Add awareness broadcast to session
This commit is contained in:
parent
cd4b1def5b
commit
93bb462ffa
3 changed files with 46 additions and 3 deletions
|
|
@ -6,10 +6,17 @@ export type ClientMessage =
|
|||
| { type: "update"; data: number[] } // yjs update as byte array
|
||||
| { type: "awareness"; data: number[] };
|
||||
|
||||
export type AwarenessState = {
|
||||
clientId: number;
|
||||
cursor?: { line: number; col: number };
|
||||
selection?: { startLine: number; startCol: number; endLine: number; endCol: number };
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export type ServerMessage =
|
||||
| { type: "sync"; data: number[] } // full yjs state
|
||||
| { type: "update"; data: number[] }
|
||||
| { type: "awareness"; data: number[] }
|
||||
| { type: "awareness"; data: AwarenessState }
|
||||
| { type: "peers"; count: number }
|
||||
| { type: "error"; message: string };
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect, test } from "bun:test";
|
||||
import * as Y from "yjs";
|
||||
import { getOrCreateSession, Session, type WsData } from "./session";
|
||||
import { getOrCreateSession, Session, type Client, type WsData } from "./session";
|
||||
|
||||
describe("Session", () => {
|
||||
test("creates yjs doc on init", () => {
|
||||
|
|
@ -57,3 +57,26 @@ describe("getOrCreateSession", () => {
|
|||
expect(s1).not.toBe(s2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("awareness", () => {
|
||||
test("broadcasts awareness to other clients", () => {
|
||||
const session = new Session("test-room");
|
||||
const sent1: unknown[] = [];
|
||||
const sent2: unknown[] = [];
|
||||
|
||||
const client1 = { ws: { send: (m: string) => sent1.push(JSON.parse(m)) } } as Client;
|
||||
const client2 = { ws: { send: (m: string) => sent2.push(JSON.parse(m)) } } as Client;
|
||||
|
||||
session.join(client1);
|
||||
session.join(client2);
|
||||
|
||||
const awareness = { clientId: 1, cursor: { line: 5, col: 10 } };
|
||||
session.broadcastAwareness(client1, awareness);
|
||||
|
||||
// client1 should NOT receive their own awareness
|
||||
expect(sent1.filter(m => m.type === "awareness")).toHaveLength(0);
|
||||
// client2 should receive it
|
||||
expect(sent2.filter(m => m.type === "awareness")).toHaveLength(1);
|
||||
expect(sent2.find(m => m.type === "awareness")?.data).toEqual(awareness);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ServerWebSocket } from "bun";
|
||||
import * as Y from "yjs";
|
||||
import { encode } from "./protocol";
|
||||
import { encode, type AwarenessState } from "./protocol";
|
||||
|
||||
export interface WsData {
|
||||
room: string | null;
|
||||
|
|
@ -84,6 +84,19 @@ export class Session {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
broadcastAwareness(sender: Client, state: AwarenessState): void {
|
||||
const message = encode({ type: "awareness", data: state });
|
||||
for (const client of this.clients) {
|
||||
if (client !== sender) {
|
||||
try {
|
||||
client.ws.send(message);
|
||||
} catch {
|
||||
// client disconnected, ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// room name -> session
|
||||
|
|
|
|||
Loading…
Reference in a new issue