diff options
Diffstat (limited to 'docs/guides/websocket')
-rw-r--r-- | docs/guides/websocket/compression.md | 31 | ||||
-rw-r--r-- | docs/guides/websocket/context.md | 72 | ||||
-rw-r--r-- | docs/guides/websocket/index.json | 4 | ||||
-rw-r--r-- | docs/guides/websocket/pubsub.md | 38 | ||||
-rw-r--r-- | docs/guides/websocket/simple.md | 33 | ||||
-rw-r--r-- | docs/guides/websocket/upgrade.md | 28 |
6 files changed, 206 insertions, 0 deletions
diff --git a/docs/guides/websocket/compression.md b/docs/guides/websocket/compression.md new file mode 100644 index 000000000..e98d8f0c9 --- /dev/null +++ b/docs/guides/websocket/compression.md @@ -0,0 +1,31 @@ +--- +name: Enable compression for WebSocket messages +--- + +Per-message compression can be enabled with the `perMessageDeflate` parameter. When set, all messages will be compressed using the [permessage-deflate](https://tools.ietf.org/html/rfc7692) WebSocket extension. + +```ts +Bun.serve({ + // ... + websocket: { + // enable compression + perMessageDeflate: true, + }, +}); +``` + +--- + +To enable compression for individual messages, pass `true` as the second parameter to `ws.send()`. + +```ts +Bun.serve({ + // ... + websocket: { + async message(ws, message) { + // send a compressed message + ws.send("Hello world!", true); + }, + }, +}); +``` diff --git a/docs/guides/websocket/context.md b/docs/guides/websocket/context.md new file mode 100644 index 000000000..9e387d685 --- /dev/null +++ b/docs/guides/websocket/context.md @@ -0,0 +1,72 @@ +--- +name: Set per-socket contextual data on a WebSocket +--- + +When building a WebSocket server, it's typically necessary to store some identifying information or context associated with each connected client. + +With [Bun.serve()](/docs/api/websockets#contextual-data), this "contextual data" is set when the connection is initially upgraded by passing a `data` parameter in the `server.upgrade()` call. + +```ts +Bun.serve<{ socketId: number }>({ + fetch(req, server) { + const success = server.upgrade(req, { + data: { + socketId: Math.random(), + }, + }); + if (success) return undefined; + + // handle HTTP request normally + // ... + }, + websocket: { + // define websocket handlers + async message(ws, message) { + // the contextual dta is available as the `data` property + // on the WebSocket instance + console.log(`Received ${message} from ${ws.data.socketId}}`); + }, + }, +}); +``` + +--- + +It's common to read cookies/headers from the incoming request to identify the connecting client. + +```ts +type WebSocketData = { + createdAt: number; + token: string; + userId: string; +}; + +// TypeScript: specify the type of `data` +Bun.serve<WebSocketData>({ + async fetch(req, server) { + // use a library to parse cookies + const cookies = parseCookies(req.headers.get("Cookie")); + const token = cookies["X-Token"]; + const user = await getUserFromToken(ws.data.authToken); + + const upgraded = server.upgrade(req, { + data: { + createdAt: Date.now(), + token: cookies["X-Token"], + userId: user.id, + }, + }); + + if (upgraded) return undefined; + }, + websocket: { + async message(ws, message) { + // save the message to a database + await saveMessageToDatabase({ + message: String(message), + userId: ws.data.userId, + }); + }, + }, +}); +``` diff --git a/docs/guides/websocket/index.json b/docs/guides/websocket/index.json new file mode 100644 index 000000000..cb4d71b1a --- /dev/null +++ b/docs/guides/websocket/index.json @@ -0,0 +1,4 @@ +{ + "name": "WebSocket", + "description": "A collection of guides relating to building WebSocket servers with Bun" +} diff --git a/docs/guides/websocket/pubsub.md b/docs/guides/websocket/pubsub.md new file mode 100644 index 000000000..7403d4d2f --- /dev/null +++ b/docs/guides/websocket/pubsub.md @@ -0,0 +1,38 @@ +--- +name: Build a publish-subscribe WebSocket server +--- + +Bun's server-side `WebSocket` API provides a native pub-sub API. Sockets can be subscribed to a set of named channels using `socket.subscribe(<name>)`; messages can be published to a channel using `socket.publish(<name>, <message>)`. + +This code snippet implements a simple single-channel chat server. + +```ts +const server = Bun.serve<{ username: string }>({ + fetch(req, server) { + const cookies = req.headers.get("cookie"); + const username = getUsernameFromCookies(cookies); + const success = server.upgrade(req, { data: { username } }); + if (success) return undefined; + + return new Response("Hello world"); + }, + websocket: { + open(ws) { + const msg = `${ws.data.username} has entered the chat`; + ws.subscribe("the-group-chat"); + ws.publish("the-group-chat", msg); + }, + message(ws, message) { + // the server re-broadcasts incoming messages to everyone + ws.publish("the-group-chat", `${ws.data.username}: ${message}`); + }, + close(ws) { + const msg = `${ws.data.username} has left the chat`; + ws.publish("the-group-chat", msg); + ws.unsubscribe("the-group-chat"); + }, + }, +}); + +console.log(`Listening on ${server.hostname}:${server.port}`); +``` diff --git a/docs/guides/websocket/simple.md b/docs/guides/websocket/simple.md new file mode 100644 index 000000000..5aabf2fdf --- /dev/null +++ b/docs/guides/websocket/simple.md @@ -0,0 +1,33 @@ +--- +name: Build a simple WebSocket server +--- + +Start a simple WebSocket server using [`Bun.serve`](/docs/api/http). + +Inside `fetch`, we attempt to upgrade incoming `ws:` or `wss:` requests to WebSocket connections. + +```ts +const server = Bun.serve<{ authToken: string }>({ + fetch(req, server) { + const success = server.upgrade(req); + if (success) { + // Bun automatically returns a 101 Switching Protocols + // if the upgrade succeeds + return undefined; + } + + // handle HTTP request normally + return new Response("Hello world!"); + }, + websocket: { + // this is called when a message is received + async message(ws, message) { + console.log(`Received ${message}`); + // send back a message + ws.send(`You said: ${message}`); + }, + }, +}); + +console.log(`Listening on localhost:\${server.port}`); +``` diff --git a/docs/guides/websocket/upgrade.md b/docs/guides/websocket/upgrade.md new file mode 100644 index 000000000..cec8c3802 --- /dev/null +++ b/docs/guides/websocket/upgrade.md @@ -0,0 +1,28 @@ +--- +name: Upgrade an HTTP request to a WebSocket connection +--- + +Inside `fetch`, use the `server.upgrade()` function to upgrade an incoming `Request` to a WebSocket connection. Bun automatically returns a 101 Switching Protocols response if the upgrade succeeds. + +Refer to the [WebSocket docs](/docs/api/websockets) for more information on building WebSocket servers. + +```ts +const server = Bun.serve<{ authToken: string }>({ + fetch(req, server) { + const success = server.upgrade(req); + if (success) { + // Bun automatically returns a 101 Switching Protocols + // if the upgrade succeeds + return undefined; + } + + // handle HTTP request normally + return new Response("Hello world!"); + }, + websocket: { + // define websocket handlers + }, +}); + +console.log(`Listening on localhost:\${server.port}`); +``` |