UNPKG

rwsdk

Version:

Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime

73 lines (72 loc) 2.63 kB
import { manager } from "../state/clientManager.js"; import { reconnect } from "../reconnect/reconnect.js"; import { sendMessage, makeMessageId, unpackMessage, handleServerMessage } from "./messages.js"; import { rejectPending, startPendingRequestTimer } from "./timer.js"; export function getConnection(endpoint, webSocketFactory) { let connection = manager.getConnection(endpoint); if (!connection) { connection = createConnection(endpoint, webSocketFactory); manager.setConnection(endpoint, connection); } return connection; } function createConnection(endpoint, webSocketFactory) { const connection = { ws: webSocketFactory(endpoint), nextId: 0, pending: new Map(), isOpen: false, messageHandlers: new Map(), pendingRequestTimer: null, webSocketFactory, }; connection.ws.addEventListener("open", () => { connection.isOpen = true; manager.notifyStatusChange(endpoint, "connected"); manager.resetBackoff(endpoint); // After reconnect, any requests that were queued while disconnected now // have a live socket. Start the timer in case the server never replies. startPendingRequestTimer(connection); resubscribeAndSync(connection, endpoint); }); connection.ws.addEventListener("message", (event) => { const message = unpackMessage(event.data); if (!message) return; handleServerMessage(connection, message); }); connection.ws.addEventListener("close", () => { connection.isOpen = false; rejectPending(connection, "WebSocket closed"); if (manager.getConnection(endpoint) === connection) { manager.deleteConnection(endpoint); reconnect(endpoint); } }); connection.ws.addEventListener("error", () => { // Close event will fire next and drive reconnection. }); return connection; } function resubscribeAndSync(connection, endpoint) { const client = manager.getClient(endpoint); if (!client) return; for (const sub of manager.subscriptionsForClient(client)) { void sendMessage(connection, { kind: "subscribe", key: sub.key, id: makeMessageId(connection), }).catch(() => { }); void sendMessage(connection, { kind: "getState", key: sub.key, id: makeMessageId(connection), }) .then((value) => { if (value !== undefined) sub.handler(value); }) .catch(() => { }); } }