Skip to content

Esta é uma API de baixo nível destinada a autores de bibliotecas e casos de uso avançados.

Iniciar um servidor (Bun.listen())

Para iniciar um servidor TCP com Bun.listen:

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {}, // mensagem recebida do cliente
    open(socket) {}, // socket aberto
    close(socket, error) {}, // socket fechado
    drain(socket) {}, // socket pronto para mais dados
    error(socket, error) {}, // handler de erro
  },
});

Uma API projetada para velocidade

No Bun, um conjunto de handlers é declarado uma vez por servidor ao invés de atribuir callbacks a cada socket, como com EventEmitters do Node.js ou a API WebSocket padrão web.

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

Para servidores sensíveis a performance, atribuir listeners a cada socket pode causar pressão significativa no garbage collector e aumentar o uso de memória. Em contraste, o Bun apenas aloca uma função handler para cada evento e compartilha entre todos os sockets. Esta é uma pequena otimização, mas se acumula.

Dados contextuais podem ser anexados a um socket no handler 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, passe um objeto tls contendo campos key e cert.

ts
Bun.listen({
  hostname: "localhost",
  port: 8080,
  socket: {
    data(socket, data) {},
  },
  tls: {
    // pode ser string, BunFile, TypedArray, Buffer, ou array disso
    key: Bun.file("./key.pem"), 
    cert: Bun.file("./cert.pem"), 
  },
});

Os campos key e cert esperam o conteúdo da sua chave TLS e certificado. Isto pode ser uma string, BunFile, TypedArray, ou Buffer.

ts
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")], // array dos acima
  },
});

O resultado de Bun.listen é um servidor que conforma com a interface TCPSocket.

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

// para escuta
// parâmetro determina se conexões ativas são fechadas
server.stop(true);

// permite processo Bun sair mesmo se servidor ainda está escutando
server.unref();

Criar uma conexão (Bun.connect())

Use Bun.connect para conectar a um servidor TCP. Especifique o servidor ao qual conectar com hostname e port. Clientes TCP podem definir o mesmo conjunto de handlers que Bun.listen, mais alguns handlers específicos de cliente.

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

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

    // handlers específicos do cliente
    connectError(socket, error) {}, // conexão falhou
    end(socket) {}, // conexão fechada pelo servidor
    timeout(socket) {}, // conexão teve timeout
  },
});

Para requerer TLS, especifique tls: true.

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

Hot reloading

Tanto servidores TCP quanto sockets podem ser hot reloadados com novos handlers.

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

// recarrega handlers para todos os sockets do lado do servidor ativos
server.reload({
  socket: {
    data() {
      // novo handler 'data'
    },
  },
});
ts
const socket = await Bun.connect({
  /* config */
});

socket.reload({
  data() {
    // novo handler 'data'
  },
});

Bufferização

Atualmente, sockets TCP no Bun não bufferizam dados. Para código sensível a performance, é importante considerar a bufferização cuidadosamente. Por exemplo, isto:

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

...tem performance significativamente pior que isto:

ts
socket.write("hello");

Para simplificar isto por enquanto, considere usar ArrayBufferSink do Bun com a opção {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) {
    // coloca de volta no sink se o socket está cheio
    sink.write(data.subarray(wrote));
  }
});

NOTE

**Corking**

Suporte para corking é planejado, mas enquanto isso backpressure deve ser gerenciado manualmente com o handler drain.

Bun by www.bunjs.com.cn edit