github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/public/src/streamService.ts (about) 1 import { QuickFeedService } from '../proto/qf/quickfeed_connectweb' 2 import { Submission } from '../proto/qf/types_pb' 3 import { Code, createConnectTransport, createPromiseClient, PromiseClient } from "@bufbuild/connect-web" 4 import { ConnStatus } from './Helpers' 5 6 7 export class StreamService { 8 private service: PromiseClient<typeof QuickFeedService> 9 private backoff = 1000 10 11 constructor() { 12 this.service = createPromiseClient(QuickFeedService, createConnectTransport({ baseUrl: "https://" + window.location.host })) 13 } 14 15 // timeout returns a promise that resolves after the current backoff has elapsed 16 private async timeout() { 17 return new Promise(resolve => setTimeout(resolve, this.backoff)) 18 } 19 20 public async submissionStream(options: { 21 onMessage: (payload?: Submission | undefined) => void, 22 onError: (error: Error) => void 23 onStatusChange: (status: ConnStatus) => void 24 }) { 25 const stream = this.service.submissionStream({}) 26 try { 27 options.onStatusChange(ConnStatus.CONNECTED) 28 for await (const msg of stream) { 29 options.onMessage(msg) 30 } 31 } catch (error) { 32 if (error.code === Code.Canceled) { 33 // The stream was canceled, so we don't need to reconnect. 34 // This happens when the stream is closed by the server 35 // which happens only if the user opens a new stream, i.e., opens the frontend in a new tab. 36 options.onError(new Error("Stream was canceled by the server.")) 37 return 38 } 39 40 // Attempt to reconnect up to log2(128) + 1 times, increasing delay between attempts by 2x each time 41 // This is a total of 8 attempts with a maximum delay of 255 seconds 42 if (this.backoff <= 128 * 1000) { 43 // Attempt to reconnect after a backoff 44 options.onStatusChange(ConnStatus.RECONNECTING) 45 await this.timeout() 46 this.submissionStream(options) 47 this.backoff *= 2 48 } else { 49 this.backoff = 1000 50 options.onError(new Error("An error occurred while connecting to the server")) 51 } 52 } 53 } 54 }