소스 검색

Introduced new actions and functions for app initialization

j8
Ilya Daynatovich 8 년 전
부모
커밋
f53fb3d814

react/features/app/actions.js → react/features/app/actions.native.js 파일 보기


+ 173
- 0
react/features/app/actions.web.js 파일 보기

@@ -0,0 +1,173 @@
1
+import { setRoom } from '../base/conference';
2
+import {
3
+    getDomain,
4
+    setDomain
5
+} from '../base/connection';
6
+import {
7
+    loadConfig,
8
+    setConfig
9
+} from '../base/lib-jitsi-meet';
10
+
11
+import {
12
+    APP_WILL_MOUNT,
13
+    APP_WILL_UNMOUNT
14
+} from './actionTypes';
15
+import {
16
+    _getRoomAndDomainFromUrlString,
17
+    _getRouteToRender,
18
+    init
19
+} from './functions';
20
+import './reducer';
21
+
22
+
23
+/**
24
+ * Triggers an in-app navigation to a different route. Allows navigation to be
25
+ * abstracted between the mobile and web versions.
26
+ *
27
+ * @param {(string|undefined)} urlOrRoom - The URL or room name to which to
28
+ * navigate.
29
+ * @returns {Function}
30
+ */
31
+export function appNavigate(urlOrRoom) {
32
+    return (dispatch, getState) => {
33
+        const oldDomain = getDomain(getState());
34
+
35
+        const { domain, room } = _getRoomAndDomainFromUrlString(urlOrRoom);
36
+
37
+        // TODO Kostiantyn Tsaregradskyi: We should probably detect if user is
38
+        // currently in a conference and ask her if she wants to close the
39
+        // current conference and start a new one with the new room name or
40
+        // domain.
41
+
42
+        if (typeof domain === 'undefined' || oldDomain === domain) {
43
+            // If both domain and room vars became undefined, that means we're
44
+            // actually dealing with just room name and not with URL.
45
+            dispatch(
46
+                _setRoomAndNavigate(
47
+                    typeof room === 'undefined' && typeof domain === 'undefined'
48
+                        ? urlOrRoom
49
+                        : room));
50
+        } else if (oldDomain !== domain) {
51
+            // Update domain without waiting for config to be loaded to prevent
52
+            // race conditions when we will start to load config multiple times.
53
+            dispatch(setDomain(domain));
54
+
55
+            // If domain has changed, we need to load the config of the new
56
+            // domain and set it, and only after that we can navigate to
57
+            // different route.
58
+            loadConfig(`https://${domain}`)
59
+                .then(
60
+                    config => configLoaded(/* err */ undefined, config),
61
+                    err => configLoaded(err, /* config */ undefined));
62
+        }
63
+
64
+        /**
65
+         * Notifies that an attempt to load the config(uration) of domain has
66
+         * completed.
67
+         *
68
+         * @param {string|undefined} err - If the loading has failed, the error
69
+         * detailing the cause of the failure.
70
+         * @param {Object|undefined} config - If the loading has succeeded, the
71
+         * loaded config(uration).
72
+         * @returns {void}
73
+         */
74
+        function configLoaded(err, config) {
75
+            if (err) {
76
+                // XXX The failure could be, for example, because of a
77
+                // certificate-related error. In which case the connection will
78
+                // fail later in Strophe anyway even if we use the default
79
+                // config here.
80
+
81
+                // The function loadConfig will log the err.
82
+                return;
83
+            }
84
+
85
+            // We set room name only here to prevent race conditions on app
86
+            // start to not make app re-render conference page for two times.
87
+            dispatch(setRoom(room));
88
+            dispatch(setConfig(config));
89
+            _navigate(getState());
90
+        }
91
+    };
92
+}
93
+
94
+/**
95
+ * Temporary solution. Should dispatch actions related to
96
+ * initial settings of the app like setting log levels,
97
+ * reading the config parameters from query string etc.
98
+ *
99
+ * @returns {Function}
100
+ */
101
+export function appInit() {
102
+    return () => {
103
+        init();
104
+    };
105
+}
106
+
107
+/**
108
+ * Signals that a specific App will mount (in the terms of React).
109
+ *
110
+ * @param {App} app - The App which will mount.
111
+ * @returns {{
112
+ *     type: APP_WILL_MOUNT,
113
+ *     app: App
114
+ * }}
115
+ */
116
+export function appWillMount(app) {
117
+    return {
118
+        type: APP_WILL_MOUNT,
119
+        app
120
+    };
121
+}
122
+
123
+/**
124
+ * Signals that a specific App will unmount (in the terms of React).
125
+ *
126
+ * @param {App} app - The App which will unmount.
127
+ * @returns {{
128
+ *     type: APP_WILL_UNMOUNT,
129
+ *     app: App
130
+ * }}
131
+ */
132
+export function appWillUnmount(app) {
133
+    return {
134
+        type: APP_WILL_UNMOUNT,
135
+        app
136
+    };
137
+}
138
+
139
+/**
140
+ * Navigates to route corresponding to current room name.
141
+ *
142
+ * @param {Object} state - Redux state.
143
+ * @private
144
+ * @returns {void}
145
+ */
146
+function _navigate(state) {
147
+    const app = state['features/app'].app;
148
+    const routeToRender = _getRouteToRender(state);
149
+
150
+    app._navigate(routeToRender);
151
+}
152
+
153
+/**
154
+ * Sets room and navigates to new route if needed.
155
+ *
156
+ * @param {string} newRoom - New room name.
157
+ * @private
158
+ * @returns {Function}
159
+ */
160
+function _setRoomAndNavigate(newRoom) {
161
+    return (dispatch, getState) => {
162
+        const oldRoom = getState()['features/base/conference'].room;
163
+
164
+        dispatch(setRoom(newRoom));
165
+
166
+        const state = getState();
167
+        const room = state['features/base/conference'].room;
168
+
169
+        if (room !== oldRoom) {
170
+            _navigate(state);
171
+        }
172
+    };
173
+}

