Introduced new actions and functions for app initialization
This commit is contained in:
parent
e716c1738c
commit
f53fb3d814
|
@ -0,0 +1,173 @@
|
||||||
|
import { setRoom } from '../base/conference';
|
||||||
|
import {
|
||||||
|
getDomain,
|
||||||
|
setDomain
|
||||||
|
} from '../base/connection';
|
||||||
|
import {
|
||||||
|
loadConfig,
|
||||||
|
setConfig
|
||||||
|
} from '../base/lib-jitsi-meet';
|
||||||
|
|
||||||
|
import {
|
||||||
|
APP_WILL_MOUNT,
|
||||||
|
APP_WILL_UNMOUNT
|
||||||
|
} from './actionTypes';
|
||||||
|
import {
|
||||||
|
_getRoomAndDomainFromUrlString,
|
||||||
|
_getRouteToRender,
|
||||||
|
init
|
||||||
|
} from './functions';
|
||||||
|
import './reducer';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers an in-app navigation to a different route. Allows navigation to be
|
||||||
|
* abstracted between the mobile and web versions.
|
||||||
|
*
|
||||||
|
* @param {(string|undefined)} urlOrRoom - The URL or room name to which to
|
||||||
|
* navigate.
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function appNavigate(urlOrRoom) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const oldDomain = getDomain(getState());
|
||||||
|
|
||||||
|
const { domain, room } = _getRoomAndDomainFromUrlString(urlOrRoom);
|
||||||
|
|
||||||
|
// TODO Kostiantyn Tsaregradskyi: We should probably detect if user is
|
||||||
|
// currently in a conference and ask her if she wants to close the
|
||||||
|
// current conference and start a new one with the new room name or
|
||||||
|
// domain.
|
||||||
|
|
||||||
|
if (typeof domain === 'undefined' || oldDomain === domain) {
|
||||||
|
// If both domain and room vars became undefined, that means we're
|
||||||
|
// actually dealing with just room name and not with URL.
|
||||||
|
dispatch(
|
||||||
|
_setRoomAndNavigate(
|
||||||
|
typeof room === 'undefined' && typeof domain === 'undefined'
|
||||||
|
? urlOrRoom
|
||||||
|
: room));
|
||||||
|
} else if (oldDomain !== domain) {
|
||||||
|
// Update domain without waiting for config to be loaded to prevent
|
||||||
|
// race conditions when we will start to load config multiple times.
|
||||||
|
dispatch(setDomain(domain));
|
||||||
|
|
||||||
|
// If domain has changed, we need to load the config of the new
|
||||||
|
// domain and set it, and only after that we can navigate to
|
||||||
|
// different route.
|
||||||
|
loadConfig(`https://${domain}`)
|
||||||
|
.then(
|
||||||
|
config => configLoaded(/* err */ undefined, config),
|
||||||
|
err => configLoaded(err, /* config */ undefined));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies that an attempt to load the config(uration) of domain has
|
||||||
|
* completed.
|
||||||
|
*
|
||||||
|
* @param {string|undefined} err - If the loading has failed, the error
|
||||||
|
* detailing the cause of the failure.
|
||||||
|
* @param {Object|undefined} config - If the loading has succeeded, the
|
||||||
|
* loaded config(uration).
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function configLoaded(err, config) {
|
||||||
|
if (err) {
|
||||||
|
// XXX The failure could be, for example, because of a
|
||||||
|
// certificate-related error. In which case the connection will
|
||||||
|
// fail later in Strophe anyway even if we use the default
|
||||||
|
// config here.
|
||||||
|
|
||||||
|
// The function loadConfig will log the err.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We set room name only here to prevent race conditions on app
|
||||||
|
// start to not make app re-render conference page for two times.
|
||||||
|
dispatch(setRoom(room));
|
||||||
|
dispatch(setConfig(config));
|
||||||
|
_navigate(getState());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary solution. Should dispatch actions related to
|
||||||
|
* initial settings of the app like setting log levels,
|
||||||
|
* reading the config parameters from query string etc.
|
||||||
|
*
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
export function appInit() {
|
||||||
|
return () => {
|
||||||
|
init();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that a specific App will mount (in the terms of React).
|
||||||
|
*
|
||||||
|
* @param {App} app - The App which will mount.
|
||||||
|
* @returns {{
|
||||||
|
* type: APP_WILL_MOUNT,
|
||||||
|
* app: App
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function appWillMount(app) {
|
||||||
|
return {
|
||||||
|
type: APP_WILL_MOUNT,
|
||||||
|
app
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals that a specific App will unmount (in the terms of React).
|
||||||
|
*
|
||||||
|
* @param {App} app - The App which will unmount.
|
||||||
|
* @returns {{
|
||||||
|
* type: APP_WILL_UNMOUNT,
|
||||||
|
* app: App
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function appWillUnmount(app) {
|
||||||
|
return {
|
||||||
|
type: APP_WILL_UNMOUNT,
|
||||||
|
app
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigates to route corresponding to current room name.
|
||||||
|
*
|
||||||
|
* @param {Object} state - Redux state.
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function _navigate(state) {
|
||||||
|
const app = state['features/app'].app;
|
||||||
|
const routeToRender = _getRouteToRender(state);
|
||||||
|
|
||||||
|
app._navigate(routeToRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets room and navigates to new route if needed.
|
||||||
|
*
|
||||||
|
* @param {string} newRoom - New room name.
|
||||||
|
* @private
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
function _setRoomAndNavigate(newRoom) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const oldRoom = getState()['features/base/conference'].room;
|
||||||
|
|
||||||
|
dispatch(setRoom(newRoom));
|
||||||
|
|
||||||
|
const state = getState();
|
||||||
|
const room = state['features/base/conference'].room;
|
||||||
|
|
||||||
|
if (room !== oldRoom) {
|
||||||
|
_navigate(state);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
/* global APP, JitsiMeetJS, loggingConfig $ */
|
/* global $ */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { compose } from 'redux';
|
import { compose } from 'redux';
|
||||||
|
@ -13,18 +13,7 @@ import { getDomain } from '../../base/connection';
|
||||||
import { RouteRegistry } from '../../base/navigator';
|
import { RouteRegistry } from '../../base/navigator';
|
||||||
|
|
||||||
import { AbstractApp } from './AbstractApp';
|
import { AbstractApp } from './AbstractApp';
|
||||||
import settings from '../../../../modules/settings/Settings';
|
import { appInit } from '../actions';
|
||||||
|
|
||||||
|
|
||||||
import URLProcessor from '../../../../modules/config/URLProcessor';
|
|
||||||
import getTokenData from '../../../../modules/tokendata/TokenData';
|
|
||||||
import JitsiMeetLogStorage from '../../../../modules/util/JitsiMeetLogStorage';
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
import KeyboardShortcut from '../../../../modules/keyboardshortcut/keyboardshortcut';
|
|
||||||
|
|
||||||
const Logger = require('jitsi-meet-logger');
|
|
||||||
const LogCollector = Logger.LogCollector;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,78 +53,13 @@ export class App extends AbstractApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init translation from old app.
|
* Inits the app before component will mount.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
componentWillMount(...args) {
|
componentWillMount(...args) {
|
||||||
super.componentWillMount(...args);
|
super.componentWillMount(...args);
|
||||||
|
this.props.store.dispatch(appInit());
|
||||||
URLProcessor.setConfigParametersFromUrl();
|
|
||||||
|
|
||||||
/* APP.init BEGIN */
|
|
||||||
|
|
||||||
/* Init logging BEGIN */
|
|
||||||
|
|
||||||
// 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 LogCollector(new JitsiMeetLogStorage());
|
|
||||||
Logger.addGlobalTransport(APP.logCollector);
|
|
||||||
JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init logging BEGIN */
|
|
||||||
|
|
||||||
APP.keyboardshortcut = KeyboardShortcut;
|
|
||||||
APP.tokenData = getTokenData();
|
|
||||||
|
|
||||||
/* APP.init END */
|
|
||||||
|
|
||||||
APP.API.init(APP.tokenData.externalAPISettings);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adjusts the logging levels.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function configureLoggingLevels() {
|
|
||||||
// NOTE The library Logger is separated from
|
|
||||||
// the app loggers, so the levels
|
|
||||||
// have to be set in two places
|
|
||||||
|
|
||||||
// Set default logging level
|
|
||||||
const defaultLogLevel
|
|
||||||
= loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
|
|
||||||
|
|
||||||
Logger.setLogLevel(defaultLogLevel);
|
|
||||||
JitsiMeetJS.setLogLevel(defaultLogLevel);
|
|
||||||
|
|
||||||
// NOTE console was used on purpose here to go around the logging
|
|
||||||
// and always print the default logging level to the console
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
APP.translation.init(settings.getLanguage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
/* global APP, JitsiMeetJS, loggingConfig */
|
||||||
|
import { isRoomValid } from '../base/conference';
|
||||||
|
import { RouteRegistry } from '../base/navigator';
|
||||||
|
import { Conference } from '../conference';
|
||||||
|
import { WelcomePage } from '../welcome';
|
||||||
|
|
||||||
|
import getTokenData from '../../../modules/tokendata/TokenData';
|
||||||
|
import settings from '../../../modules/settings/Settings';
|
||||||
|
|
||||||
|
import URLProcessor from '../../../modules/config/URLProcessor';
|
||||||
|
import JitsiMeetLogStorage from '../../../modules/util/JitsiMeetLogStorage';
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-len
|
||||||
|
import KeyboardShortcut from '../../../modules/keyboardshortcut/keyboardshortcut';
|
||||||
|
|
||||||
|
const Logger = require('jitsi-meet-logger');
|
||||||
|
const LogCollector = Logger.LogCollector;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets room name and domain from URL object.
|
||||||
|
*
|
||||||
|
* @param {URL} url - URL object.
|
||||||
|
* @private
|
||||||
|
* @returns {{
|
||||||
|
* domain: (string|undefined),
|
||||||
|
* room: (string|undefined)
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
function _getRoomAndDomainFromUrlObject(url) {
|
||||||
|
let domain;
|
||||||
|
let room;
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
domain = url.hostname;
|
||||||
|
room = url.pathname.substr(1);
|
||||||
|
|
||||||
|
// Convert empty string to undefined to simplify checks.
|
||||||
|
if (room === '') {
|
||||||
|
room = undefined;
|
||||||
|
}
|
||||||
|
if (domain === '') {
|
||||||
|
domain = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
domain,
|
||||||
|
room
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets conference room name and connection domain from URL.
|
||||||
|
*
|
||||||
|
* @param {(string|undefined)} url - URL.
|
||||||
|
* @returns {{
|
||||||
|
* domain: (string|undefined),
|
||||||
|
* room: (string|undefined)
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function _getRoomAndDomainFromUrlString(url) {
|
||||||
|
// Rewrite the specified URL in order to handle special cases such as
|
||||||
|
// hipchat.com and enso.me which do not follow the common pattern of most
|
||||||
|
// Jitsi Meet deployments.
|
||||||
|
if (typeof url === 'string') {
|
||||||
|
// hipchat.com
|
||||||
|
let regex = /^(https?):\/\/hipchat.com\/video\/call\//gi;
|
||||||
|
let match = regex.exec(url);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
// enso.me
|
||||||
|
regex = /^(https?):\/\/enso\.me\/(?:call|meeting)\//gi;
|
||||||
|
match = regex.exec(url);
|
||||||
|
}
|
||||||
|
if (match && match.length > 1) {
|
||||||
|
/* eslint-disable no-param-reassign, prefer-template */
|
||||||
|
|
||||||
|
url
|
||||||
|
= match[1] /* URL protocol */
|
||||||
|
+ '://enso.hipchat.me/'
|
||||||
|
+ url.substring(regex.lastIndex);
|
||||||
|
|
||||||
|
/* eslint-enable no-param-reassign, prefer-template */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _getRoomAndDomainFromUrlObject(_urlStringToObject(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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}
|
||||||
|
*/
|
||||||
|
export function _getRouteToRender(stateOrGetState) {
|
||||||
|
const state
|
||||||
|
= typeof stateOrGetState === 'function'
|
||||||
|
? stateOrGetState()
|
||||||
|
: stateOrGetState;
|
||||||
|
const room = state['features/base/conference'].room;
|
||||||
|
const component = isRoomValid(room) ? Conference : WelcomePage;
|
||||||
|
|
||||||
|
return RouteRegistry.getRouteByComponent(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string into a URL (object).
|
||||||
|
*
|
||||||
|
* @param {(string|undefined)} url - The URL to parse.
|
||||||
|
* @private
|
||||||
|
* @returns {URL}
|
||||||
|
*/
|
||||||
|
function _urlStringToObject(url) {
|
||||||
|
let urlObj;
|
||||||
|
|
||||||
|
if (url) {
|
||||||
|
try {
|
||||||
|
urlObj = new URL(url);
|
||||||
|
} catch (ex) {
|
||||||
|
// The return value will signal the failure & the logged
|
||||||
|
// exception will provide the details to the developers.
|
||||||
|
console.log(`${url} seems to be not a valid URL, but it's OK`, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Temporary solution. Later we'll get rid of global APP
|
||||||
|
* and set its properties in redux store.
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
export function init() {
|
||||||
|
_setConfigParametersFromUrl();
|
||||||
|
_initLogging();
|
||||||
|
|
||||||
|
APP.keyboardshortcut = KeyboardShortcut;
|
||||||
|
APP.tokenData = getTokenData();
|
||||||
|
APP.API.init(APP.tokenData.externalAPISettings);
|
||||||
|
|
||||||
|
APP.translation.init(settings.getLanguage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes logging in the app.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
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 LogCollector(new JitsiMeetLogStorage());
|
||||||
|
Logger.addGlobalTransport(APP.logCollector);
|
||||||
|
JitsiMeetJS.addGlobalLogTransport(APP.logCollector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts the logging levels.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function configureLoggingLevels() {
|
||||||
|
// NOTE The library Logger is separated from
|
||||||
|
// the app loggers, so the levels
|
||||||
|
// have to be set in two places
|
||||||
|
|
||||||
|
// Set default logging level
|
||||||
|
const defaultLogLevel
|
||||||
|
= loggingConfig.defaultLogLevel || JitsiMeetJS.logLevels.TRACE;
|
||||||
|
|
||||||
|
Logger.setLogLevel(defaultLogLevel);
|
||||||
|
JitsiMeetJS.setLogLevel(defaultLogLevel);
|
||||||
|
|
||||||
|
// NOTE console was used on purpose here to go around the logging
|
||||||
|
// and always print the default logging level to the console
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets config parameters from query string.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function _setConfigParametersFromUrl() {
|
||||||
|
URLProcessor.setConfigParametersFromUrl();
|
||||||
|
}
|
Loading…
Reference in New Issue