浏览代码

feat(BridgeChannel): Add retries for WS.

dev1
Hristo Terezov 5 年前
父节点
当前提交
afa08b4ea5
共有 2 个文件被更改,包括 107 次插入7 次删除
  1. 89
    7
      modules/RTC/BridgeChannel.js
  2. 18
    0
      service/statistics/AnalyticsEvents.js

+ 89
- 7
modules/RTC/BridgeChannel.js 查看文件

@@ -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
 

+ 18
- 0
service/statistics/AnalyticsEvents.js 查看文件

@@ -442,6 +442,24 @@ export const createRttByRegionEvent = function(attributes) {
442 442
     };
443 443
 };
444 444
 
445
+/**
446
+ * Creates an event which contains an information related to the bridge channel close event.
447
+ *
448
+ * @param {string} code - A code from {@link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent}
449
+ * @param {string} reason - A string which describes the reason for closing the bridge channel.
450
+ * @returns {{type: string, action: string, attributes: { code: string, reason: string }}}
451
+ */
452
+export const createBridgeChannelClosedEvent = function(code, reason) {
453
+    return {
454
+        type: TYPE_OPERATIONAL,
455
+        action: 'bridge-channel.error',
456
+        attributes: {
457
+            code,
458
+            reason
459
+        }
460
+    };
461
+};
462
+
445 463
 /**
446 464
  * Creates an event which indicates the Time To First Media (TTFM).
447 465
  * It is measured in milliseconds relative to the beginning of the document's

正在加载...
取消
保存