+ 4
- 80
react/features/app/components/App.web.js 파일 보기

@@ -1,4 +1,4 @@
1
-/* global APP, JitsiMeetJS, loggingConfig $ */
1
+/* global $ */
2 2
 import React from 'react';
3 3
 import { Provider } from 'react-redux';
4 4
 import { compose } from 'redux';
@@ -13,18 +13,7 @@ import { getDomain } from '../../base/connection';
13 13
 import { RouteRegistry } from '../../base/navigator';
14 14
 
15 15
 import { AbstractApp } from './AbstractApp';
16
-import settings from '../../../../modules/settings/Settings';
17
-
18
-
19
-import URLProcessor from '../../../../modules/config/URLProcessor';
20
-import getTokenData from '../../../../modules/tokendata/TokenData';
21
-import JitsiMeetLogStorage from '../../../../modules/util/JitsiMeetLogStorage';
22
-
23
-// eslint-disable-next-line max-len
24
-import KeyboardShortcut from '../../../../modules/keyboardshortcut/keyboardshortcut';
25
-
26
-const Logger = require('jitsi-meet-logger');
27
-const LogCollector = Logger.LogCollector;
16
+import { appInit } from '../actions';
28 17
 
29 18
 
30 19
 /**
@@ -64,78 +53,13 @@ export class App extends AbstractApp {
64 53
     }
65 54
 
66 55
     /**
67
-     * Init translation from old app.
56
+     * Inits the app before component will mount.
68 57
      *
69 58
      * @inheritdoc
70 59
      */
71 60
     componentWillMount(...args) {
72 61
         super.componentWillMount(...args);
73
-
74
-        URLProcessor.setConfigParametersFromUrl();
75
-
76
-        /* APP.init BEGIN */
77
-
78
-        /*  Init logging BEGIN */
79
-
80
-        // Adjust logging level
81
-        configureLoggingLevels();
82
-
83
-        // Create the LogCollector and register it as the global log transport.
84
-        // It is done early to capture as much logs as possible. Captured logs
85
-        // will be cached, before the JitsiMeetLogStorage gets ready (statistics
86
-        // module is initialized).
87
-        if (!APP.logCollector && !loggingConfig.disableLogCollector) {
88
-            APP.logCollector = new LogCollector(new JitsiMeetLogStorage());
89
-            Logger.addGlobalTransport(APP.logCollector);
90
-            JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
91
-        }
92
-
93
-        /*  Init logging BEGIN */
94
-
95
-        APP.keyboardshortcut = KeyboardShortcut;
96
-        APP.tokenData = getTokenData();
97
-
98
-        /* APP.init END */
99
-
100
-        APP.API.init(APP.tokenData.externalAPISettings);
101
-
102
-        /**
103
-         * Adjusts the logging levels.
104
-         *
105
-         * @private
106
-         * @returns {void}
107
-         */
108
-        function configureLoggingLevels() {
109
-            // NOTE The library Logger is separated from
110
-            // the app loggers, so the levels
111
-            // have to be set in two places
112
-
113
-            // Set default logging level
114
-            const defaultLogLevel
115
-                = loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
116
-
117
-            Logger.setLogLevel(defaultLogLevel);
118
-            JitsiMeetJS.setLogLevel(defaultLogLevel);
119
-
120
-            // NOTE console was used on purpose here to go around the logging
121
-            // and always print the default logging level to the console
122
-            console.info(`Default logging level set to: ${defaultLogLevel}`);
123
-
124
-            // Set log level for each logger
125
-            if (loggingConfig) {
126
-                Object.keys(loggingConfig).forEach(loggerName => {
127
-                    if (loggerName !== 'defaultLogLevel') {
128
-                        const level = loggingConfig[loggerName];
129
-
130
-                        Logger.setLogLevelById(level, loggerName);
131
-                        JitsiMeetJS.setLogLevelById(level, loggerName);
132
-                    }
133
-                });
134
-            }
135
-        }
136
-
137
-
138
-        APP.translation.init(settings.getLanguage());
62
+        this.props.store.dispatch(appInit());
139 63
     }
