Browse Source

feat(RN): add a fatal error state which is a catch all

Adds a fatal error state on which will depend whether or not the reload
screen is to be displayed. It is to happen when a relevant fatal error
action is not claimed by any feature for error recovery (the recoverable
flag is not set).
master
paweldomas 6 years ago
parent
commit
67d7d4fc14

+ 12
- 0
react/features/overlay/actionTypes.js View File

@@ -21,3 +21,15 @@ export const MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED
21 21
  * @public
22 22
  */
23 23
 export const SUSPEND_DETECTED = Symbol('SUSPEND_DETECTED');
24
+
25
+/**
26
+ * Adjust the state of the fatal error which shows/hides the reload screen. See
27
+ * action methods's description for more info about each of the fields.
28
+ *
29
+ * {
30
+ *     type: SET_FATAL_ERROR,
31
+ *     fatalError: ?Object
32
+ * }
33
+ * @public
34
+ */
35
+export const SET_FATAL_ERROR = Symbol('SET_FATAL_ERROR');

+ 22
- 0
react/features/overlay/actions.js View File

@@ -3,6 +3,7 @@ import { toURLString } from '../base/util';
3 3
 
4 4
 import {
5 5
     MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
6
+    SET_FATAL_ERROR,
6 7
     SUSPEND_DETECTED
7 8
 } from './actionTypes';
8 9
 
