openvidu-browser: reconnection support for OpenVidu Enterprise

pull/678/head
pabloFuente 2021-12-23 15:28:23 +01:00
parent 24ba648015
commit e6b4f23fcf
2 changed files with 81 additions and 43 deletions

View File

@ -1030,13 +1030,16 @@ export class OpenVidu {
} }
} }
private reconnectedCallback(): void { private reconnectWebsocketThroughRpcConnectMethod(rpcSessionId) {
logger.warn('Websocket reconnected'); // This RPC method allows checking:
if (this.isRoomAvailable()) { // Single Master: if success, connection recovered
if (!!this.session.connection) { // if error, no Master Node crashed and life will be -1. onLostConnection with reason networkDisconnect will be triggered
// This RPC method allows checking if the WebSocket reconnected to a session where // Multi Master: if success, connection recovered
// the user is still a participant, or the session evicted the user // if error and Master Node crashed notification was already received, nothing must be done
this.sendRequest('connect', { sessionId: this.session.connection.rpcSessionId }, (error, response) => { // if error and Master Node NOT crashed, sessionStatus method must be sent:
// if life is equal, networkDisconnect
// if life is greater, nodeCrashed
this.sendRequest('connect', { sessionId: rpcSessionId, reconnect: true }, (error, response) => {
if (!!error) { if (!!error) {
if (this.isMasterNodeCrashed()) { if (this.isMasterNodeCrashed()) {
@ -1047,29 +1050,47 @@ export class OpenVidu {
logger.error(error); logger.error(error);
const notifyNetworkDisconnection = (error) => { const notifyLostConnection = (reason, errorMsg) => {
logger.warn('Websocket was able to reconnect to OpenVidu Server, but your Connection was already destroyed due to timeout. You are no longer a participant of the Session and your media streams have been destroyed'); logger.warn(errorMsg);
this.session.onLostConnection("networkDisconnect"); this.session.onLostConnection(reason);
this.jsonRpcClient.close(4101, "Reconnection fault"); this.jsonRpcClient.close(4101, "Reconnection fault: " + errorMsg);
} }
const rpcSessionStatus = () => {
if (this.life === -1) { if (this.life === -1) {
notifyNetworkDisconnection(error); // Single Master
notifyLostConnection('networkDisconnect', 'WS successfully reconnected but the user was already evicted due to timeout');
} else { } else {
// Multi Master
// This RPC method is only required to find out the reason of the disconnection: // This RPC method is only required to find out the reason of the disconnection:
// whether the client lost its network connection or a Master Node crashed // whether the client lost its network connection or a Master Node crashed
this.sendRequest('sessionStatus', { sessionId: this.session.sessionId }, (error, response) => { this.sendRequest('sessionStatus', { sessionId: this.session.sessionId }, (error, response) => {
if (error != null) {
console.error('Error checking session status', error);
} else {
if (this.life === response.life) { if (this.life === response.life) {
// If the life stored in the client matches the life stored in the server, it means that the client lost its network connection // If the life stored in the client matches the life stored in the server, it means that the client lost its network connection
notifyNetworkDisconnection(error); notifyLostConnection('networkDisconnect', 'WS successfully reconnected but the user was already evicted due to timeout');
} else { } else {
// If the life stored in the client is below the life stored in the server, it means that the Master Node has crashed // If the life stored in the client is below the life stored in the server, it means that the Master Node has crashed
logger.warn('Websocket was able to reconnect to OpenVidu Server, but your Master Node crashed.'); notifyLostConnection('nodeCrashed', 'WS successfully reconnected to OpenVidu Server but your Master Node crashed');
this.session.onLostConnection("nodeCrashed"); }
this.jsonRpcClient.close(4101, "Reconnection fault");
} }
}); });
} }
};
if (error.code === 40007 && error.message === 'reconnection error') {
// Kurento error: invalid RPC sessionId. This means that the kurento-jsonrpc-server of openvidu-server where kurento-jsonrpc-client
// is trying to reconnect does not know about this sessionId. This can mean two things:
// 1) openvidu-browser managed to reconnect after a while, but openvidu-server already evicted the user for not receiving ping.
// 2) openvidu-server process is a different one because of a node crash.
// Send a "sessionStatus" method to check the reason
console.error('Invalid RPC sessionId. Client network disconnection or Master Node crash');
rpcSessionStatus();
} else {
rpcSessionStatus();
}
} }
} else { } else {
@ -1077,6 +1098,13 @@ export class OpenVidu {
this.session.onRecoveredConnection(); this.session.onRecoveredConnection();
} }
}); });
}
private reconnectedCallback(): void {
logger.warn('Websocket reconnected');
if (this.isRoomAvailable()) {
if (!!this.session.connection) {
this.reconnectWebsocketThroughRpcConnectMethod(this.session.connection.rpcSessionId);
} else { } else {
logger.warn('There was no previous connection when running reconnection callback'); logger.warn('There was no previous connection when running reconnection callback');
// Make Session object dispatch 'sessionDisconnected' event // Make Session object dispatch 'sessionDisconnected' event

View File

@ -100,9 +100,19 @@ function WebSocketWithReconnection(config) {
reconnectAux(maxRetries, numRetries); reconnectAux(maxRetries, numRetries);
} }
function addReconnectionQueryParamsIfMissing(uriString) {
var searchParams = new URLSearchParams((new URL(uriString)).search);
if (!searchParams.has("reconnect")) {
uriString = (Array.from(searchParams).length > 0) ? (uriString + '&reconnect=true') : (uriString + '?reconnect=true');
}
return uriString;
}
function reconnectAux(maxRetries, numRetries) { function reconnectAux(maxRetries, numRetries) {
Logger.debug("Reconnection attempt #" + numRetries); Logger.debug("Reconnection attempt #" + numRetries);
ws.close(4104, 'Connection closed for reconnection'); ws.close(4104, 'Connection closed for reconnection');
wsUri = addReconnectionQueryParamsIfMissing(wsUri);
ws = new WebSocket(wsUri); ws = new WebSocket(wsUri);
ws.onopen = () => { ws.onopen = () => {