Skip to content

Questa è un'API di basso livello destinata agli autori di librerie e ai casi d'uso avanzati.

Avviare un server (Bun.listen())

Per avviare un server TCP con Bun.listen:

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {}, // messaggio ricevuto dal client
    open(socket) {}, // socket aperto
    close(socket, error) {}, // socket chiuso
    drain(socket) {}, // socket pronto per più dati
    error(socket, error) {}, // gestore errori
  },
});

Un'API progettata per la velocità

In Bun, un insieme di gestori sono dichiarati una volta per server invece di assegnare callback a ogni socket, come con gli EventEmitter di Node.js o l'API WebSocket standard del web.

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    open(socket) {},
    data(socket, data) {},
    drain(socket) {},
    close(socket, error) {},
    error(socket, error) {},
  },
});

Per server sensibili alle prestazioni, assegnare listener a ogni socket può causare una significativa pressione del garbage collector e aumentare l'uso della memoria. Al contrario, Bun alloca solo una funzione gestore per ogni evento e la condivide tra tutti i socket. Questa è una piccola ottimizzazione, ma si accumula.

I dati contestuali possono essere allegati a un socket nel gestore open.

ts
type SocketData = { sessionId: string };

Bun.listen<SocketData>({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {
      socket.write(`${socket.data.sessionId}: ack`); 
    },
    open(socket) {
      socket.data = { sessionId: "abcd" }; 
    },
  },
});

Per abilitare TLS, passa un oggetto tls contenente i campi key e cert.

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {},
  },
  tls: {
    // può essere stringa, BunFile, TypedArray, Buffer, o array degli stessi
    key: Bun.file("./key.pem"), 
    cert: Bun.file("./cert.pem"), 
  },
});

I campi key e cert si aspettano i contenuti della tua chiave TLS e del certificato. Questo può essere una stringa, BunFile, TypedArray o Buffer.

ts
Bun.listen({
  // ...
  tls: {
    key: Bun.file("./key.pem"), // BunFile
    key: fs.readFileSync("./key.pem"), // Buffer
    key: fs.readFileSync("./key.pem", "utf8"), // stringa
    key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")], // array di quanto sopra
  },
});

Il risultato di Bun.listen è un server che conforms all'interfaccia TCPSocket.

ts
const server = Bun.listen({
  /* config*/
});

// smetti di ascoltare
// il parametro determina se le connessioni attive sono chiuse
server.stop(true);

// lascia che Bun process exit anche se il server sta ancora ascoltando
server.unref();

Creare una connessione (Bun.connect())

Usa Bun.connect per connetterti a un server TCP. Specifica il server a cui connetterti con hostname e port. I client TCP possono definire lo stesso insieme di gestori di Bun.listen, più alcuni gestori specifici del client.

ts
// Il client
const socket = await Bun.connect({
  hostname: "localhost",
  port: 8080,

  socket: {
    data(socket, data) {},
    open(socket) {},
    close(socket, error) {},
    drain(socket) {},
    error(socket, error) {},

    // gestori specifici del client
    connectError(socket, error) {}, // connessione fallita
    end(socket) {}, // connessione chiusa dal server
    timeout(socket) {}, // connessione scaduta
  },
});

Per richiedere TLS, specifica tls: true.

ts
// Il client
const socket = await Bun.connect({
  // ... config
  tls: true, 
});

Hot reloading

Sia i server TCP che i socket possono essere hot reloaded con nuovi gestori.

ts
const server = Bun.listen({
  /* config */
});

// ricarica i gestori per tutti i socket server-side attivi
server.reload({
  socket: {
    data() {
      // nuovo gestore 'data'
    },
  },
});
ts
const socket = await Bun.connect({
  /* config */
});

socket.reload({
  data() {
    // nuovo gestore 'data'
  },
});

Buffering

Attualmente, i socket TCP in Bun non memorizzano i dati in buffer. Per codice sensibile alle prestazioni, è importante considerare attentamente il buffering. Ad esempio, questo:

ts
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");

...funziona significativamente peggio di questo:

ts
socket.write("hello");

Per semplificare questo per ora, considera l'uso di ArrayBufferSink di Bun con l'opzione {stream: true}:

ts
import { ArrayBufferSink } from "bun";

const sink = new ArrayBufferSink();
sink.start({
  stream: true, 
  highWaterMark: 1024,
});

sink.write("h");
sink.write("e");
sink.write("l");
sink.write("l");
sink.write("o");

queueMicrotask(() => {
  const data = sink.flush();
  const wrote = socket.write(data);
  if (wrote < data.byteLength) {
    // rimettilo nel sink se il socket è pieno
    sink.write(data.subarray(wrote));
  }
});

NOTE

**Corking**

Il supporto per il corking è pianificato, ma nel frattempo la backpressure deve essere gestita manualmente con il gestore drain.

Bun a cura di www.bunjs.com.cn