[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 { getLocationContextRoot } from './react/features/app';
|
||||
import {
|
||||
AVATAR_ID_COMMAND,
|
||||
AVATAR_URL_COMMAND,
|
||||
|
@ -50,6 +49,7 @@ import {
|
|||
trackAdded,
|
||||
trackRemoved
|
||||
} from './react/features/base/tracks';
|
||||
import { getLocationContextRoot } from './react/features/base/util';
|
||||
import { statsEmitter } from './react/features/connection-indicator';
|
||||
import { showDesktopPicker } from './react/features/desktop-picker';
|
||||
import {
|
||||
|
|
|
@ -2,9 +2,9 @@ import { setRoom } from '../base/conference';
|
|||
import { setLocationURL } from '../base/connection';
|
||||
import { setConfig } from '../base/config';
|
||||
import { loadConfig } from '../base/lib-jitsi-meet';
|
||||
import { parseURIString } from '../base/util';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from './actionTypes';
|
||||
import { _parseURIString } from './functions';
|
||||
|
||||
declare var APP: Object;
|
||||
|
||||
|
@ -19,9 +19,7 @@ declare var APP: Object;
|
|||
*/
|
||||
export function appNavigate(uri: ?string) {
|
||||
return (dispatch: Dispatch<*>, getState: Function) =>
|
||||
_appNavigateToOptionalLocation(
|
||||
dispatch, getState,
|
||||
_parseURIString(uri));
|
||||
_appNavigateToOptionalLocation(dispatch, getState, parseURIString(uri));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +131,7 @@ function _appNavigateToOptionalLocation(
|
|||
// default.
|
||||
if (!location || !location.host) {
|
||||
const defaultLocation
|
||||
= _parseURIString(getState()['features/app'].app._getDefaultURL());
|
||||
= parseURIString(getState()['features/app'].app._getDefaultURL());
|
||||
|
||||
if (location) {
|
||||
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
|
||||
// be supported by fetch (or whatever loadConfig utilizes).
|
||||
if (protocol !== 'http:' && protocol !== 'https:') {
|
||||
protocol = 'https:';
|
||||
}
|
||||
protocol !== 'http:' && protocol !== 'https:' && (protocol = 'https:');
|
||||
|
||||
// TDOO userinfo
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { AbstractApp } from './AbstractApp';
|
||||
import { getLocationContextRoot } from '../functions';
|
||||
|
||||
import { getLocationContextRoot } from '../../base/util';
|
||||
import '../../room-lock';
|
||||
|
||||
import { AbstractApp } from './AbstractApp';
|
||||
|
||||
/**
|
||||
* Root application component.
|
||||
*
|
||||
|
|
|
@ -3,132 +3,6 @@ import { RouteRegistry } from '../base/react';
|
|||
import { Conference } from '../conference';
|
||||
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
|
||||
* store.
|
||||
|
@ -159,137 +33,3 @@ export function _getRouteToRender(stateOrGetState) {
|
|||
|
||||
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
|
||||
* store.
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
/* @flow */
|
||||
|
||||
import _ from 'lodash';
|
||||
import type { Dispatch } from 'redux';
|
||||
|
||||
import { conferenceWillLeave } from '../conference';
|
||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||
import { parseStandardURIString } from '../util';
|
||||
|
||||
import {
|
||||
CONNECTION_DISCONNECTED,
|
||||
|
@ -21,29 +23,8 @@ import {
|
|||
export function connect() {
|
||||
return (dispatch: Dispatch<*>, getState: Function) => {
|
||||
const state = getState();
|
||||
let { options } = state['features/base/connection'];
|
||||
|
||||
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 options = _constructOptions(state);
|
||||
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
|
||||
= new JitsiMeetJS.JitsiConnection(
|
||||
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.
|
||||
*
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* @flow */
|
||||
|
||||
import { assign, ReducerRegistry, set } from '../redux';
|
||||
import { parseURIString } from '../util';
|
||||
|
||||
import {
|
||||
CONNECTION_DISCONNECTED,
|
||||
|
@ -119,38 +120,38 @@ function _connectionWillConnect(
|
|||
|
||||
/**
|
||||
* 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
|
||||
* populated.
|
||||
* @param {string} locationURL - The location URL with which the returned
|
||||
* options are to be constructed.
|
||||
* @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
|
||||
// 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
|
||||
// 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 (typeof window === 'object') {
|
||||
if (!protocol && domain === 'beta.meet.jit.si') {
|
||||
const windowLocation = window.location;
|
||||
|
||||
if (windowLocation) {
|
||||
// React Native doesn't have a window.location at the time of
|
||||
// this writing, let alone a window.location.protocol.
|
||||
boshProtocol = windowLocation.protocol;
|
||||
}
|
||||
}
|
||||
boshProtocol || (boshProtocol = 'http:');
|
||||
windowLocation && (protocol = windowLocation.protocol);
|
||||
protocol || (protocol = 'http:');
|
||||
}
|
||||
|
||||
// Default to the HTTPS scheme for the BOSH URL.
|
||||
boshProtocol || (boshProtocol = 'https:');
|
||||
protocol || (protocol = 'https:');
|
||||
|
||||
return {
|
||||
bosh: `${String(boshProtocol)}//${domain}/http-bind`,
|
||||
bosh:
|
||||
`${String(protocol)}//${domain}${locationURI.contextRoot || '/'
|
||||
}http-bind`,
|
||||
hosts: {
|
||||
domain,
|
||||
|
||||
|
@ -176,6 +177,6 @@ function _setLocationURL(
|
|||
{ locationURL }: { locationURL: ?URL }) {
|
||||
return assign(state, {
|
||||
locationURL,
|
||||
options: locationURL ? _constructOptions(locationURL.host) : undefined
|
||||
options: locationURL ? _constructOptions(locationURL) : undefined
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
export * from './loadScript';
|
||||
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