Il s'agit d'une API de bas niveau destinée aux auteurs de bibliothèques et aux cas d'utilisation avancés.
Démarrer un serveur (Bun.listen())
Pour démarrer un serveur TCP avec Bun.listen :
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {}, // message reçu du client
open(socket) {}, // socket ouvert
close(socket, error) {}, // socket fermé
drain(socket) {}, // socket prêt pour plus de données
error(socket, error) {}, // gestionnaire d'erreur
},
});Une API conçue pour la vitesse">
Dans Bun, un ensemble de gestionnaires est déclaré une fois par serveur au lieu d'assigner des callbacks à chaque socket, comme avec les EventEmitters de Node.js ou l'API standard WebSocket.
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
open(socket) {},
data(socket, data) {},
drain(socket) {},
close(socket, error) {},
error(socket, error) {},
},
});Pour les serveurs sensibles aux performances, l'assignation de listeners à chaque socket peut provoquer une pression significative sur le garbage collector et augmenter l'utilisation de la mémoire. En revanche, Bun n'alloue qu'une seule fonction de gestionnaire pour chaque événement et la partage entre tous les sockets. C'est une petite optimisation, mais elle s'additionne.
Des données contextuelles peuvent être attachées à un socket dans le gestionnaire 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" };
},
},
});Pour activer TLS, passez un objet tls contenant les champs key et cert.
Bun.listen({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
},
tls: {
// peut être une chaîne, BunFile, TypedArray, Buffer, ou un tableau de ceux-ci
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
},
});Les champs key et cert attendent le contenu de votre clé TLS et de votre certificat. Cela peut être une chaîne, BunFile, TypedArray, ou Buffer.
Bun.listen({
// ...
tls: {
key: Bun.file("./key.pem"), // BunFile
key: fs.readFileSync("./key.pem"), // Buffer
key: fs.readFileSync("./key.pem", "utf8"), // string
key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")], // tableau de ce qui précède
},
});Le résultat de Bun.listen est un serveur qui se conforme à l'interface TCPSocket.
const server = Bun.listen({
/* config*/
});
// arrêter l'écoute
// le paramètre détermine si les connexions actives sont fermées
server.stop(true);
// permettre au processus Bun de se terminer même si le serveur écoute toujours
server.unref();Créer une connexion (Bun.connect())
Utilisez Bun.connect pour vous connecter à un serveur TCP. Spécifiez le serveur auquel vous vous connectez avec hostname et port. Les clients TCP peuvent définir le même ensemble de gestionnaires que Bun.listen, plus quelques gestionnaires spécifiques au client.
// Le client
const socket = await Bun.connect({
hostname: "localhost",
port: 8080,
socket: {
data(socket, data) {},
open(socket) {},
close(socket, error) {},
drain(socket) {},
error(socket, error) {},
// gestionnaires spécifiques au client
connectError(socket, error) {}, // échec de la connexion
end(socket) {}, // connexion fermée par le serveur
timeout(socket) {}, // délai d'attente de la connexion dépassé
},
});Pour exiger TLS, spécifiez tls: true.
// Le client
const socket = await Bun.connect({
// ... config
tls: true,
});Rechargement à chaud
Les serveurs TCP et les sockets peuvent être rechargés à chaud avec de nouveaux gestionnaires.
const server = Bun.listen({
/* config */
});
// recharge les gestionnaires pour tous les sockets serveur actifs
server.reload({
socket: {
data() {
// nouveau gestionnaire 'data'
},
},
});const socket = await Bun.connect({
/* config */
});
socket.reload({
data() {
// nouveau gestionnaire 'data'
},
});Mise en tampon
Actuellement, les sockets TCP dans Bun ne mettent pas les données en tampon. Pour le code sensible aux performances, il est important de considérer attentivement la mise en tampon. Par exemple, ceci :
socket.write("h");
socket.write("e");
socket.write("l");
socket.write("l");
socket.write("o");...performe considérablement moins bien que ceci :
socket.write("hello");Pour simplifier cela pour l'instant, envisagez d'utiliser ArrayBufferSink de Bun avec l'option {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) {
// remettre dans le sink si le socket est plein
sink.write(data.subarray(wrote));
}
});NOTE
**Corking**La prise en charge du corking est prévue, mais en attendant, la contre-pression doit être gérée manuellement avec le gestionnaire drain.