Route awareness messages between peers

This commit is contained in:
Jared Miller 2026-01-27 20:38:47 -05:00
parent 93bb462ffa
commit 56aa8dc9bd
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
3 changed files with 66 additions and 4 deletions

55
src/awareness.test.ts Normal file
View file

@ -0,0 +1,55 @@
import { describe, test, expect, beforeAll, afterAll } from "bun:test";
import type { Server } from "bun";
describe("awareness routing", () => {
let server: Server;
const PORT = 4042;
beforeAll(async () => {
// Import and start server on test port
process.env.PORT = String(PORT);
const mod = await import("./index");
server = mod.server;
});
afterAll(() => {
server?.stop();
});
test("awareness message routes to other peers in same room", async () => {
const ws1 = new WebSocket(`ws://localhost:${PORT}/ws`);
const ws2 = new WebSocket(`ws://localhost:${PORT}/ws`);
const received: unknown[] = [];
await Promise.all([
new Promise(r => ws1.onopen = r),
new Promise(r => ws2.onopen = r),
]);
ws2.onmessage = (e) => {
received.push(JSON.parse(e.data));
};
// Both join same room
ws1.send(JSON.stringify({ type: "join", room: "test" }));
ws2.send(JSON.stringify({ type: "join", room: "test" }));
await Bun.sleep(50);
// ws1 sends awareness
ws1.send(JSON.stringify({
type: "awareness",
data: { clientId: 1, cursor: { line: 10, col: 5 } }
}));
await Bun.sleep(50);
const awareness = received.find(m => m.type === "awareness");
expect(awareness).toBeDefined();
expect(awareness.data.cursor).toEqual({ line: 10, col: 5 });
ws1.close();
ws2.close();
});
});

View file

@ -14,7 +14,7 @@ function isValidRoomName(name: unknown): name is string {
return /^[a-zA-Z0-9_-]+$/.test(name); return /^[a-zA-Z0-9_-]+$/.test(name);
} }
Bun.serve<WsData>({ export const server = Bun.serve<WsData>({
port: PORT, port: PORT,
fetch(req, server) { fetch(req, server) {
const url = new URL(req.url); const url = new URL(req.url);
@ -77,6 +77,15 @@ Bun.serve<WsData>({
} }
break; break;
} }
case "awareness": {
if (ws.data.room) {
const session = getSession(ws.data.room);
if (session && "data" in msg) {
session.broadcastAwareness(client, msg.data);
}
}
break;
}
} }
}, },
close(ws) { close(ws) {

View file

@ -46,9 +46,7 @@ function isClientMessage(obj: unknown): obj is ClientMessage {
Array.isArray(msg.data) && msg.data.every((n) => typeof n === "number") Array.isArray(msg.data) && msg.data.every((n) => typeof n === "number")
); );
case "awareness": case "awareness":
return ( return typeof msg.data === "object" && msg.data !== null;
Array.isArray(msg.data) && msg.data.every((n) => typeof n === "number")
);
default: default:
return false; return false;
} }