diff --git a/src/durable-objects/canvas-room.js b/src/durable-objects/canvas-room.js index 7f64973..00c6048 100644 --- a/src/durable-objects/canvas-room.js +++ b/src/durable-objects/canvas-room.js @@ -1,12 +1,10 @@ /** * Durable Object for WebSocket broadcast room. - * All connected clients receive pixel updates in real-time. + * Uses Hibernation API so connections survive DO eviction. */ export class CanvasRoom { constructor(state) { this.state = state; - /** @type {Set} */ - this.sessions = new Set(); } async fetch(request) { @@ -16,11 +14,11 @@ export class CanvasRoom { if (url.pathname === '/broadcast' && request.method === 'POST') { const pixels = await request.json(); const message = JSON.stringify({ type: 'pixels', pixels }); - for (const ws of this.sessions) { + for (const ws of this.state.getWebSockets()) { try { ws.send(message); } catch { - this.sessions.delete(ws); + ws.close(1011, 'send failed'); } } return new Response('ok'); @@ -30,17 +28,23 @@ export class CanvasRoom { const pair = new WebSocketPair(); const [client, server] = Object.values(pair); - server.accept(); - this.sessions.add(server); - - server.addEventListener('close', () => { - this.sessions.delete(server); - }); - - server.addEventListener('error', () => { - this.sessions.delete(server); - }); + this.state.acceptWebSocket(server); return new Response(null, { status: 101, webSocket: client }); } + + /** Called when a WebSocket receives a message (required by Hibernation API) */ + webSocketMessage(ws, message) { + // Clients don't send messages in this protocol; ignore. + } + + /** Called when a WebSocket is closed */ + webSocketClose(ws, code, reason, wasClean) { + ws.close(code, reason); + } + + /** Called on WebSocket error */ + webSocketError(ws, error) { + ws.close(1011, 'error'); + } }