fix: When adding a room param to urls check for previous params. (#11607)
* fix: When adding a room param to urls check for previous params. * squash: Uses URL object to modify the url. * squash: Use common connection options from base/connection. Normalizes bosh url and for web. * squash: Adds release param to external api and handles it. * feat: Adds release handling for mobile(links in welcome page). * squash: Fixes comments.
This commit is contained in:
parent
7dd85bb6ad
commit
f3c6b54ffa
|
@ -8,7 +8,8 @@ import { LoginDialog } from './react/features/authentication/components';
|
||||||
import { isTokenAuthEnabled } from './react/features/authentication/functions';
|
import { isTokenAuthEnabled } from './react/features/authentication/functions';
|
||||||
import {
|
import {
|
||||||
connectionEstablished,
|
connectionEstablished,
|
||||||
connectionFailed
|
connectionFailed,
|
||||||
|
constructOptions
|
||||||
} from './react/features/base/connection/actions';
|
} from './react/features/base/connection/actions';
|
||||||
import { openDialog } from './react/features/base/dialog/actions';
|
import { openDialog } from './react/features/base/dialog/actions';
|
||||||
import { setJWT } from './react/features/base/jwt';
|
import { setJWT } from './react/features/base/jwt';
|
||||||
|
@ -81,12 +82,10 @@ function checkForAttachParametersAndConnect(id, password, connection) {
|
||||||
* Try to open connection using provided credentials.
|
* Try to open connection using provided credentials.
|
||||||
* @param {string} [id]
|
* @param {string} [id]
|
||||||
* @param {string} [password]
|
* @param {string} [password]
|
||||||
* @param {string} [roomName]
|
|
||||||
* @returns {Promise<JitsiConnection>} connection if
|
* @returns {Promise<JitsiConnection>} connection if
|
||||||
* everything is ok, else error.
|
* everything is ok, else error.
|
||||||
*/
|
*/
|
||||||
export async function connect(id, password, roomName) {
|
export async function connect(id, password) {
|
||||||
const connectionConfig = Object.assign({}, config);
|
|
||||||
const state = APP.store.getState();
|
const state = APP.store.getState();
|
||||||
let { jwt } = state['features/base/jwt'];
|
let { jwt } = state['features/base/jwt'];
|
||||||
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
|
const { iAmRecorder, iAmSipGateway } = state['features/base/config'];
|
||||||
|
@ -100,19 +99,7 @@ export async function connect(id, password, roomName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use Websocket URL for the web app if configured. Note that there is no 'isWeb' check, because there's assumption
|
const connection = new JitsiMeetJS.JitsiConnection(null, jwt, constructOptions(state));
|
||||||
// that this code executes only on web browsers/electron. This needs to be changed when mobile and web are unified.
|
|
||||||
let serviceUrl = connectionConfig.websocket || connectionConfig.bosh;
|
|
||||||
|
|
||||||
serviceUrl += `?room=${roomName}`;
|
|
||||||
|
|
||||||
connectionConfig.serviceUrl = serviceUrl;
|
|
||||||
|
|
||||||
if (connectionConfig.websocketKeepAliveUrl) {
|
|
||||||
connectionConfig.websocketKeepAliveUrl += `?room=${roomName}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connection = new JitsiMeetJS.JitsiConnection(null, jwt, connectionConfig);
|
|
||||||
|
|
||||||
if (config.iAmRecorder) {
|
if (config.iAmRecorder) {
|
||||||
connection.addFeature(DISCO_JIBRI_FEATURE);
|
connection.addFeature(DISCO_JIBRI_FEATURE);
|
||||||
|
|
|
@ -301,6 +301,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||||
* the participant opening the meeting.
|
* the participant opening the meeting.
|
||||||
* @param {string} [options.e2eeKey] - The key used for End-to-End encryption.
|
* @param {string} [options.e2eeKey] - The key used for End-to-End encryption.
|
||||||
* THIS IS EXPERIMENTAL.
|
* THIS IS EXPERIMENTAL.
|
||||||
|
* @param {string} [options.release] - The key used for specifying release if enabled on the backend.
|
||||||
*/
|
*/
|
||||||
constructor(domain, ...args) {
|
constructor(domain, ...args) {
|
||||||
super();
|
super();
|
||||||
|
@ -317,7 +318,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||||
invitees,
|
invitees,
|
||||||
devices,
|
devices,
|
||||||
userInfo,
|
userInfo,
|
||||||
e2eeKey
|
e2eeKey,
|
||||||
|
release
|
||||||
} = parseArguments(args);
|
} = parseArguments(args);
|
||||||
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
|
||||||
|
|
||||||
|
@ -332,7 +334,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
||||||
userInfo,
|
userInfo,
|
||||||
appData: {
|
appData: {
|
||||||
localStorageContent
|
localStorageContent
|
||||||
}
|
},
|
||||||
|
release
|
||||||
});
|
});
|
||||||
this._createIFrame(height, width, onload);
|
this._createIFrame(height, width, onload);
|
||||||
this._transport = new Transport({
|
this._transport = new Transport({
|
||||||
|
|
|
@ -15,8 +15,10 @@ import { connect, disconnect, setLocationURL } from '../base/connection';
|
||||||
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
|
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
|
||||||
import { createDesiredLocalTracks } from '../base/tracks';
|
import { createDesiredLocalTracks } from '../base/tracks';
|
||||||
import {
|
import {
|
||||||
|
appendURLParam,
|
||||||
getBackendSafeRoomName,
|
getBackendSafeRoomName,
|
||||||
parseURIString,
|
parseURIString,
|
||||||
|
parseURLParams,
|
||||||
toURLString
|
toURLString
|
||||||
} from '../base/util';
|
} from '../base/util';
|
||||||
import { isPrejoinPageEnabled } from '../mobile/navigation/functions';
|
import { isPrejoinPageEnabled } from '../mobile/navigation/functions';
|
||||||
|
@ -90,7 +92,11 @@ export function appNavigate(uri: ?string) {
|
||||||
let url = `${baseURL}config.js`;
|
let url = `${baseURL}config.js`;
|
||||||
|
|
||||||
// XXX In order to support multiple shards, tell the room to the deployment.
|
// XXX In order to support multiple shards, tell the room to the deployment.
|
||||||
room && (url += `?room=${getBackendSafeRoomName(room)}`);
|
room && (url = appendURLParam(url, 'room', getBackendSafeRoomName(room)));
|
||||||
|
|
||||||
|
const { release } = parseURLParams(location, true, 'search');
|
||||||
|
|
||||||
|
release && (url = appendURLParam(url, 'release', release));
|
||||||
|
|
||||||
let config;
|
let config;
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,10 @@ import {
|
||||||
import { setLocationURL } from '../base/connection';
|
import { setLocationURL } from '../base/connection';
|
||||||
import { loadConfig } from '../base/lib-jitsi-meet/functions.web';
|
import { loadConfig } from '../base/lib-jitsi-meet/functions.web';
|
||||||
import {
|
import {
|
||||||
|
appendURLParam,
|
||||||
getBackendSafeRoomName,
|
getBackendSafeRoomName,
|
||||||
parseURIString
|
parseURIString,
|
||||||
|
parseURLParams
|
||||||
} from '../base/util';
|
} from '../base/util';
|
||||||
import { isVpaasMeeting } from '../jaas/functions';
|
import { isVpaasMeeting } from '../jaas/functions';
|
||||||
import {
|
import {
|
||||||
|
@ -93,7 +95,11 @@ export function appNavigate(uri: ?string) {
|
||||||
let url = `${baseURL}config.js`;
|
let url = `${baseURL}config.js`;
|
||||||
|
|
||||||
// XXX In order to support multiple shards, tell the room to the deployment.
|
// XXX In order to support multiple shards, tell the room to the deployment.
|
||||||
room && (url += `?room=${getBackendSafeRoomName(room)}`);
|
room && (url = appendURLParam(url, 'room', getBackendSafeRoomName(room)));
|
||||||
|
|
||||||
|
const { release } = parseURLParams(location, true, 'search');
|
||||||
|
|
||||||
|
release && (url = appendURLParam(url, 'release', release));
|
||||||
|
|
||||||
let config;
|
let config;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import {
|
||||||
|
appendURLParam,
|
||||||
|
getBackendSafeRoomName,
|
||||||
|
parseURIString
|
||||||
|
} from '../util';
|
||||||
|
|
||||||
|
import logger from './logger';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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}.
|
||||||
|
*/
|
||||||
|
export function constructOptions(state) {
|
||||||
|
// Deep clone the options to make sure we don't modify the object in the
|
||||||
|
// redux store.
|
||||||
|
const options = _.cloneDeep(state['features/base/config']);
|
||||||
|
|
||||||
|
let { bosh, websocket } = options;
|
||||||
|
|
||||||
|
// TESTING: Only enable WebSocket for some percentage of users.
|
||||||
|
if (websocket && navigator.product === 'ReactNative') {
|
||||||
|
if ((Math.random() * 100) >= (options?.testing?.mobileXmppWsThreshold ?? 0)) {
|
||||||
|
websocket = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize the BOSH URL.
|
||||||
|
if (bosh && !websocket) {
|
||||||
|
const { locationURL } = state['features/base/connection'];
|
||||||
|
|
||||||
|
if (bosh.startsWith('//')) {
|
||||||
|
// By default our config.js doesn't include the protocol.
|
||||||
|
bosh = `${locationURL.protocol}${bosh}`;
|
||||||
|
} else if (bosh.startsWith('/')) {
|
||||||
|
// Handle relative URLs, which won't work on mobile.
|
||||||
|
const {
|
||||||
|
protocol,
|
||||||
|
host,
|
||||||
|
contextRoot
|
||||||
|
} = parseURIString(locationURL.href);
|
||||||
|
|
||||||
|
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocket is preferred over BOSH.
|
||||||
|
const serviceUrl = websocket || bosh;
|
||||||
|
|
||||||
|
logger.log(`Using service URL ${serviceUrl}`);
|
||||||
|
|
||||||
|
// Append room to the URL's search.
|
||||||
|
const { room } = state['features/base/conference'];
|
||||||
|
|
||||||
|
if (serviceUrl && room) {
|
||||||
|
const roomName = getBackendSafeRoomName(room);
|
||||||
|
|
||||||
|
options.serviceUrl = appendURLParam(serviceUrl, 'room', roomName);
|
||||||
|
|
||||||
|
if (options.websocketKeepAliveUrl) {
|
||||||
|
options.websocketKeepAliveUrl = appendURLParam(options.websocketKeepAliveUrl, 'room', roomName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
|
@ -1,15 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import _ from 'lodash';
|
|
||||||
import type { Dispatch } from 'redux';
|
import type { Dispatch } from 'redux';
|
||||||
|
|
||||||
import { conferenceLeft, conferenceWillLeave } from '../conference/actions';
|
import { conferenceLeft, conferenceWillLeave } from '../conference/actions';
|
||||||
import { getCurrentConference } from '../conference/functions';
|
import { getCurrentConference } from '../conference/functions';
|
||||||
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
|
||||||
import {
|
|
||||||
getBackendSafeRoomName,
|
|
||||||
parseURIString
|
|
||||||
} from '../util';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CONNECTION_DISCONNECTED,
|
CONNECTION_DISCONNECTED,
|
||||||
|
@ -18,9 +13,12 @@ import {
|
||||||
CONNECTION_WILL_CONNECT,
|
CONNECTION_WILL_CONNECT,
|
||||||
SET_LOCATION_URL
|
SET_LOCATION_URL
|
||||||
} from './actionTypes';
|
} from './actionTypes';
|
||||||
|
import { constructOptions } from './actions.any';
|
||||||
import { JITSI_CONNECTION_URL_KEY } from './constants';
|
import { JITSI_CONNECTION_URL_KEY } from './constants';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
|
export * from './actions.any';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The error structure passed to the {@link connectionFailed} action.
|
* The error structure passed to the {@link connectionFailed} action.
|
||||||
*
|
*
|
||||||
|
@ -78,7 +76,7 @@ export type ConnectionFailedError = {
|
||||||
export function connect(id: ?string, password: ?string) {
|
export function connect(id: ?string, password: ?string) {
|
||||||
return (dispatch: Dispatch<any>, getState: Function) => {
|
return (dispatch: Dispatch<any>, getState: Function) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const options = _constructOptions(state);
|
const options = constructOptions(state);
|
||||||
const { locationURL } = state['features/base/connection'];
|
const { locationURL } = state['features/base/connection'];
|
||||||
const { jwt } = state['features/base/jwt'];
|
const { jwt } = state['features/base/jwt'];
|
||||||
const connection = new JitsiMeetJS.JitsiConnection(options.appId, jwt, options);
|
const connection = new JitsiMeetJS.JitsiConnection(options.appId, jwt, options);
|
||||||
|
@ -262,69 +260,6 @@ function _connectionWillConnect(connection) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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) {
|
|
||||||
// Deep clone the options to make sure we don't modify the object in the
|
|
||||||
// redux store.
|
|
||||||
const options = _.cloneDeep(state['features/base/config']);
|
|
||||||
|
|
||||||
let { bosh, websocket } = options;
|
|
||||||
|
|
||||||
// TESTING: Only enable WebSocket for some percentage of users.
|
|
||||||
if (websocket) {
|
|
||||||
if ((Math.random() * 100) >= (options?.testing?.mobileXmppWsThreshold ?? 0)) {
|
|
||||||
websocket = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normalize the BOSH URL.
|
|
||||||
if (bosh && !websocket) {
|
|
||||||
const { locationURL } = state['features/base/connection'];
|
|
||||||
|
|
||||||
if (bosh.startsWith('//')) {
|
|
||||||
// By default our config.js doesn't include the protocol.
|
|
||||||
bosh = `${locationURL.protocol}${bosh}`;
|
|
||||||
} else if (bosh.startsWith('/')) {
|
|
||||||
// Handle relative URLs, which won't work on mobile.
|
|
||||||
const {
|
|
||||||
protocol,
|
|
||||||
host,
|
|
||||||
contextRoot
|
|
||||||
} = parseURIString(locationURL.href);
|
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
|
||||||
bosh = `${protocol}//${host}${contextRoot || '/'}${bosh.substr(1)}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebSocket is preferred over BOSH.
|
|
||||||
const serviceUrl = websocket || bosh;
|
|
||||||
|
|
||||||
logger.log(`Using service URL ${serviceUrl}`);
|
|
||||||
|
|
||||||
// Append room to the URL's search.
|
|
||||||
const { room } = state['features/base/conference'];
|
|
||||||
|
|
||||||
if (serviceUrl && room) {
|
|
||||||
const roomName = getBackendSafeRoomName(room);
|
|
||||||
|
|
||||||
options.serviceUrl = `${serviceUrl}?room=${roomName}`;
|
|
||||||
|
|
||||||
if (options.websocketKeepAliveUrl) {
|
|
||||||
options.websocketKeepAliveUrl += `?room=${roomName}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes connection.
|
* Closes connection.
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,6 +16,8 @@ export {
|
||||||
} from './actions.native';
|
} from './actions.native';
|
||||||
import logger from './logger';
|
import logger from './logger';
|
||||||
|
|
||||||
|
export * from './actions.any';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens new connection.
|
* Opens new connection.
|
||||||
*
|
*
|
||||||
|
|
|
@ -524,7 +524,7 @@ export function urlObjectToString(o: Object): ?string {
|
||||||
// query/search
|
// query/search
|
||||||
|
|
||||||
// Web's ExternalAPI jwt and lang
|
// Web's ExternalAPI jwt and lang
|
||||||
const { jwt, lang } = o;
|
const { jwt, lang, release } = o;
|
||||||
|
|
||||||
const search = new URLSearchParams(url.search);
|
const search = new URLSearchParams(url.search);
|
||||||
|
|
||||||
|
@ -538,6 +538,10 @@ export function urlObjectToString(o: Object): ?string {
|
||||||
search.set('lang', lang || defaultLanguage);
|
search.set('lang', lang || defaultLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (release) {
|
||||||
|
search.set('release', release);
|
||||||
|
}
|
||||||
|
|
||||||
const searchString = search.toString();
|
const searchString = search.toString();
|
||||||
|
|
||||||
if (searchString) {
|
if (searchString) {
|
||||||
|
@ -603,3 +607,20 @@ export function addHashParamsToURL(url: URL, hashParamsToAdd: Object = {}) {
|
||||||
export function getDecodedURI(uri: string) {
|
export function getDecodedURI(uri: string) {
|
||||||
return decodeURI(uri.replace(/^https?:\/\//i, ''));
|
return decodeURI(uri.replace(/^https?:\/\//i, ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds new param to a url string. Checks whether to use '?' or '&' as a separator (checks for already existing params).
|
||||||
|
*
|
||||||
|
* @param {string} url - The url to modify.
|
||||||
|
* @param {string} name - The param name to add.
|
||||||
|
* @param {string} value - The value for the param.
|
||||||
|
*
|
||||||
|
* @returns {string} - The modified url.
|
||||||
|
*/
|
||||||
|
export function appendURLParam(url: string, name: string, value: string) {
|
||||||
|
const newUrl = new URL(url);
|
||||||
|
|
||||||
|
newUrl.searchParams.append(name, value);
|
||||||
|
|
||||||
|
return newUrl.toString();
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,11 @@ import { i18next } from '../base/i18n';
|
||||||
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
|
||||||
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
|
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
|
||||||
import { toState } from '../base/redux';
|
import { toState } from '../base/redux';
|
||||||
import { parseURIString } from '../base/util';
|
import {
|
||||||
|
appendURLParam,
|
||||||
|
parseURIString,
|
||||||
|
parseURLParams
|
||||||
|
} from '../base/util';
|
||||||
import { isVpaasMeeting } from '../jaas/functions';
|
import { isVpaasMeeting } from '../jaas/functions';
|
||||||
|
|
||||||
import { getDialInConferenceID, getDialInNumbers } from './_utils';
|
import { getDialInConferenceID, getDialInNumbers } from './_utils';
|
||||||
|
@ -596,7 +600,7 @@ export function getDialInfoPageURL(state: Object, roomName: ?string) {
|
||||||
|
|
||||||
const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/${DIAL_IN_INFO_PAGE_PATH_NAME}`;
|
const url = didPageUrl || `${href.substring(0, href.lastIndexOf('/'))}/${DIAL_IN_INFO_PAGE_PATH_NAME}`;
|
||||||
|
|
||||||
return `${url}?room=${room}`;
|
return appendURLParam(url, 'room', room);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -611,8 +615,15 @@ export function getDialInfoPageURLForURIString(
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const { protocol, host, contextRoot, room } = parseURIString(uri);
|
const { protocol, host, contextRoot, room } = parseURIString(uri);
|
||||||
|
let url = `${protocol}//${host}${contextRoot}${DIAL_IN_INFO_PAGE_PATH_NAME}`;
|
||||||
|
|
||||||
return `${protocol}//${host}${contextRoot}${DIAL_IN_INFO_PAGE_PATH_NAME}?room=${room}`;
|
url = appendURLParam(url, 'room', room);
|
||||||
|
|
||||||
|
const { release } = parseURLParams(uri, true, 'search');
|
||||||
|
|
||||||
|
release && (url = appendURLParam(url, 'release', release));
|
||||||
|
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue