@@ -6,17 +6,26 @@ import { Env } from ".";
66import migrations from "../drizzle/migrations" ;
77import { Result } from "./result" ;
88import { poll , pollOptions , votes } from "./schema" ;
9- import { PollWithOptions , PollWithResults , Vote , VoteInsert } from "./types" ;
9+ import {
10+ PollWithOptions ,
11+ PollWithResults ,
12+ Vote ,
13+ VoteInsert ,
14+ WebSocketMessage ,
15+ } from "./types" ;
1016
1117export class PollDurableObject extends DurableObject {
1218 storage : DurableObjectStorage ;
1319 db : DrizzleSqliteDODatabase < any > ;
1420
21+ currentlyConnectedWebSockets : WebSocket [ ] ;
22+
1523 constructor ( ctx : DurableObjectState , env : Env ) {
1624 super ( ctx , env ) ;
1725
1826 this . storage = this . ctx . storage ;
1927 this . db = drizzle ( this . storage , { logger : false } ) ;
28+ this . currentlyConnectedWebSockets = [ ] ;
2029
2130 ctx . blockConcurrencyWhile ( async ( ) => {
2231 await this . _migrate ( ) ;
@@ -146,12 +155,47 @@ export class PollDurableObject extends DurableObject {
146155 . values ( voteInserts )
147156 . returning ( ) ;
148157
158+ this . currentlyConnectedWebSockets . forEach ( ( ws ) => {
159+ if ( ws . readyState === WebSocket . OPEN ) {
160+ ws . send (
161+ JSON . stringify ( {
162+ type : "newVote" ,
163+ data : insertedVotes ,
164+ } satisfies WebSocketMessage < Vote [ ] > )
165+ ) ;
166+ }
167+ } ) ;
168+
149169 return {
150170 success : true ,
151171 data : insertedVotes ,
152172 } ;
153173 }
154174
175+ async fetch ( request : Request ) : Promise < Response > {
176+ // Creates two ends of a WebSocket connection.
177+ const webSocketPair = new WebSocketPair ( ) ;
178+ const [ client , server ] = Object . values ( webSocketPair ) ;
179+
180+ // Calling `accept()` tells the runtime that this WebSocket is to begin terminating
181+ // request within the Durable Object. It has the effect of "accepting" the connection,
182+ // and allowing the WebSocket to send and receive messages.
183+ this . ctx . acceptWebSocket ( server ) ;
184+ this . currentlyConnectedWebSockets . push ( client ) ;
185+
186+ // If the client closes the connection, the runtime will close the connection too.
187+ server . addEventListener ( "close" , ( cls : CloseEvent ) => {
188+ this . currentlyConnectedWebSockets =
189+ this . currentlyConnectedWebSockets . filter ( ( ws ) => ws !== client ) ;
190+ server . close ( cls . code , "Durable Object is closing WebSocket" ) ;
191+ } ) ;
192+
193+ return new Response ( null , {
194+ status : 101 ,
195+ webSocket : client ,
196+ } ) ;
197+ }
198+
155199 async _migrate ( ) {
156200 migrate ( this . db , migrations ) ;
157201 }
0 commit comments