2017-04-14 16:48:40 +00:00
|
|
|
/* @flow */
|
|
|
|
|
|
|
|
import Logger from 'jitsi-meet-logger';
|
2016-12-14 12:09:29 +00:00
|
|
|
|
2017-01-15 04:05:56 +00:00
|
|
|
import { isRoomValid } from '../base/conference';
|
2017-02-19 00:42:11 +00:00
|
|
|
import JitsiMeetJS from '../base/lib-jitsi-meet';
|
2017-04-14 16:48:40 +00:00
|
|
|
import { Platform, RouteRegistry } from '../base/react';
|
2017-01-15 04:05:56 +00:00
|
|
|
import { Conference } from '../conference';
|
2017-04-14 16:48:40 +00:00
|
|
|
import {
|
|
|
|
NoMobileApp,
|
|
|
|
PluginRequiredBrowser,
|
|
|
|
UnsupportedDesktopBrowser,
|
|
|
|
UnsupportedMobileBrowser
|
|
|
|
} from '../unsupported-browser';
|
2017-01-15 04:05:56 +00:00
|
|
|
import { WelcomePage } from '../welcome';
|
|
|
|
|
2016-12-14 12:09:29 +00:00
|
|
|
import URLProcessor from '../../../modules/config/URLProcessor';
|
2017-01-10 21:55:31 +00:00
|
|
|
import KeyboardShortcut
|
|
|
|
from '../../../modules/keyboardshortcut/keyboardshortcut';
|
|
|
|
import getTokenData from '../../../modules/tokendata/TokenData';
|
2016-12-14 12:09:29 +00:00
|
|
|
import JitsiMeetLogStorage from '../../../modules/util/JitsiMeetLogStorage';
|
|
|
|
|
2017-04-14 16:48:40 +00:00
|
|
|
declare var APP: Object;
|
|
|
|
declare var interfaceConfig: Object;
|
|
|
|
declare var loggingConfig: Object;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array of rules defining whether we should {@link _interceptComponent} to
|
|
|
|
* render.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {Object} state - Object containing current Redux state.
|
|
|
|
* @returns {ReactElement|void}
|
|
|
|
* @type {Function[]}
|
|
|
|
*/
|
|
|
|
const _INTERCEPT_COMPONENT_RULES = [
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This rule describes case when user opens application using mobile
|
|
|
|
* browser. In order to promote the app, we choose to suggest the mobile
|
|
|
|
* app even if the browser supports the app (e.g. Google Chrome with
|
|
|
|
* WebRTC support on Android).
|
|
|
|
*
|
|
|
|
* @param {Object} state - Redux state of the app.
|
|
|
|
* @returns {UnsupportedMobileBrowser|void} If the rule is satisfied then
|
|
|
|
* we should intercept existing component by UnsupportedMobileBrowser.
|
|
|
|
*/
|
|
|
|
() => {
|
|
|
|
const OS = Platform.OS;
|
|
|
|
|
|
|
|
if (OS === 'android' || OS === 'ios') {
|
|
|
|
const mobileAppPromo
|
|
|
|
= typeof interfaceConfig === 'object'
|
|
|
|
&& interfaceConfig.MOBILE_APP_PROMO;
|
|
|
|
|
|
|
|
return (
|
|
|
|
typeof mobileAppPromo === 'undefined' || Boolean(mobileAppPromo)
|
|
|
|
? UnsupportedMobileBrowser
|
|
|
|
: NoMobileApp);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
state => {
|
|
|
|
const { webRTCReady } = state['features/base/lib-jitsi-meet'];
|
|
|
|
|
|
|
|
switch (typeof webRTCReady) {
|
|
|
|
case 'boolean':
|
|
|
|
if (webRTCReady === false) {
|
|
|
|
return UnsupportedDesktopBrowser;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'undefined':
|
|
|
|
// If webRTCReady is not set, then we cannot use it to take a
|
|
|
|
// decision.
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return PluginRequiredBrowser;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
];
|
2016-12-14 12:09:29 +00:00
|
|
|
|
2017-02-01 04:25:09 +00:00
|
|
|
export { _parseURIString } from './functions.native';
|
2016-12-14 12:09:29 +00:00
|
|
|
|
2016-12-27 16:03:30 +00:00
|
|
|
/**
|
|
|
|
* Determines which route is to be rendered in order to depict a specific Redux
|
|
|
|
* store.
|
|
|
|
*
|
|
|
|
* @param {(Object|Function)} stateOrGetState - Redux state or Regux getState()
|
|
|
|
* method.
|
|
|
|
* @returns {Route}
|
|
|
|
*/
|
2017-04-14 16:48:40 +00:00
|
|
|
export function _getRouteToRender(stateOrGetState: Object | Function) {
|
2016-12-27 16:03:30 +00:00
|
|
|
const state
|
|
|
|
= typeof stateOrGetState === 'function'
|
|
|
|
? stateOrGetState()
|
|
|
|
: stateOrGetState;
|
|
|
|
|
2017-01-19 15:47:22 +00:00
|
|
|
// If mobile browser page was shown, there is no need to show it again.
|
2017-01-18 12:21:30 +00:00
|
|
|
const { room } = state['features/base/conference'];
|
|
|
|
const component = isRoomValid(room) ? Conference : WelcomePage;
|
2017-01-19 15:47:22 +00:00
|
|
|
const route = RouteRegistry.getRouteByComponent(component);
|
2016-12-27 16:03:30 +00:00
|
|
|
|
2017-01-20 14:20:20 +00:00
|
|
|
// Intercepts route components if any of component interceptor rules
|
|
|
|
// is satisfied.
|
2017-04-14 16:48:40 +00:00
|
|
|
route.component = _interceptComponent(state, component);
|
2016-12-27 16:03:30 +00:00
|
|
|
|
2017-01-18 12:21:30 +00:00
|
|
|
return route;
|
|
|
|
}
|
|
|
|
|
2016-12-14 12:09:29 +00:00
|
|
|
/**
|
2017-01-10 21:55:31 +00:00
|
|
|
* Temporary solution. Later we'll get rid of global APP and set its properties
|
|
|
|
* in redux store.
|
2016-12-14 12:09:29 +00:00
|
|
|
*
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
|
|
|
export function init() {
|
2017-01-10 21:55:31 +00:00
|
|
|
URLProcessor.setConfigParametersFromUrl();
|
2016-12-14 12:09:29 +00:00
|
|
|
_initLogging();
|
|
|
|
|
|
|
|
APP.keyboardshortcut = KeyboardShortcut;
|
|
|
|
APP.tokenData = getTokenData();
|
2017-01-18 00:16:18 +00:00
|
|
|
|
|
|
|
// Force enable the API if jwt token is passed because most probably
|
|
|
|
// jitsi meet is displayed inside of wrapper that will need to communicate
|
|
|
|
// with jitsi meet.
|
|
|
|
APP.API.init(APP.tokenData.jwt ? { forceEnable: true } : undefined);
|
2016-12-14 12:09:29 +00:00
|
|
|
|
2017-03-01 04:53:45 +00:00
|
|
|
APP.translation.init();
|
2016-12-14 12:09:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adjusts the logging levels.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2017-01-10 21:55:31 +00:00
|
|
|
function _configureLoggingLevels() {
|
|
|
|
// NOTE The library Logger is separated from the app loggers, so the levels
|
2016-12-14 12:09:29 +00:00
|
|
|
// have to be set in two places
|
|
|
|
|
|
|
|
// Set default logging level
|
|
|
|
const defaultLogLevel
|
|
|
|
= loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
|
|
|
|
|
|
|
|
Logger.setLogLevel(defaultLogLevel);
|
|
|
|
JitsiMeetJS.setLogLevel(defaultLogLevel);
|
|
|
|
|
2017-01-10 21:55:31 +00:00
|
|
|
// NOTE console was used on purpose here to go around the logging and always
|
|
|
|
// print the default logging level to the console
|
2016-12-14 12:09:29 +00:00
|
|
|
console.info(`Default logging level set to: ${defaultLogLevel}`);
|
|
|
|
|
|
|
|
// Set log level for each logger
|
|
|
|
if (loggingConfig) {
|
|
|
|
Object.keys(loggingConfig).forEach(loggerName => {
|
|
|
|
if (loggerName !== 'defaultLogLevel') {
|
|
|
|
const level = loggingConfig[loggerName];
|
|
|
|
|
|
|
|
Logger.setLogLevelById(level, loggerName);
|
|
|
|
JitsiMeetJS.setLogLevelById(level, loggerName);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-10 21:55:31 +00:00
|
|
|
* Initializes logging in the app.
|
2016-12-14 12:09:29 +00:00
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2017-01-10 21:55:31 +00:00
|
|
|
function _initLogging() {
|
|
|
|
// Adjust logging level
|
|
|
|
_configureLoggingLevels();
|
|
|
|
|
|
|
|
// Create the LogCollector and register it as the global log transport. It
|
|
|
|
// is done early to capture as much logs as possible. Captured logs will be
|
|
|
|
// cached, before the JitsiMeetLogStorage gets ready (statistics module is
|
|
|
|
// initialized).
|
|
|
|
if (!APP.logCollector && !loggingConfig.disableLogCollector) {
|
|
|
|
APP.logCollector = new Logger.LogCollector(new JitsiMeetLogStorage());
|
|
|
|
Logger.addGlobalTransport(APP.logCollector);
|
|
|
|
JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
|
|
|
|
}
|
2016-12-14 12:09:29 +00:00
|
|
|
}
|
2017-04-14 16:48:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Intercepts route components based on a {@link _INTERCEPT_COMPONENT_RULES}.
|
|
|
|
*
|
|
|
|
* @param {Object|Function} stateOrGetState - Either Redux state object or
|
|
|
|
* getState() function.
|
|
|
|
* @param {ReactElement} component - Current route component to render.
|
|
|
|
* @private
|
|
|
|
* @returns {ReactElement} If any of the pre-defined rules is satisfied, returns
|
|
|
|
* intercepted component.
|
|
|
|
*/
|
|
|
|
function _interceptComponent(
|
|
|
|
stateOrGetState: Object,
|
|
|
|
component: ReactElement<*>) {
|
|
|
|
let result;
|
|
|
|
const state
|
|
|
|
= typeof stateOrGetState === 'function'
|
|
|
|
? stateOrGetState()
|
|
|
|
: stateOrGetState;
|
|
|
|
|
|
|
|
for (const rule of _INTERCEPT_COMPONENT_RULES) {
|
|
|
|
result = rule(state);
|
|
|
|
if (result) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result || component;
|
|
|
|
}
|