@@ -37,6 +38,8 @@ export function mediaPermissionPromptVisibilityChanged(isVisible, browser) {
37 38
  */
38 39
 export function _reloadNow() {
39 40
     return (dispatch, getState) => {
41
+        dispatch(setFatalError(undefined));
42
+
40 43
         const { locationURL } = getState()['features/base/connection'];
41 44
 
42 45
         logger.info(`Reloading the conference using URL: ${locationURL}`);
@@ -62,3 +65,22 @@ export function suspendDetected() {
62 65
         type: SUSPEND_DETECTED
63 66
     };
64 67
 }
68
+
69
+/**
70
+ * The action indicates that an unrecoverable error has occurred and the reload
71
+ * screen will be displayed or hidden.
72
+ *
73
+ * @param {Object} fatalError - A critical error which was not claimed by any
74
+ * feature for error recovery (the recoverable flag was not set). If
75
+ * {@code undefined} then any fatal error currently stored will be discarded.
76
+ * @returns {{
77
+ *     type: SET_FATAL_ERROR,
78
+ *     fatalError: ?Error
79
+ * }}
80
+ */
81
+export function setFatalError(fatalError) {
82
+    return {
83
+        type: SET_FATAL_ERROR,
84
+        fatalError
85
+    };
86
+}

+ 24
- 4
react/features/overlay/components/AbstractPageReloadOverlay.js View File

@@ -77,6 +77,25 @@ export default class AbstractPageReloadOverlay extends Component<*, *> {
77 77
      * {@code false}, otherwise.
78 78
      */
79 79
     static needsRender(state: Object) {
80
+        // FIXME web does not rely on the 'recoverable' flag set on an error
81
+        // action, but on a predefined list of fatal errors. Because of that
82
+        // the value of 'fatalError' which relies on the flag should not be used
83
+        // on web yet (until conference/connection and their errors handling is
84
+        // not unified).
85
+        return typeof APP === 'undefined'
86
+            ? Boolean(state['features/overlay'].fatalError)
87
+            : this.needsRenderWeb(state);
88
+    }
89
+
90
+    /**
91
+     * Determines whether this overlay needs to be rendered (according to a
92
+     * specific redux state). Called by {@link OverlayContainer}.
93
+     *
94
+     * @param {Object} state - The redux state.
95
+     * @returns {boolean} - If this overlay needs to be rendered, {@code true};
96
+     * {@code false}, otherwise.
97
+     */
98
+    static needsRenderWeb(state: Object) {
80 99
         const conferenceError = state['features/base/conference'].error;
81 100
         const configError = state['features/base/config'].error;
82 101
         const connectionError = state['features/base/connection'].error;
@@ -273,13 +292,14 @@ export default class AbstractPageReloadOverlay extends Component<*, *> {
273 292
  * }}
274 293
  */
275 294
 export function abstractMapStateToProps(state: Object) {
276
-    const { error: conferenceError } = state['features/base/conference'];
277 295
     const { error: configError } = state['features/base/config'];
278 296
     const { error: connectionError } = state['features/base/connection'];
297
+    const { fatalError } = state['features/overlay'];
279 298
 
280 299
     return {
281
-        details: connectionError ? connectionError.details : undefined,
282
-        isNetworkFailure: Boolean(configError || connectionError),
283
-        reason: (configError || connectionError || conferenceError).message
300
+        details: fatalError && fatalError.details,
301
+        isNetworkFailure:
302
+            fatalError === configError || fatalError === connectionError,
303
+        reason: fatalError && fatalError.message
284 304
     };
285 305
 }

+ 2
- 2
react/features/overlay/components/PageReloadOverlay.native.js View File

@@ -6,10 +6,9 @@ import { appNavigate } from '../../app';
6 6
 import { translate } from '../../base/i18n';
7 7
 import { LoadingIndicator } from '../../base/react';
8 8
 
9
-import { _reloadNow } from '../actions';
10
-
11 9
 import AbstractPageReloadOverlay, { abstractMapStateToProps }
12 10
     from './AbstractPageReloadOverlay';
11
+import { _reloadNow, setFatalError } from '../actions';
13 12
 import OverlayFrame from './OverlayFrame';
14 13
 import { pageReloadOverlay as styles } from './styles';
15 14
 
@@ -42,6 +41,7 @@ class PageReloadOverlay extends AbstractPageReloadOverlay {
42 41
      */
43 42
     _onCancel() {
44 43
         clearInterval(this._interval);
44
+        this.props.dispatch(setFatalError(undefined));
45 45
         this.props.dispatch(appNavigate(undefined));
46 46
     }
47 47
 

+ 1
- 0
react/features/overlay/index.js View File

@@ -1,4 +1,5 @@
1 1
 export * from './actions';
2 2
 export * from './components';
3 3
 
4
+import './middleware';
4 5
 import './reducer';

+ 27
- 0
react/features/overlay/middleware.js View File

@@ -0,0 +1,27 @@
1
+// @flow
2
+
3
+import { StateListenerRegistry } from '../base/redux';
4
+
5
+import { setFatalError } from './actions';
6
+
7
+declare var APP: Object;
8
+
9
+/**
10
+ * State listener which emits the {@code fatalErrorOccurred} action which works
11
+ * as a catch all for critical errors which have not been claimed by any other
12
+ * feature for error recovery (the recoverable flag is not set).
13
+ */
14
+StateListenerRegistry.register(
15
+    /* selector */ state => {
16
+        const { error: conferenceError } = state['features/base/conference'];
17
+        const { error: configError } = state['features/base/config'];
18
+        const { error: connectionError } = state['features/base/connection'];
19
+
20
+        return configError || connectionError || conferenceError;
21
+    },
22
+    /* listener */ (error, { dispatch }) => {
23
+        error
24
+            && typeof error.recoverable === 'undefined'
25
+            && dispatch(setFatalError(error));
26
+    }
27
+);

+ 19
- 1
react/features/overlay/reducer.js View File

@@ -4,6 +4,7 @@ import { assign, ReducerRegistry, set } from '../base/redux';
4 4
 
5 5
 import {
6 6
     MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED,
7
+    SET_FATAL_ERROR,
7 8
     SUSPEND_DETECTED
8 9
 } from './actionTypes';
9 10
 
@@ -12,11 +13,14 @@ import {
12 13
  *
13 14
  * FIXME: these pieces of state should probably be in a different place.
14 15
  */
15
-ReducerRegistry.register('features/overlay', (state = {}, action) => {
16
+ReducerRegistry.register('features/overlay', (state = { }, action) => {
16 17
     switch (action.type) {
17 18
     case MEDIA_PERMISSION_PROMPT_VISIBILITY_CHANGED:
18 19
         return _mediaPermissionPromptVisibilityChanged(state, action);
19 20
 
21
+    case SET_FATAL_ERROR:
22
+        return _setFatalError(state, action);
23
+
20 24
     case SUSPEND_DETECTED:
21 25
         return _suspendDetected(state);
22 26
     }
@@ -54,3 +58,17 @@ function _mediaPermissionPromptVisibilityChanged(
54 58
 function _suspendDetected(state) {
55 59
     return set(state, 'suspendDetected', true);
56 60
 }
61
+
62
+/**
63
+ * Reduces a specific redux action {@code SET_FATAL_ERROR} of the feature
64
+ * overlay.
65
+ *
66
+ * @param {Object} state - The redux state of the feature overlay.
67
+ * @param {Error} fatalError - If the value is set it indicates that a fatal
68
+ * error has occurred and that the reload screen is to be displayed.
69
+ * @returns {Object}
70
+ * @private
71
+ */
72
+function _setFatalError(state, { fatalError }) {
73
+    return set(state, 'fatalError', fatalError);
74
+}

Loading…
Cancel
Save