140 64
 
141 65
     /**

react/features/app/functions.js → react/features/app/functions.native.js 파일 보기


+ 214
- 0
react/features/app/functions.web.js 파일 보기

@@ -0,0 +1,214 @@
1
+/* global APP, JitsiMeetJS, loggingConfig */
2
+import { isRoomValid } from '../base/conference';
3
+import { RouteRegistry } from '../base/navigator';
4
+import { Conference } from '../conference';
5
+import { WelcomePage } from '../welcome';
6
+
7
+import getTokenData from '../../../modules/tokendata/TokenData';
8
+import settings from '../../../modules/settings/Settings';
9
+
10
+import URLProcessor from '../../../modules/config/URLProcessor';
11
+import JitsiMeetLogStorage from '../../../modules/util/JitsiMeetLogStorage';
12
+
13
+// eslint-disable-next-line max-len
14
+import KeyboardShortcut from '../../../modules/keyboardshortcut/keyboardshortcut';
15
+
16
+const Logger = require('jitsi-meet-logger');
17
+const LogCollector = Logger.LogCollector;
18
+
19
+
20
+/**
21
+ * Gets room name and domain from URL object.
22
+ *
23
+ * @param {URL} url - URL object.
24
+ * @private
25
+ * @returns {{
26
+ *      domain: (string|undefined),
27
+ *      room: (string|undefined)
28
+ *  }}
29
+ */
30
+function _getRoomAndDomainFromUrlObject(url) {
31
+    let domain;
32
+    let room;
33
+
34
+    if (url) {
35
+        domain = url.hostname;
36
+        room = url.pathname.substr(1);
37
+
38
+        // Convert empty string to undefined to simplify checks.
39
+        if (room === '') {
40
+            room = undefined;
41
+        }
42
+        if (domain === '') {
43
+            domain = undefined;
44
+        }
45
+    }
46
+
47
+    return {
48
+        domain,
49
+        room
50
+    };
51
+}
52
+
53
+/**
54
+ * Gets conference room name and connection domain from URL.
55
+ *
56
+ * @param {(string|undefined)} url - URL.
57
+ * @returns {{
58
+ *      domain: (string|undefined),
59
+ *      room: (string|undefined)
60
+ *  }}
61
+ */
62
+export function _getRoomAndDomainFromUrlString(url) {
63
+    // Rewrite the specified URL in order to handle special cases such as
64
+    // hipchat.com and enso.me which do not follow the common pattern of most
65
+    // Jitsi Meet deployments.
66
+    if (typeof url === 'string') {
67
+        // hipchat.com
68
+        let regex = /^(https?):\/\/hipchat.com\/video\/call\//gi;
69
+        let match = regex.exec(url);
70
+
71
+        if (!match) {
72
+            // enso.me
73
+            regex = /^(https?):\/\/enso\.me\/(?:call|meeting)\//gi;
74
+            match = regex.exec(url);
75
+        }
76
+        if (match && match.length > 1) {
77
+            /* eslint-disable no-param-reassign, prefer-template */
78
+
79
+            url
80
+                = match[1] /* URL protocol */
81
+                + '://enso.hipchat.me/'
82
+                + url.substring(regex.lastIndex);
83
+
84
+            /* eslint-enable no-param-reassign, prefer-template */
85
+        }
86
+    }
87
+
88
+    return _getRoomAndDomainFromUrlObject(_urlStringToObject(url));
89
+}
90
+
91
+/**
92
+ * Determines which route is to be rendered in order to depict a specific Redux
93
+ * store.
94
+ *
95
+ * @param {(Object|Function)} stateOrGetState - Redux state or Regux getState()
96
+ * method.
97
+ * @returns {Route}
98
+ */
99
+export function _getRouteToRender(stateOrGetState) {
100
+    const state
101
+        = typeof stateOrGetState === 'function'
102
+        ? stateOrGetState()
103
+        : stateOrGetState;
104
+    const room = state['features/base/conference'].room;
105
+    const component = isRoomValid(room) ? Conference : WelcomePage;
106
+
107
+    return RouteRegistry.getRouteByComponent(component);
108
+}
109
+
110
+/**
111
+ * Parses a string into a URL (object).
112
+ *
113
+ * @param {(string|undefined)} url - The URL to parse.
114
+ * @private
115
+ * @returns {URL}
116
+ */
117
+function _urlStringToObject(url) {
118
+    let urlObj;
119
+
120
+    if (url) {
121
+        try {
122
+            urlObj = new URL(url);
123
+        } catch (ex) {
124
+            // The return value will signal the failure & the logged
125
+            // exception will provide the details to the developers.
126
+            console.log(`${url} seems to be not a valid URL, but it's OK`, ex);
127
+        }
128
+    }
129
+
130
+    return urlObj;
131
+}
132
+
133
+/**
134
+ * Temporary solution. Later we'll get rid of global APP
135
+ * and set its properties in redux store.
136
+ *
137
+ * @returns {void}
138
+ */
139
+export function init() {
140
+    _setConfigParametersFromUrl();
141
+    _initLogging();
142
+
143
+    APP.keyboardshortcut = KeyboardShortcut;
144
+    APP.tokenData = getTokenData();
145
+    APP.API.init(APP.tokenData.externalAPISettings);
146
+
147
+    APP.translation.init(settings.getLanguage());
148
+}
149
+
150
+/**
151
+ * Initializes logging in the app.
152
+ *
153
+ * @private
154
+ * @returns {void}
155
+ */
156
+function _initLogging() {
157
+    // Adjust logging level
158
+    configureLoggingLevels();
159
+
160
+    // Create the LogCollector and register it as the global log transport.
161
+    // It is done early to capture as much logs as possible. Captured logs
162
+    // will be cached, before the JitsiMeetLogStorage gets ready (statistics
163
+    // module is initialized).
164
+    if (!APP.logCollector && !loggingConfig.disableLogCollector) {
165
+        APP.logCollector = new LogCollector(new JitsiMeetLogStorage());
166
+        Logger.addGlobalTransport(APP.logCollector);
167
+        JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
168
+    }
169
+}
170
+
171
+/**
172
+ * Adjusts the logging levels.
173
+ *
174
+ * @private
175
+ * @returns {void}
176
+ */
177
+function configureLoggingLevels() {
178
+    // NOTE The library Logger is separated from
179
+    // the app loggers, so the levels
180
+    // have to be set in two places
181
+
182
+    // Set default logging level
183
+    const defaultLogLevel
184
+        = loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
185
+
186
+    Logger.setLogLevel(defaultLogLevel);
187
+    JitsiMeetJS.setLogLevel(defaultLogLevel);
188
+
189
+    // NOTE console was used on purpose here to go around the logging
190
+    // and always print the default logging level to the console
191
+    console.info(`Default logging level set to: ${defaultLogLevel}`);
192
+
193
+    // Set log level for each logger
194
+    if (loggingConfig) {
195
+        Object.keys(loggingConfig).forEach(loggerName => {
196
+            if (loggerName !== 'defaultLogLevel') {
197
+                const level = loggingConfig[loggerName];
198
+
199
+                Logger.setLogLevelById(level, loggerName);
200
+                JitsiMeetJS.setLogLevelById(level, loggerName);
201
+            }
202
+        });
203
+    }
204
+}
205
+
206
+/**
207
+ * Sets config parameters from query string.
208
+ *
209
+ * @private
210
+ * @returns {void}
211
+ */
212
+function _setConfigParametersFromUrl() {
213
+    URLProcessor.setConfigParametersFromUrl();
214
+}

Loading…
취소
저장