|
@@ -1,6 +1,8 @@
|
1
|
1
|
import { getLogger } from 'jitsi-meet-logger';
|
2
|
2
|
|
3
|
3
|
import RTCEvents from '../../service/RTC/RTCEvents';
|
|
4
|
+import { createBridgeChannelClosedEvent } from '../../service/statistics/AnalyticsEvents';
|
|
5
|
+import Statistics from '../statistics/statistics';
|
4
|
6
|
import GlobalOnErrorHandler from '../util/GlobalOnErrorHandler';
|
5
|
7
|
|
6
|
8
|
const logger = getLogger(__filename);
|
|
@@ -46,6 +48,12 @@ export default class BridgeChannel {
|
46
|
48
|
// @type {string} "datachannel" / "websocket"
|
47
|
49
|
this._mode = null;
|
48
|
50
|
|
|
51
|
+ // Indicates whether the connection retries are enabled or not.
|
|
52
|
+ this._areRetriesEnabled = false;
|
|
53
|
+
|
|
54
|
+ // Indicates whether the connection was closed from the client or not.
|
|
55
|
+ this._closedFromClient = false;
|
|
56
|
+
|
49
|
57
|
// If a RTCPeerConnection is given, listen for new RTCDataChannel
|
50
|
58
|
// event.
|
51
|
59
|
if (peerconnection) {
|
|
@@ -61,13 +69,77 @@ export default class BridgeChannel {
|
61
|
69
|
|
62
|
70
|
// Otherwise create a WebSocket connection.
|
63
|
71
|
} else if (wsUrl) {
|
64
|
|
- // Create a WebSocket instance.
|
65
|
|
- const ws = new WebSocket(wsUrl);
|
|
72
|
+ this._areRetriesEnabled = true;
|
|
73
|
+ this._wsUrl = wsUrl;
|
|
74
|
+ this._initWebSocket();
|
|
75
|
+ }
|
|
76
|
+ }
|
66
|
77
|
|
67
|
|
- // Handle the WebSocket.
|
68
|
|
- this._handleChannel(ws);
|
69
|
|
- this._mode = 'websocket';
|
|
78
|
+ /**
|
|
79
|
+ * Initializes the web socket channel.
|
|
80
|
+ *
|
|
81
|
+ * @returns {void}
|
|
82
|
+ */
|
|
83
|
+ _initWebSocket() {
|
|
84
|
+ // Create a WebSocket instance.
|
|
85
|
+ const ws = new WebSocket(this._wsUrl);
|
|
86
|
+
|
|
87
|
+ // Handle the WebSocket.
|
|
88
|
+ this._handleChannel(ws);
|
|
89
|
+ this._mode = 'websocket';
|
|
90
|
+ }
|
|
91
|
+
|
|
92
|
+ /**
|
|
93
|
+ * Starts the websocket connection retries.
|
|
94
|
+ *
|
|
95
|
+ * @returns {void}
|
|
96
|
+ */
|
|
97
|
+ _startConnectionRetries() {
|
|
98
|
+ let timeoutS = 1;
|
|
99
|
+
|
|
100
|
+ const reload = () => {
|
|
101
|
+ if (this.isOpen()) {
|
|
102
|
+ return;
|
|
103
|
+ }
|
|
104
|
+ this._initWebSocket(this._wsUrl);
|
|
105
|
+ timeoutS = Math.min(timeoutS * 2, 60);
|
|
106
|
+ this._retryTimeout = setTimeout(reload, timeoutS * 1000);
|
|
107
|
+ };
|
|
108
|
+
|
|
109
|
+ this._retryTimeout = setTimeout(reload, timeoutS * 1000);
|
|
110
|
+ }
|
|
111
|
+
|
|
112
|
+ /**
|
|
113
|
+ * Stops the websocket connection retries.
|
|
114
|
+ *
|
|
115
|
+ * @returns {void}
|
|
116
|
+ */
|
|
117
|
+ _stopConnectionRetries() {
|
|
118
|
+ if (this._retryTimeout) {
|
|
119
|
+ clearTimeout(this._retryTimeout);
|
|
120
|
+ this._retryTimeout = undefined;
|
|
121
|
+ }
|
|
122
|
+ }
|
|
123
|
+
|
|
124
|
+ /**
|
|
125
|
+ * Retries to establish the websocket connection after the connection was closed by the server.
|
|
126
|
+ *
|
|
127
|
+ * @param {CloseEvent} closeEvent - The close event that triggered the retries.
|
|
128
|
+ * @returns {void}
|
|
129
|
+ */
|
|
130
|
+ _retryWebSocketConnection(closeEvent) {
|
|
131
|
+ if (!this._areRetriesEnabled) {
|
|
132
|
+ return;
|
70
|
133
|
}
|
|
134
|
+ const { code, reason } = closeEvent;
|
|
135
|
+
|
|
136
|
+ Statistics.sendAnalytics(createBridgeChannelClosedEvent(code, reason));
|
|
137
|
+ this._areRetriesEnabled = false;
|
|
138
|
+ this._eventEmitter.once(RTCEvents.DATA_CHANNEL_OPEN, () => {
|
|
139
|
+ this._stopConnectionRetries();
|
|
140
|
+ this._areRetriesEnabled = true;
|
|
141
|
+ });
|
|
142
|
+ this._startConnectionRetries();
|
71
|
143
|
}
|
72
|
144
|
|
73
|
145
|
/**
|
|
@@ -82,6 +154,9 @@ export default class BridgeChannel {
|
82
|
154
|
* Closes the currently opened channel.
|
83
|
155
|
*/
|
84
|
156
|
close() {
|
|
157
|
+ this._closedFromClient = true;
|
|
158
|
+ this._stopConnectionRetries();
|
|
159
|
+ this._areRetriesEnabled = false;
|
85
|
160
|
if (this._channel) {
|
86
|
161
|
try {
|
87
|
162
|
this._channel.close();
|
|
@@ -284,8 +359,14 @@ export default class BridgeChannel {
|
284
|
359
|
}
|
285
|
360
|
};
|
286
|
361
|
|
287
|
|
- channel.onclose = () => {
|
288
|
|
- logger.info('Channel closed');
|
|
362
|
+ channel.onclose = event => {
|
|
363
|
+ logger.info(`Channel closed by ${this._closedFromClient ? 'client' : 'server'}`);
|
|
364
|
+
|
|
365
|
+ if (this._mode === 'websocket') {
|
|
366
|
+ if (!this._closedFromClient) {
|
|
367
|
+ this._retryWebSocketConnection(event);
|
|
368
|
+ }
|
|
369
|
+ }
|
289
|
370
|
|
290
|
371
|
// Remove the channel.
|
291
|
372
|
this._channel = null;
|
|
@@ -306,6 +387,7 @@ export default class BridgeChannel {
|
306
|
387
|
const channel = this._channel;
|
307
|
388
|
|
308
|
389
|
if (!this.isOpen()) {
|
|
390
|
+ logger.error('Bridge Channel send: no opened channel.');
|
309
|
391
|
throw new Error('No opened channel');
|
310
|
392
|
}
|
311
|
393
|
|