-
Notifications
You must be signed in to change notification settings - Fork 158
Support ICE restart and signaling reconnect in samples #281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop-pre-2.3.0
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -57,7 +57,8 @@ interface WebSocketMessage { | |||||
| */ | ||||||
| export class SignalingClient extends EventEmitter { | ||||||
| private static DEFAULT_CLIENT_ID = 'MASTER'; | ||||||
|
|
||||||
| private reconnectDelay = 1 * 1000; | ||||||
| private reconnection: boolean; | ||||||
| private websocket: WebSocket = null; | ||||||
| private readyState = ReadyState.CLOSED; | ||||||
| private readonly requestSigner: RequestSigner; | ||||||
|
|
@@ -86,7 +87,7 @@ export class SignalingClient extends EventEmitter { | |||||
| validateValueNonNil(config.region, 'region'); | ||||||
| validateValueNonNil(config.channelEndpoint, 'channelEndpoint'); | ||||||
|
|
||||||
| this.config = { ...config }; // Copy config to new object for immutability. | ||||||
| this.config = {...config}; // Copy config to new object for immutability. | ||||||
|
|
||||||
| if (config.requestSigner) { | ||||||
| this.requestSigner = config.requestSigner; | ||||||
|
|
@@ -112,7 +113,6 @@ export class SignalingClient extends EventEmitter { | |||||
| throw new Error('Client is already open, opening, or closing'); | ||||||
| } | ||||||
| this.readyState = ReadyState.CONNECTING; | ||||||
|
|
||||||
| // The process of opening the connection is asynchronous via promises, but the interaction model is to handle asynchronous actions via events. | ||||||
| // Therefore, we just kick off the asynchronous process and then return and let it fire events. | ||||||
| this.asyncOpen() | ||||||
|
|
@@ -150,6 +150,7 @@ export class SignalingClient extends EventEmitter { | |||||
| * connection has been closed. | ||||||
| */ | ||||||
| public close(): void { | ||||||
| console.log("Closing the websocket"); | ||||||
| if (this.websocket !== null) { | ||||||
| this.readyState = ReadyState.CLOSING; | ||||||
| this.websocket.close(); | ||||||
|
|
@@ -158,6 +159,36 @@ export class SignalingClient extends EventEmitter { | |||||
| } | ||||||
| } | ||||||
|
|
||||||
| public reconnect(maxAttempt = 3): void { | ||||||
| this.reconnection = true; | ||||||
| if (this.readyState === ReadyState.CLOSED) { | ||||||
| this.attemptReconnect(maxAttempt); | ||||||
| } else { | ||||||
| console.log('Invalid state to invoke reconnect from'); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| private attemptReconnect(maxAttempts: number, attempt = 0): void { | ||||||
| if (this.readyState === ReadyState.CLOSED) { | ||||||
| this.open(); | ||||||
| // If reconnect fails | ||||||
| setTimeout(() => { | ||||||
| if (this.readyState !== ReadyState.OPEN) { | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Logic needed to check if
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. setTimeout returns a timer id, you can use clearTimeout(id) in |
||||||
| if (attempt < maxAttempts) { | ||||||
| console.log("Failed reconnect attempt ", attempt); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Space not needed, this will result in double space |
||||||
| this.attemptReconnect(maxAttempts, attempt + 1); | ||||||
| } else { | ||||||
| console.error("Max reconnect attempts reached, bailing out"); | ||||||
| } | ||||||
| } else { | ||||||
| console.log("Reconnected to WS"); | ||||||
| } | ||||||
| }, this.reconnectDelay * (attempt + 1)); // increasing delay | ||||||
| } else { | ||||||
| console.log('Invalid state to invoke reconnect from'); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's also log that invalid state - |
||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Sends the given SDP offer to the signaling service. | ||||||
| * | ||||||
|
|
@@ -166,6 +197,7 @@ export class SignalingClient extends EventEmitter { | |||||
| * @param {string} [recipientClientId] - ID of the client to send the message to. Required for 'MASTER' role. Should not be present for 'VIEWER' role. | ||||||
| */ | ||||||
| public sendSdpOffer(sdpOffer: RTCSessionDescription, recipientClientId?: string): void { | ||||||
| console.log("Sending SDP offer"); | ||||||
| this.sendMessage(MessageType.SDP_OFFER, sdpOffer.toJSON(), recipientClientId); | ||||||
| } | ||||||
|
|
||||||
|
|
@@ -229,7 +261,13 @@ export class SignalingClient extends EventEmitter { | |||||
| */ | ||||||
| private onOpen(): void { | ||||||
| this.readyState = ReadyState.OPEN; | ||||||
| this.emit('open'); | ||||||
| if(this.reconnection) { | ||||||
| console.log("Successfully reconnected to a new WS"); | ||||||
| this.emit('reconnect') | ||||||
| } else { | ||||||
| console.log("Successfully opened a WS"); | ||||||
| this.emit('open'); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
|
|
@@ -246,7 +284,7 @@ export class SignalingClient extends EventEmitter { | |||||
| // TODO: Consider how to make it easier for users to be aware of dropped messages. | ||||||
| return; | ||||||
| } | ||||||
| const { messageType, senderClientId } = parsedEventData; | ||||||
| const {messageType, senderClientId} = parsedEventData; | ||||||
| switch (messageType) { | ||||||
| case MessageType.SDP_OFFER: | ||||||
| this.emit('sdpOffer', parsedMessagePayload, senderClientId); | ||||||
|
|
@@ -321,15 +359,36 @@ export class SignalingClient extends EventEmitter { | |||||
| * 'error' event handler. Forwards the error onto listeners. | ||||||
| */ | ||||||
| private onError(error: Error | Event): void { | ||||||
| console.log("On error invoked"); | ||||||
| this.emit('error', error); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * 'close' event handler. Forwards the error onto listeners and cleans up the connection. | ||||||
| */ | ||||||
| private onClose(): void { | ||||||
| private onClose(event?: CloseEvent): void { | ||||||
| this.readyState = ReadyState.CLOSED; | ||||||
| this.cleanupWebSocket(); | ||||||
| this.emit('close'); | ||||||
| console.log("On close invoked"); | ||||||
| switch (event.code) { | ||||||
| // Going away | ||||||
| case 1001: | ||||||
| // Abnormal closure | ||||||
| case 1006: | ||||||
| // Service Restart | ||||||
| case 1012: | ||||||
| // Try Again Later | ||||||
| case 1013: | ||||||
| // TLS Handshake | ||||||
| case 1015: | ||||||
| console.log("Allowing reconnect if option enabled on test page for code", event.code); | ||||||
| this.cleanupWebSocket(); | ||||||
| this.emit('closewithretry'); | ||||||
| break; | ||||||
| default: | ||||||
| console.log("No reconnect will be attempted. Just exiting with code", event.code); | ||||||
| this.cleanupWebSocket(); | ||||||
| this.emit('close'); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we also emit the
Suggested change
|
||||||
| break; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make the logging configurable? Currently there is no logs so adding logs might be something customers want to disable