[RN] Don't override config values
This commit is contained in:
parent
b0ffe2e63f
commit
96e0c56bde
|
@ -19,7 +19,6 @@ import analytics from './modules/analytics/analytics';
|
||||||
|
|
||||||
import EventEmitter from "events";
|
import EventEmitter from "events";
|
||||||
|
|
||||||
import { getLocationContextRoot } from './react/features/app';
|
|
||||||
import {
|
import {
|
||||||
AVATAR_ID_COMMAND,
|
AVATAR_ID_COMMAND,
|
||||||
AVATAR_URL_COMMAND,
|
AVATAR_URL_COMMAND,
|
||||||
|
@ -50,6 +49,7 @@ import {
|
||||||
trackAdded,
|
trackAdded,
|
||||||
trackRemoved
|
trackRemoved
|
||||||
} from './react/features/base/tracks';
|
} from './react/features/base/tracks';
|
||||||
|
import { getLocationContextRoot } from './react/features/base/util';
|
||||||
import { statsEmitter } from './react/features/connection-indicator';
|
import { statsEmitter } from './react/features/connection-indicator';
|
||||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||||
import {
|
import {
|
||||||
|
|
|
@ -2,9 +2,9 @@ import { setRoom } from '../base/conference';
|
||||||
import { setLocationURL } from '../base/connection';
|
import { setLocationURL } from '../base/connection';
|
||||||
import { setConfig } from '../base/config';
|
import { setConfig } from '../base/config';
|
||||||
import { loadConfig } from '../base/lib-jitsi-meet';
|
import { loadConfig } from '../base/lib-jitsi-meet';
|
||||||
|
import { parseURIString } from '../base/util';
|
||||||
|
|
||||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
||||||
import { _parseURIString } from './functions';
|
|
||||||
|
|
||||||
declare var APP: Object;
|
declare var APP: Object;
|
||||||
|
|
||||||
|
@ -19,9 +19,7 @@ declare var APP: Object;
|
||||||
*/
|
*/
|
||||||
export function appNavigate(uri: ?string) {
|
export function appNavigate(uri: ?string) {
|
||||||
return (dispatch: Dispatch<*>, getState: Function) =>
|
return (dispatch: Dispatch<*>, getState: Function) =>
|
||||||
_appNavigateToOptionalLocation(
|
_appNavigateToOptionalLocation(dispatch, getState, parseURIString(uri));
|
||||||
dispatch, getState,
|
|
||||||
_parseURIString(uri));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,7 +131,7 @@ function _appNavigateToOptionalLocation(
|
||||||
// default.
|
// default.
|
||||||
if (!location || !location.host) {
|
if (!location || !location.host) {
|
||||||
const defaultLocation
|
const defaultLocation
|
||||||
= _parseURIString(getState()['features/app'].app._getDefaultURL());
|
= parseURIString(getState()['features/app'].app._getDefaultURL());
|
||||||
|
|
||||||
if (location) {
|
if (location) {
|
||||||
location.host = defaultLocation.host;
|
location.host = defaultLocation.host;
|
||||||
|
@ -211,9 +209,7 @@ function _loadConfig(location: Object) {
|
||||||
|
|
||||||
// The React Native app supports an app-specific scheme which is sure to not
|
// The React Native app supports an app-specific scheme which is sure to not
|
||||||
// be supported by fetch (or whatever loadConfig utilizes).
|
// be supported by fetch (or whatever loadConfig utilizes).
|
||||||
if (protocol !== 'http:' && protocol !== 'https:') {
|
protocol !== 'http:' && protocol !== 'https:' && (protocol = 'https:');
|
||||||
protocol = 'https:';
|
|
||||||
}
|
|
||||||
|
|
||||||
// TDOO userinfo
|
// TDOO userinfo
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { AbstractApp } from './AbstractApp';
|
import { getLocationContextRoot } from '../../base/util';
|
||||||
import { getLocationContextRoot } from '../functions';
|
|
||||||
|
|
||||||
import '../../room-lock';
|
import '../../room-lock';
|
||||||
|
|
||||||
|
import { AbstractApp } from './AbstractApp';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Root application component.
|
* Root application component.
|
||||||
*
|
*
|
||||||
|
|
|
@ -3,132 +3,6 @@ import { RouteRegistry } from '../base/react';
|
||||||
import { Conference } from '../conference';
|
import { Conference } from '../conference';
|
||||||
import { WelcomePage } from '../welcome';
|
import { WelcomePage } from '../welcome';
|
||||||
|
|
||||||
/**
|
|
||||||
* The RegExp pattern of the authority of a URI.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const _URI_AUTHORITY_PATTERN = '(//[^/?#]+)';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The RegExp pattern of the path of a URI.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const _URI_PATH_PATTERN = '([^?#]*)';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The RegExp patther of the protocol of a URI.
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
const _URI_PROTOCOL_PATTERN = '([a-z][a-z0-9\\.\\+-]*:)';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fixes the hier-part of a specific URI (string) so that the URI is well-known.
|
|
||||||
* For example, certain Jitsi Meet deployments are not conventional but it is
|
|
||||||
* possible to translate their URLs into conventional.
|
|
||||||
*
|
|
||||||
* @param {string} uri - The URI (string) to fix the hier-part of.
|
|
||||||
* @private
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function _fixURIStringHierPart(uri) {
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
// hipchat.com
|
|
||||||
let regex
|
|
||||||
= new RegExp(
|
|
||||||
`^${_URI_PROTOCOL_PATTERN}//hipchat\\.com/video/call/`,
|
|
||||||
'gi');
|
|
||||||
let match = regex.exec(uri);
|
|
||||||
|
|
||||||
if (!match) {
|
|
||||||
// enso.me
|
|
||||||
regex
|
|
||||||
= new RegExp(
|
|
||||||
`^${_URI_PROTOCOL_PATTERN}//enso\\.me/(?:call|meeting)/`,
|
|
||||||
'gi');
|
|
||||||
match = regex.exec(uri);
|
|
||||||
}
|
|
||||||
if (match) {
|
|
||||||
/* eslint-disable no-param-reassign, prefer-template */
|
|
||||||
|
|
||||||
uri
|
|
||||||
= match[1] /* protocol */
|
|
||||||
+ '//enso.hipchat.me/'
|
|
||||||
+ uri.substring(regex.lastIndex); /* room (name) */
|
|
||||||
|
|
||||||
/* eslint-enable no-param-reassign, prefer-template */
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fixes the scheme part of a specific URI (string) so that it contains a
|
|
||||||
* well-known scheme such as HTTP(S). For example, the mobile app implements an
|
|
||||||
* app-specific URI scheme in addition to Universal Links. The app-specific
|
|
||||||
* scheme may precede or replace the well-known scheme. In such a case, dealing
|
|
||||||
* with the app-specific scheme only complicates the logic and it is simpler to
|
|
||||||
* get rid of it (by translating the app-specific scheme into a well-known
|
|
||||||
* scheme).
|
|
||||||
*
|
|
||||||
* @param {string} uri - The URI (string) to fix the scheme of.
|
|
||||||
* @private
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
function _fixURIStringScheme(uri) {
|
|
||||||
const regex = new RegExp(`^${_URI_PROTOCOL_PATTERN}+`, 'gi');
|
|
||||||
const match = regex.exec(uri);
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
// As an implementation convenience, pick up the last scheme and make
|
|
||||||
// sure that it is a well-known one.
|
|
||||||
let protocol = match[match.length - 1].toLowerCase();
|
|
||||||
|
|
||||||
if (protocol !== 'http:' && protocol !== 'https:') {
|
|
||||||
protocol = 'https:';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
|
|
||||||
uri = uri.substring(regex.lastIndex);
|
|
||||||
if (uri.startsWith('//')) {
|
|
||||||
// The specified URL was not a room name only, it contained an
|
|
||||||
// authority.
|
|
||||||
uri = protocol + uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-enable no-param-reassign */
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the (Web application) context root defined by a specific location (URI).
|
|
||||||
*
|
|
||||||
* @param {Object} location - The location (URI) which defines the (Web
|
|
||||||
* application) context root.
|
|
||||||
* @returns {string} - The (Web application) context root defined by the
|
|
||||||
* specified {@code location} (URI).
|
|
||||||
*/
|
|
||||||
export function getLocationContextRoot(location: Object) {
|
|
||||||
const pathname = location.pathname;
|
|
||||||
const contextRootEndIndex = pathname.lastIndexOf('/');
|
|
||||||
|
|
||||||
return (
|
|
||||||
contextRootEndIndex === -1
|
|
||||||
? '/'
|
|
||||||
: pathname.substring(0, contextRootEndIndex + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines which route is to be rendered in order to depict a specific Redux
|
* Determines which route is to be rendered in order to depict a specific Redux
|
||||||
* store.
|
* store.
|
||||||
|
@ -159,137 +33,3 @@ export function _getRouteToRender(stateOrGetState) {
|
||||||
|
|
||||||
return RouteRegistry.getRouteByComponent(component);
|
return RouteRegistry.getRouteByComponent(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a specific URI string into an object with the well-known properties of
|
|
||||||
* the {@link Location} and/or {@link URL} interfaces implemented by Web
|
|
||||||
* browsers. The parsing attempts to be in accord with IETF's RFC 3986.
|
|
||||||
*
|
|
||||||
* @param {string} str - The URI string to parse.
|
|
||||||
* @returns {{
|
|
||||||
* hash: string,
|
|
||||||
* host: (string|undefined),
|
|
||||||
* hostname: (string|undefined),
|
|
||||||
* pathname: string,
|
|
||||||
* port: (string|undefined),
|
|
||||||
* protocol: (string|undefined),
|
|
||||||
* search: string
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
function _parseStandardURIString(str: string) {
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
|
|
||||||
const obj = {};
|
|
||||||
|
|
||||||
let regex;
|
|
||||||
let match;
|
|
||||||
|
|
||||||
// protocol
|
|
||||||
regex = new RegExp(`^${_URI_PROTOCOL_PATTERN}`, 'gi');
|
|
||||||
match = regex.exec(str);
|
|
||||||
if (match) {
|
|
||||||
obj.protocol = match[1].toLowerCase();
|
|
||||||
str = str.substring(regex.lastIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// authority
|
|
||||||
regex = new RegExp(`^${_URI_AUTHORITY_PATTERN}`, 'gi');
|
|
||||||
match = regex.exec(str);
|
|
||||||
if (match) {
|
|
||||||
let authority = match[1].substring(/* // */ 2);
|
|
||||||
|
|
||||||
str = str.substring(regex.lastIndex);
|
|
||||||
|
|
||||||
// userinfo
|
|
||||||
const userinfoEndIndex = authority.indexOf('@');
|
|
||||||
|
|
||||||
if (userinfoEndIndex !== -1) {
|
|
||||||
authority = authority.substring(userinfoEndIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.host = authority;
|
|
||||||
|
|
||||||
// port
|
|
||||||
const portBeginIndex = authority.lastIndexOf(':');
|
|
||||||
|
|
||||||
if (portBeginIndex !== -1) {
|
|
||||||
obj.port = authority.substring(portBeginIndex + 1);
|
|
||||||
authority = authority.substring(0, portBeginIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// hostname
|
|
||||||
obj.hostname = authority;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathname
|
|
||||||
regex = new RegExp(`^${_URI_PATH_PATTERN}`, 'gi');
|
|
||||||
match = regex.exec(str);
|
|
||||||
|
|
||||||
let pathname;
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
pathname = match[1];
|
|
||||||
str = str.substring(regex.lastIndex);
|
|
||||||
}
|
|
||||||
if (pathname) {
|
|
||||||
if (!pathname.startsWith('/')) {
|
|
||||||
pathname = `/${pathname}`;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pathname = '/';
|
|
||||||
}
|
|
||||||
obj.pathname = pathname;
|
|
||||||
|
|
||||||
// query
|
|
||||||
if (str.startsWith('?')) {
|
|
||||||
let hashBeginIndex = str.indexOf('#', 1);
|
|
||||||
|
|
||||||
if (hashBeginIndex === -1) {
|
|
||||||
hashBeginIndex = str.length;
|
|
||||||
}
|
|
||||||
obj.search = str.substring(0, hashBeginIndex);
|
|
||||||
str = str.substring(hashBeginIndex);
|
|
||||||
} else {
|
|
||||||
obj.search = ''; // Google Chrome
|
|
||||||
}
|
|
||||||
|
|
||||||
// fragment
|
|
||||||
obj.hash = str.startsWith('#') ? str : '';
|
|
||||||
|
|
||||||
/* eslint-enable no-param-reassign */
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a specific URI which (supposedly) references a Jitsi Meet resource
|
|
||||||
* (location).
|
|
||||||
*
|
|
||||||
* @param {(string|undefined)} uri - The URI to parse which (supposedly)
|
|
||||||
* references a Jitsi Meet resource (location).
|
|
||||||
* @returns {{
|
|
||||||
* room: (string|undefined)
|
|
||||||
* }}
|
|
||||||
*/
|
|
||||||
export function _parseURIString(uri: ?string) {
|
|
||||||
if (typeof uri !== 'string') {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const obj
|
|
||||||
= _parseStandardURIString(
|
|
||||||
_fixURIStringHierPart(_fixURIStringScheme(uri)));
|
|
||||||
|
|
||||||
// Add the properties that are specific to a Jitsi Meet resource (location)
|
|
||||||
// such as contextRoot, room:
|
|
||||||
|
|
||||||
// contextRoot
|
|
||||||
obj.contextRoot = getLocationContextRoot(obj);
|
|
||||||
|
|
||||||
// The room (name) is the last component of pathname.
|
|
||||||
const { pathname } = obj;
|
|
||||||
|
|
||||||
obj.room = pathname.substring(pathname.lastIndexOf('/') + 1) || undefined;
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
|
@ -71,8 +71,6 @@ const _INTERCEPT_COMPONENT_RULES = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
export { getLocationContextRoot, _parseURIString } from './functions.native';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines which route is to be rendered in order to depict a specific Redux
|
* Determines which route is to be rendered in order to depict a specific Redux
|
||||||
* store.
|
* store.
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { conferenceWillLeave } from '../conference';
|
import { conferenceWillLeave } from '../conference';
|
||||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||||
|
import { parseStandardURIString } from '../util';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CONNECTION_DISCONNECTED,
|
CONNECTION_DISCONNECTED,
|
||||||
|
@ -21,29 +23,8 @@ import {
|
||||||
export function connect() {
|
export function connect() {
|
||||||
return (dispatch: Dispatch<*>, getState: Function) => {
|
return (dispatch: Dispatch<*>, getState: Function) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
let { options } = state['features/base/connection'];
|
const options = _constructOptions(state);
|
||||||
|
|
||||||
options = {
|
|
||||||
// Lib-jitsi-meet wants the config passed in multiple places and
|
|
||||||
// here is the latest one I have discovered.
|
|
||||||
...state['features/base/config'],
|
|
||||||
|
|
||||||
// TODO It is probable that config should override the options that
|
|
||||||
// have been automatically constructed by the app. Unfortunately,
|
|
||||||
// config may specify URLs such as bosh at the time of this writing
|
|
||||||
// which react-native cannot parse (because they do not have a
|
|
||||||
// protocol/scheme).
|
|
||||||
...options
|
|
||||||
};
|
|
||||||
|
|
||||||
const { issuer, jwt } = state['features/jwt'];
|
const { issuer, jwt } = state['features/jwt'];
|
||||||
const { room } = state['features/base/conference'];
|
|
||||||
|
|
||||||
// XXX The Jitsi Meet deployments require the room argument to be in
|
|
||||||
// lower case at the time of this writing but, unfortunately, they do
|
|
||||||
// not ignore case themselves.
|
|
||||||
options.bosh += room ? `?room=${room.toLowerCase()}` : '';
|
|
||||||
|
|
||||||
const connection
|
const connection
|
||||||
= new JitsiMeetJS.JitsiConnection(
|
= new JitsiMeetJS.JitsiConnection(
|
||||||
options.appId,
|
options.appId,
|
||||||
|
@ -202,6 +183,51 @@ export function connectionFailed(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs options to be passed to the constructor of {@code JitsiConnection}
|
||||||
|
* based on the redux state.
|
||||||
|
*
|
||||||
|
* @param {Object} state - The redux state.
|
||||||
|
* @returns {Object} The options to be passed to the constructor of
|
||||||
|
* {@code JitsiConnection}.
|
||||||
|
*/
|
||||||
|
function _constructOptions(state) {
|
||||||
|
const defaultOptions = state['features/base/connection'].options;
|
||||||
|
const options = _.merge(
|
||||||
|
{},
|
||||||
|
defaultOptions,
|
||||||
|
|
||||||
|
// Lib-jitsi-meet wants the config passed in multiple places and here is
|
||||||
|
// the latest one I have discovered.
|
||||||
|
state['features/base/config'],
|
||||||
|
);
|
||||||
|
let { bosh } = options;
|
||||||
|
|
||||||
|
if (bosh) {
|
||||||
|
// Append room to the URL's search.
|
||||||
|
const { room } = state['features/base/conference'];
|
||||||
|
|
||||||
|
// XXX The Jitsi Meet deployments require the room argument to be in
|
||||||
|
// lower case at the time of this writing but, unfortunately, they do
|
||||||
|
// not ignore case themselves.
|
||||||
|
room && (bosh += `?room=${room.toLowerCase()}`);
|
||||||
|
|
||||||
|
// XXX By default, config.js does not add a protocol to the BOSH URL.
|
||||||
|
// Which trips React Native. Make sure there is a protocol in order to
|
||||||
|
// satisfy React Native.
|
||||||
|
if (bosh !== defaultOptions.bosh
|
||||||
|
&& !parseStandardURIString(bosh).protocol) {
|
||||||
|
const { protocol } = parseStandardURIString(defaultOptions.bosh);
|
||||||
|
|
||||||
|
protocol && (bosh = protocol + bosh);
|
||||||
|
}
|
||||||
|
|
||||||
|
options.bosh = bosh;
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes connection.
|
* Closes connection.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
import { assign, ReducerRegistry, set } from '../redux';
|
import { assign, ReducerRegistry, set } from '../redux';
|
||||||
|
import { parseURIString } from '../util';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CONNECTION_DISCONNECTED,
|
CONNECTION_DISCONNECTED,
|
||||||
|
@ -119,38 +120,38 @@ function _connectionWillConnect(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs options to be passed to the constructor of {@code JitsiConnection}
|
* Constructs options to be passed to the constructor of {@code JitsiConnection}
|
||||||
* based on a specific domain.
|
* based on a specific location URL.
|
||||||
*
|
*
|
||||||
* @param {string} domain - The domain with which the returned options are to be
|
* @param {string} locationURL - The location URL with which the returned
|
||||||
* populated.
|
* options are to be constructed.
|
||||||
* @private
|
* @private
|
||||||
* @returns {Object}
|
* @returns {Object} The options to be passed to the constructor of
|
||||||
|
* {@code JitsiConnection} based on the location URL.
|
||||||
*/
|
*/
|
||||||
function _constructOptions(domain: string) {
|
function _constructOptions(locationURL: URL) {
|
||||||
|
const locationURI = parseURIString(locationURL.href);
|
||||||
|
|
||||||
// FIXME The HTTPS scheme for the BOSH URL works with meet.jit.si on both
|
// FIXME The HTTPS scheme for the BOSH URL works with meet.jit.si on both
|
||||||
// mobile & Web. It also works with beta.meet.jit.si on Web. Unfortunately,
|
// mobile & Web. It also works with beta.meet.jit.si on Web. Unfortunately,
|
||||||
// it doesn't work with beta.meet.jit.si on mobile. Temporarily, use the
|
// it doesn't work with beta.meet.jit.si on mobile. Temporarily, use the
|
||||||
// HTTP scheme for the BOSH URL with beta.meet.jit.si on mobile.
|
// HTTP scheme for the BOSH URL with beta.meet.jit.si on mobile.
|
||||||
let boshProtocol;
|
let { protocol } = locationURI;
|
||||||
|
const domain = locationURI.hostname;
|
||||||
|
|
||||||
if (domain === 'beta.meet.jit.si') {
|
if (!protocol && domain === 'beta.meet.jit.si') {
|
||||||
if (typeof window === 'object') {
|
const windowLocation = window.location;
|
||||||
const windowLocation = window.location;
|
|
||||||
|
|
||||||
if (windowLocation) {
|
windowLocation && (protocol = windowLocation.protocol);
|
||||||
// React Native doesn't have a window.location at the time of
|
protocol || (protocol = 'http:');
|
||||||
// this writing, let alone a window.location.protocol.
|
|
||||||
boshProtocol = windowLocation.protocol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boshProtocol || (boshProtocol = 'http:');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default to the HTTPS scheme for the BOSH URL.
|
// Default to the HTTPS scheme for the BOSH URL.
|
||||||
boshProtocol || (boshProtocol = 'https:');
|
protocol || (protocol = 'https:');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bosh: `${String(boshProtocol)}//${domain}/http-bind`,
|
bosh:
|
||||||
|
`${String(protocol)}//${domain}${locationURI.contextRoot || '/'
|
||||||
|
}http-bind`,
|
||||||
hosts: {
|
hosts: {
|
||||||
domain,
|
domain,
|
||||||
|
|
||||||
|
@ -176,6 +177,6 @@ function _setLocationURL(
|
||||||
{ locationURL }: { locationURL: ?URL }) {
|
{ locationURL }: { locationURL: ?URL }) {
|
||||||
return assign(state, {
|
return assign(state, {
|
||||||
locationURL,
|
locationURL,
|
||||||
options: locationURL ? _constructOptions(locationURL.host) : undefined
|
options: locationURL ? _constructOptions(locationURL) : undefined
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export * from './loadScript';
|
export * from './loadScript';
|
||||||
export * from './randomUtil';
|
export * from './randomUtil';
|
||||||
|
export * from './uri';
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
/* @flow */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RegExp} pattern of the authority of a URI.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
const _URI_AUTHORITY_PATTERN = '(//[^/?#]+)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RegExp} pattern of the path of a URI.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
const _URI_PATH_PATTERN = '([^?#]*)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link RegExp} pattern of the protocol of a URI.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
const _URI_PROTOCOL_PATTERN = '([a-z][a-z0-9\\.\\+-]*:)';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes the hier-part of a specific URI (string) so that the URI is well-known.
|
||||||
|
* For example, certain Jitsi Meet deployments are not conventional but it is
|
||||||
|
* possible to translate their URLs into conventional.
|
||||||
|
*
|
||||||
|
* @param {string} uri - The URI (string) to fix the hier-part of.
|
||||||
|
* @private
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function _fixURIStringHierPart(uri) {
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// hipchat.com
|
||||||
|
let regex
|
||||||
|
= new RegExp(
|
||||||
|
`^${_URI_PROTOCOL_PATTERN}//hipchat\\.com/video/call/`,
|
||||||
|
'gi');
|
||||||
|
let match = regex.exec(uri);
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
// enso.me
|
||||||
|
regex
|
||||||
|
= new RegExp(
|
||||||
|
`^${_URI_PROTOCOL_PATTERN}//enso\\.me/(?:call|meeting)/`,
|
||||||
|
'gi');
|
||||||
|
match = regex.exec(uri);
|
||||||
|
}
|
||||||
|
if (match) {
|
||||||
|
/* eslint-disable no-param-reassign, prefer-template */
|
||||||
|
|
||||||
|
uri
|
||||||
|
= match[1] /* protocol */
|
||||||
|
+ '//enso.hipchat.me/'
|
||||||
|
+ uri.substring(regex.lastIndex); /* room (name) */
|
||||||
|
|
||||||
|
/* eslint-enable no-param-reassign, prefer-template */
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes the scheme part of a specific URI (string) so that it contains a
|
||||||
|
* well-known scheme such as HTTP(S). For example, the mobile app implements an
|
||||||
|
* app-specific URI scheme in addition to Universal Links. The app-specific
|
||||||
|
* scheme may precede or replace the well-known scheme. In such a case, dealing
|
||||||
|
* with the app-specific scheme only complicates the logic and it is simpler to
|
||||||
|
* get rid of it (by translating the app-specific scheme into a well-known
|
||||||
|
* scheme).
|
||||||
|
*
|
||||||
|
* @param {string} uri - The URI (string) to fix the scheme of.
|
||||||
|
* @private
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function _fixURIStringScheme(uri: string) {
|
||||||
|
const regex = new RegExp(`^${_URI_PROTOCOL_PATTERN}+`, 'gi');
|
||||||
|
const match = regex.exec(uri);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
// As an implementation convenience, pick up the last scheme and make
|
||||||
|
// sure that it is a well-known one.
|
||||||
|
let protocol = match[match.length - 1].toLowerCase();
|
||||||
|
|
||||||
|
if (protocol !== 'http:' && protocol !== 'https:') {
|
||||||
|
protocol = 'https:';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
|
||||||
|
uri = uri.substring(regex.lastIndex);
|
||||||
|
if (uri.startsWith('//')) {
|
||||||
|
// The specified URL was not a room name only, it contained an
|
||||||
|
// authority.
|
||||||
|
uri = protocol + uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-enable no-param-reassign */
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the (Web application) context root defined by a specific location (URI).
|
||||||
|
*
|
||||||
|
* @param {Object} location - The location (URI) which defines the (Web
|
||||||
|
* application) context root.
|
||||||
|
* @public
|
||||||
|
* @returns {string} - The (Web application) context root defined by the
|
||||||
|
* specified {@code location} (URI).
|
||||||
|
*/
|
||||||
|
export function getLocationContextRoot(location: Object) {
|
||||||
|
const pathname = location.pathname;
|
||||||
|
const contextRootEndIndex = pathname.lastIndexOf('/');
|
||||||
|
|
||||||
|
return (
|
||||||
|
contextRootEndIndex === -1
|
||||||
|
? '/'
|
||||||
|
: pathname.substring(0, contextRootEndIndex + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a specific URI string into an object with the well-known properties of
|
||||||
|
* the {@link Location} and/or {@link URL} interfaces implemented by Web
|
||||||
|
* browsers. The parsing attempts to be in accord with IETF's RFC 3986.
|
||||||
|
*
|
||||||
|
* @param {string} str - The URI string to parse.
|
||||||
|
* @public
|
||||||
|
* @returns {{
|
||||||
|
* hash: string,
|
||||||
|
* host: (string|undefined),
|
||||||
|
* hostname: (string|undefined),
|
||||||
|
* pathname: string,
|
||||||
|
* port: (string|undefined),
|
||||||
|
* protocol: (string|undefined),
|
||||||
|
* search: string
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function parseStandardURIString(str: string) {
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
|
||||||
|
const obj = {};
|
||||||
|
|
||||||
|
let regex;
|
||||||
|
let match;
|
||||||
|
|
||||||
|
// protocol
|
||||||
|
regex = new RegExp(`^${_URI_PROTOCOL_PATTERN}`, 'gi');
|
||||||
|
match = regex.exec(str);
|
||||||
|
if (match) {
|
||||||
|
obj.protocol = match[1].toLowerCase();
|
||||||
|
str = str.substring(regex.lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// authority
|
||||||
|
regex = new RegExp(`^${_URI_AUTHORITY_PATTERN}`, 'gi');
|
||||||
|
match = regex.exec(str);
|
||||||
|
if (match) {
|
||||||
|
let authority = match[1].substring(/* // */ 2);
|
||||||
|
|
||||||
|
str = str.substring(regex.lastIndex);
|
||||||
|
|
||||||
|
// userinfo
|
||||||
|
const userinfoEndIndex = authority.indexOf('@');
|
||||||
|
|
||||||
|
if (userinfoEndIndex !== -1) {
|
||||||
|
authority = authority.substring(userinfoEndIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.host = authority;
|
||||||
|
|
||||||
|
// port
|
||||||
|
const portBeginIndex = authority.lastIndexOf(':');
|
||||||
|
|
||||||
|
if (portBeginIndex !== -1) {
|
||||||
|
obj.port = authority.substring(portBeginIndex + 1);
|
||||||
|
authority = authority.substring(0, portBeginIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// hostname
|
||||||
|
obj.hostname = authority;
|
||||||
|
}
|
||||||
|
|
||||||
|
// pathname
|
||||||
|
regex = new RegExp(`^${_URI_PATH_PATTERN}`, 'gi');
|
||||||
|
match = regex.exec(str);
|
||||||
|
|
||||||
|
let pathname;
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
pathname = match[1];
|
||||||
|
str = str.substring(regex.lastIndex);
|
||||||
|
}
|
||||||
|
if (pathname) {
|
||||||
|
if (!pathname.startsWith('/')) {
|
||||||
|
pathname = `/${pathname}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pathname = '/';
|
||||||
|
}
|
||||||
|
obj.pathname = pathname;
|
||||||
|
|
||||||
|
// query
|
||||||
|
if (str.startsWith('?')) {
|
||||||
|
let hashBeginIndex = str.indexOf('#', 1);
|
||||||
|
|
||||||
|
if (hashBeginIndex === -1) {
|
||||||
|
hashBeginIndex = str.length;
|
||||||
|
}
|
||||||
|
obj.search = str.substring(0, hashBeginIndex);
|
||||||
|
str = str.substring(hashBeginIndex);
|
||||||
|
} else {
|
||||||
|
obj.search = ''; // Google Chrome
|
||||||
|
}
|
||||||
|
|
||||||
|
// fragment
|
||||||
|
obj.hash = str.startsWith('#') ? str : '';
|
||||||
|
|
||||||
|
/* eslint-enable no-param-reassign */
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a specific URI which (supposedly) references a Jitsi Meet resource
|
||||||
|
* (location).
|
||||||
|
*
|
||||||
|
* @param {(string|undefined)} uri - The URI to parse which (supposedly)
|
||||||
|
* references a Jitsi Meet resource (location).
|
||||||
|
* @public
|
||||||
|
* @returns {{
|
||||||
|
* room: (string|undefined)
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
export function parseURIString(uri: ?string) {
|
||||||
|
if (typeof uri !== 'string') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const obj
|
||||||
|
= parseStandardURIString(
|
||||||
|
_fixURIStringHierPart(_fixURIStringScheme(uri)));
|
||||||
|
|
||||||
|
// Add the properties that are specific to a Jitsi Meet resource (location)
|
||||||
|
// such as contextRoot, room:
|
||||||
|
|
||||||
|
// contextRoot
|
||||||
|
obj.contextRoot = getLocationContextRoot(obj);
|
||||||
|
|
||||||
|
// The room (name) is the last component of pathname.
|
||||||
|
const { pathname } = obj;
|
||||||
|
|
||||||
|
obj.room = pathname.substring(pathname.lastIndexOf('/') + 1) || undefined;
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
Loading…
Reference in New Issue