Skip to content

Esta es una API de bajo nivel destinada a autores de bibliotecas y casos de uso avanzados.

Iniciar un servidor (Bun.listen())

Para iniciar un servidor TCP con Bun.listen:

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {}, // mensaje recibido del cliente
    open(socket) {}, // socket abierto
    close(socket, error) {}, // socket cerrado
    drain(socket) {}, // socket listo para más datos
    error(socket, error) {}, // manejador de errores
  },
});

Una API diseñada para velocidad

En Bun, un conjunto de manejadores se declara una vez por servidor en lugar de asignar callbacks a cada socket, como con los EventEmitters de Node.js o la API WebSocket estándar web.

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

Para servidores sensibles al rendimiento, asignar listeners a cada socket puede causar presión significativa en el recolector de basura y aumentar el uso de memoria. Por el contrario, Bun solo asigna una función manejadora para cada evento y la comparte entre todos los sockets. Esta es una pequeña optimización, pero se acumula.

Se pueden adjuntar datos contextuales a un socket en el manejador 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" }; 
    },
  },
});

Para habilitar TLS, pasa un objeto tls que contenga los campos key y cert.

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {},
  },
  tls: {
    // puede ser cadena, BunFile, TypedArray, Buffer, o array de los mismos
    key: Bun.file("./key.pem"), 
    cert: Bun.file("./cert.pem"), 
  },
});

Los campos key y cert esperan el contenido de tu clave TLS y certificado. Esto puede ser una cadena, 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"), // cadena
    key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")], // array de lo anterior
  },
});

El resultado de Bun.listen es un servidor que cumple con la interfaz TCPSocket.

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

// dejar de escuchar
// el parámetro determina si las conexiones activas se cierran
server.stop(true);

// permitir que el proceso Bun salga incluso si el servidor sigue escuchando
server.unref();

Crear una conexión (Bun.connect())

Usa Bun.connect para conectarse a un servidor TCP. Especifica el servidor al que conectarse con hostname y port. Los clientes TCP pueden definir el mismo conjunto de manejadores que Bun.listen, más un par de manejadores específicos del cliente.

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

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

    // manejadores específicos del cliente
    connectError(socket, error) {}, // conexión fallida
    end(socket) {}, // conexión cerrada por el servidor
    timeout(socket) {}, // conexión agotada
  },
});

Para requerir TLS, especifica tls: true.

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

Recarga en caliente

Tanto los servidores TCP como los sockets se pueden recargar en caliente con nuevos manejadores.

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

// recarga manejadores para todos los sockets del lado del servidor activos
server.reload({
  socket: {
    data() {
      // nuevo manejador 'data'
    },
  },
});
ts
const socket = await Bun.connect({
  /* config */
});

socket.reload({
  data() {
    // nuevo manejador 'data'
  },
});

Almacenamiento en búfer

Actualmente, los sockets TCP en Bun no almacenan datos en búfer. Para código sensible al rendimiento, es importante considerar cuidadosamente el almacenamiento en búfer. Por ejemplo, esto:

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

...tiene un rendimiento significativamente peor que esto:

ts
socket.write("hello");

Para simplificar esto por ahora, considera usar ArrayBufferSink de Bun con la opción {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) {
    // volver a poner en el sink si el socket está lleno
    sink.write(data.subarray(wrote));
  }
});

NOTE

**Corking**

El soporte para corking está planeado, pero mientras tanto la contrapresión debe manejarse manualmente con el manejador drain.

Bun por www.bunjs.com.cn editar