ソースを参照

[RN] Add a timeout for loading the configuration

master
Lyubo Marinov 7年前
コミット
a5538adf8a

+ 1
- 6
react/features/app/actions.js ファイルの表示

@@ -10,11 +10,6 @@ import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
10 10
 
11 11
 declare var APP: Object;
12 12
 
13
-/**
14
- * Timeout for loading the configuration.
15
- */
16
-const LOAD_CONFIG_TIMEOUT = 8000;
17
-
18 13
 /**
19 14
  * Triggers an in-app navigation to a specific route. Allows navigation to be
20 15
  * abstracted between the mobile/React Native and Web/React applications.
@@ -211,7 +206,7 @@ function _loadConfig({ contextRoot, host, protocol, room }) {
211 206
 
212 207
     const key = `config.js/${baseURL}`;
213 208
 
214
-    return loadConfig(url, LOAD_CONFIG_TIMEOUT).then(
209
+    return loadConfig(url).then(
215 210
         /* onFulfilled */ config => {
216 211
             // Try to store the configuration in localStorage. If the deployment
217 212
             // specified 'getroom' as a function, for example, it does not make

+ 10
- 6
react/features/base/lib-jitsi-meet/functions.js ファイルの表示

@@ -2,7 +2,7 @@
2 2
 
3 3
 import { setConfigFromURLParams } from '../config';
4 4
 import { toState } from '../redux';
5
-import { loadScript, timeoutPromise } from '../util';
5
+import { loadScript } from '../util';
6 6
 
7 7
 import JitsiMeetJS from './_';
8 8
 
@@ -107,16 +107,20 @@ export function isFatalJitsiConnectionError(error: Object | string) {
107 107
  * Loads config.js from a specific remote server.
108 108
  *
109 109
  * @param {string} url - The URL to load.
110
- * @param {number} timeoutMs - The timeout for the configuration to be loaded,
111
- * in milliseconds.
110
+ * @param {number} [timeout] - The timeout for the configuration to be loaded,
111
+ * in milliseconds. If not specified, a default value deamed appropriate for the
112
+ * purpsoe is used.
112 113
  * @returns {Promise<Object>}
113 114
  */
114
-export function loadConfig(url: string, timeoutMs: number): Promise<Object> {
115
+export function loadConfig(
116
+        url: string,
117
+        timeout: ?number = 10 /* seconds */ * 1000 /* in milliseconds */
118
+): Promise<Object> {
115 119
     let promise;
116 120
 
117 121
     if (typeof APP === 'undefined') {
118 122
         promise
119
-            = loadScript(url)
123
+            = loadScript(url, timeout)
120 124
                 .then(() => {
121 125
                     const { config } = window;
122 126
 
@@ -150,5 +154,5 @@ export function loadConfig(url: string, timeoutMs: number): Promise<Object> {
150 154
         return value;
151 155
     });
152 156
 
153
-    return timeoutPromise(promise, timeoutMs);
157
+    return promise;
154 158
 }

+ 2
- 28
react/features/base/util/helpers.js ファイルの表示

@@ -1,3 +1,5 @@
1
+// @flow
2
+
1 3
 /**
2 4
  * Returns the namespace for all global variables, functions, etc that we need.
3 5
  *
@@ -16,31 +18,3 @@ export function getJitsiMeetGlobalNS() {
16 18
 
17 19
     return window.JitsiMeetJS.app;
18 20
 }
19
-
20
-/**
21
- * Makes the given promise fail with a timeout error if it wasn't fulfilled in
22
- * the given timeout.
23
- *
24
- * @param {Promise} promise - The promise which will be wrapped for timeout.
25
- * @param {number} ms - The amount of milliseconds to wait for a response before
26
- * failing with a timeout error.
27
- * @returns {Promise} - The wrapped promise.
28
- */
29
-export function timeoutPromise(promise, ms) {
30
-    return new Promise((resolve, reject) => {
31
-        const timeoutId = setTimeout(() => {
32
-            reject(new Error('timeout'));
33
-        }, ms);
34
-
35
-        promise.then(
36
-            res => {
37
-                clearTimeout(timeoutId);
38
-                resolve(res);
39
-            },
40
-            err => {
41
-                clearTimeout(timeoutId);
42
-                reject(err);
43
-            }
44
-        );
45
-    });
46
-}

+ 33
- 2
react/features/base/util/loadScript.native.js ファイルの表示

@@ -1,3 +1,7 @@
1
+// @flow
2
+
3
+import { timeoutPromise } from './timeoutPromise';
4
+
1 5
 /**
2 6
  * Loads a script from a specific URL. React Native cannot load a JS
3 7
  * file/resource/URL via a <script> HTML element, so the implementation
@@ -6,9 +10,12 @@
6 10
  *
7 11
  * @param {string} url - The absolute URL from which the script is to be
8 12
  * (down)loaded.
13
+ * @param {number} [timeout] - The timeout in millisecnods after which the
14
+ * loading of the specified {@code url} is to be aborted/rejected (if not
15
+ * settled yet).
9 16
  * @returns {void}
10 17
  */
11
-export function loadScript(url) {
18
+export function loadScript(url: string, timeout: ?number): Promise<void> {
12 19
     return new Promise((resolve, reject) => {
13 20
         // XXX The implementation of fetch on Android will throw an Exception on
14 21
         // the Java side which will break the app if the URL is invalid (which
@@ -26,7 +33,31 @@ export function loadScript(url) {
26 33
             return;
27 34
         }
28 35
 
29
-        fetch(url, { method: 'GET' })
36
+        let fetch_ = fetch(url, { method: 'GET' });
37
+
38
+        // The implementation of fetch provided by react-native is based on
39
+        // XMLHttpRequest. Which defines timeout as an unsigned long with
40
+        // default value 0, which means there is no timeout.
41
+        if (timeout) {
42
+            // FIXME I don't like the approach with timeoutPromise because:
43
+            //
44
+            // * It merely abandons the underlying XHR and, consequently, opens
45
+            //   us to potential issues with NetworkActivityIndicator which
46
+            //   tracks XHRs.
47
+            //
48
+            // * @paweldomas also reported that timeouts seem to be respected by
49
+            //   the XHR implementation on iOS. Given that we have
50
+            //   implementation of loadScript based on fetch and XHR (in an
51
+            //   earlier revision), I don't see why we're not using an XHR
52
+            //   directly on iOS.
53
+            //
54
+            // * The approach of timeoutPromise I found on the Internet is to
55
+            //   directly use XHR instead of fetch and abort the XHR on timeout.
56
+            //   Which may deal with the NetworkActivityIndicator at least.
57
+            fetch_ = timeoutPromise(fetch_, timeout);
58
+        }
59
+
60
+        fetch_
30 61
             .then(response => {
31 62
                 switch (response.status) {
32 63
                 case 200:

+ 1
- 1
react/features/base/util/loadScript.web.js ファイルの表示

@@ -1,4 +1,4 @@
1
-/* @flow */
1
+// @flow
2 2
 
3 3
 declare var JitsiMeetJS: Object;
4 4
 

+ 1
- 1
react/features/base/util/randomUtil.js ファイルの表示

@@ -1,4 +1,4 @@
1
-/* @flow */
1
+// @flow
2 2
 
3 3
 /**
4 4
  * Alphanumeric characters.

+ 36
- 0
react/features/base/util/timeoutPromise.js ファイルの表示

@@ -0,0 +1,36 @@
1
+// @flow
2
+
3
+/**
4
+ * Returns a new {@code Promise} which settles when a specific {@code Promise}
5
+ * settles and is automatically rejected if the specified {@code Promise}
6
+ * doesn't settle within a specific time interval.
7
+ *
8
+ * @param {Promise} promise - The {@code Promise} for which automatic rejecting
9
+ * after the speicified timout is to be implemented.
10
+ * @param {number} timeout - The number of milliseconds to wait the specified
11
+ * {@code promise} to settle before automatically rejecting the returned
12
+ * {@code Promise}.
13
+ * @returns {Promise} - A new {@code Promise} which settles when the specified
14
+ * {@code promise} settles and is automatically rejected after {@code timeout}
15
+ * milliseconds.
16
+ */
17
+export function timeoutPromise<T>(
18
+        promise: Promise<T>,
19
+        timeout: number
20
+): Promise<T> {
21
+    return new Promise((resolve, reject) => {
22
+        const timeoutID
23
+            = setTimeout(() => reject(new Error('timeout')), timeout);
24
+
25
+        promise.then(
26
+            /* onFulfilled */ value => {
27
+                resolve(value);
28
+                clearTimeout(timeoutID);
29
+            },
30
+            /* onRejected */ reason => {
31
+                reject(reason);
32
+                clearTimeout(timeoutID);
33
+            }
34
+        );
35
+    });
36
+}

読み込み中…
キャンセル
保存