Paul
Paul
Explore posts from servers
CDCloudflare Developers
Created by Paul on 6/27/2024 in #wrangler
Whenever I run `dev`, the process
Hi Sethi, I'm running on macOS Sonoma 14.3. Apple M1 Max 64GB
2 replies
CDCloudflare Developers
Created by Paul on 6/26/2024 in #workers-help
How to maintain WebSocket client connections in Durable Object?
As per Skye, the answer is below: You'd probably want to use the tags option when accepting the websocket found here, alongside the getTags and getWebsockets method, rather than maintaining your own state, as that won't persist across hibernations
5 replies
CDCloudflare Developers
Created by Paul on 6/26/2024 in #workers-help
How to maintain WebSocket client connections in Durable Object?
Or fundamentally, how can I restructure this whole thing so that I'm able to broadcast to all clients but delete the clients when they disconnect? I'm able to do it when NOT extending the "DurableObject" class, but then if I don't extend it, I don't think I'm able to use the Hibernation API via this.ctx.acceptWebsocket(server)
5 replies
CDCloudflare Developers
Created by Paul on 6/26/2024 in #workers-help
How to maintain WebSocket client connections in Durable Object?
Previously, I was able to do...
async handleWebSocketSession(webSocket: WebSocket) {
// ...
let closeOrErrorHandler = () => {
console.log("client disconnected", clientId);
this.clients.delete(clientId);
};
webSocket.addEventListener("close", closeOrErrorHandler);
webSocket.addEventListener("error", closeOrErrorHandler);
}
async handleWebSocketSession(webSocket: WebSocket) {
// ...
let closeOrErrorHandler = () => {
console.log("client disconnected", clientId);
this.clients.delete(clientId);
};
webSocket.addEventListener("close", closeOrErrorHandler);
webSocket.addEventListener("error", closeOrErrorHandler);
}
5 replies
CDCloudflare Developers
Created by Paul on 6/26/2024 in #workers-help
How to maintain WebSocket client connections in Durable Object?
When extending the DurableObject class
import { Environment } from "@/src/types";
import { DurableObject } from "cloudflare:workers";

interface Client {
websocket: WebSocket;
id: string;
}

export class WebSocketHibernationServer extends DurableObject {
clients: Map<string, Client>;

constructor(ctx: DurableObjectState, env: Environment) {
super(ctx, env);
this.clients = new Map();
}

async fetch(request: Request): Promise<Response> {
let pair = new WebSocketPair();
const [client, server] = Object.values(pair);
this.ctx.acceptWebSocket(server);
await this.handleWebSocketSession(server);
return new Response(null, { status: 101, webSocket: client });
}

async handleWebSocketSession(webSocket: WebSocket) {
// Create our session and add it to the users map.
const clientId = crypto.randomUUID();
this.clients.set(clientId, {
id: clientId,
websocket: webSocket,
});

// I previously added event listeners here but they don't get triggered
// Previously I was able to delete the clientId from the map on close here
}

async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) {
this.broadcast(
`[Durable Object] message: ${message}, connections: ${this.ctx.getWebSockets().length}`
);
}

async webSocketClose(ws: WebSocket, code: number, reason: string) {
ws.close(code, reason);
}

broadcast(message: string) {
// Iterate over all the sessions sending them messages.
this.clients.forEach((client, key) => {
try {
client.websocket.send(message);
} catch (err) {
this.clients.delete(key);
}
});
}
import { Environment } from "@/src/types";
import { DurableObject } from "cloudflare:workers";

interface Client {
websocket: WebSocket;
id: string;
}

export class WebSocketHibernationServer extends DurableObject {
clients: Map<string, Client>;

constructor(ctx: DurableObjectState, env: Environment) {
super(ctx, env);
this.clients = new Map();
}

async fetch(request: Request): Promise<Response> {
let pair = new WebSocketPair();
const [client, server] = Object.values(pair);
this.ctx.acceptWebSocket(server);
await this.handleWebSocketSession(server);
return new Response(null, { status: 101, webSocket: client });
}

async handleWebSocketSession(webSocket: WebSocket) {
// Create our session and add it to the users map.
const clientId = crypto.randomUUID();
this.clients.set(clientId, {
id: clientId,
websocket: webSocket,
});

// I previously added event listeners here but they don't get triggered
// Previously I was able to delete the clientId from the map on close here
}

async webSocketMessage(ws: WebSocket, message: ArrayBuffer | string) {
this.broadcast(
`[Durable Object] message: ${message}, connections: ${this.ctx.getWebSockets().length}`
);
}

async webSocketClose(ws: WebSocket, code: number, reason: string) {
ws.close(code, reason);
}

broadcast(message: string) {
// Iterate over all the sessions sending them messages.
this.clients.forEach((client, key) => {
try {
client.websocket.send(message);
} catch (err) {
this.clients.delete(key);
}
});
}
5 replies