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:
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.
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.
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.
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.
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.
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.
// 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.
// 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.
const server = Bun.listen({
/* config */
});
// ricarica i gestori per tutti i socket server-side attivi
server.reload({
socket: {
data() {
// nuovo gestore 'data'
},
},
});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:
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");...funziona significativamente peggio di questo:
socket.write("hello");Per semplificare questo per ora, considera l'uso di ArrayBufferSink di Bun con l'opzione {stream: true}:
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.