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:
Дамян Минков 2022-06-16 15:27:41 +03:00 committed by GitHub
parent 7dd85bb6ad
commit f3c6b54ffa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 137 additions and 95 deletions

View File

@ -8,7 +8,8 @@ import { LoginDialog } from './react/features/authentication/components';
import { isTokenAuthEnabled } from './react/features/authentication/functions';
import {
connectionEstablished,
connectionFailed
connectionFailed,
constructOptions
} from './react/features/base/connection/actions';
import { openDialog } from './react/features/base/dialog/actions';
import { setJWT } from './react/features/base/jwt';
@ -81,12 +82,10 @@ function checkForAttachParametersAndConnect(id, password, connection) {
* Try to open connection using provided credentials.
* @param {string} [id]
* @param {string} [password]
* @param {string} [roomName]
* @returns {Promise<JitsiConnection>} connection if
* everything is ok, else error.
*/
export async function connect(id, password, roomName) {
const connectionConfig = Object.assign({}, config);
export async function connect(id, password) {
const state = APP.store.getState();
let { jwt } = state['features/base/jwt'];
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
// 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);
const connection = new JitsiMeetJS.JitsiConnection(null, jwt, constructOptions(state));
if (config.iAmRecorder) {
connection.addFeature(DISCO_JIBRI_FEATURE);

View File

@ -301,6 +301,7 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
* the participant opening the meeting.
* @param {string} [options.e2eeKey] - The key used for End-to-End encryption.
* THIS IS EXPERIMENTAL.
* @param {string} [options.release] - The key used for specifying release if enabled on the backend.
*/
constructor(domain, ...args) {
super();
@ -317,7 +318,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
invitees,
devices,
userInfo,
e2eeKey
e2eeKey,
release
} = parseArguments(args);
const localStorageContent = jitsiLocalStorage.getItem('jitsiLocalStorage');
@ -332,7 +334,8 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
userInfo,
appData: {
localStorageContent
}
},
release
});
this._createIFrame(height, width, onload);
this._transport = new Transport({

View File

@ -15,8 +15,10 @@ import { connect, disconnect, setLocationURL } from '../base/connection';
import { loadConfig } from '../base/lib-jitsi-meet/functions.native';
import { createDesiredLocalTracks } from '../base/tracks';
import {
appendURLParam,
getBackendSafeRoomName,
parseURIString,
parseURLParams,
toURLString
} from '../base/util';
import { isPrejoinPageEnabled } from '../mobile/navigation/functions';
@ -90,7 +92,11 @@ export function appNavigate(uri: ?string) {
let url = `${baseURL}config.js`;
// 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;

View File

@ -15,8 +15,10 @@ import {
import { setLocationURL } from '../base/connection';
import { loadConfig } from '../base/lib-jitsi-meet/functions.web';
import {
appendURLParam,
getBackendSafeRoomName,
parseURIString
parseURIString,
parseURLParams
} from '../base/util';
import { isVpaasMeeting } from '../jaas/functions';
import {
@ -93,7 +95,11 @@ export function appNavigate(uri: ?string) {
let url = `${baseURL}config.js`;
// 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;

View File

@ -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;
}

View File

@ -1,15 +1,10 @@
// @flow
import _ from 'lodash';
import type { Dispatch } from 'redux';
import { conferenceLeft, conferenceWillLeave } from '../conference/actions';
import { getCurrentConference } from '../conference/functions';
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
import {
getBackendSafeRoomName,
parseURIString
} from '../util';
import {
CONNECTION_DISCONNECTED,
@ -18,9 +13,12 @@ import {
CONNECTION_WILL_CONNECT,
SET_LOCATION_URL
} from './actionTypes';
import { constructOptions } from './actions.any';
import { JITSI_CONNECTION_URL_KEY } from './constants';
import logger from './logger';
export * from './actions.any';
/**
* The error structure passed to the {@link connectionFailed} action.
*
@ -78,7 +76,7 @@ export type ConnectionFailedError = {
export function connect(id: ?string, password: ?string) {
return (dispatch: Dispatch<any>, getState: Function) => {
const state = getState();
const options = _constructOptions(state);
const options = constructOptions(state);
const { locationURL } = state['features/base/connection'];
const { jwt } = state['features/base/jwt'];
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.
*

View File

@ -16,6 +16,8 @@ export {
} from './actions.native';
import logger from './logger';
export * from './actions.any';
/**
* Opens new connection.
*

View File

@ -524,7 +524,7 @@ export function urlObjectToString(o: Object): ?string {
// query/search
// Web's ExternalAPI jwt and lang
const { jwt, lang } = o;
const { jwt, lang, release } = o;
const search = new URLSearchParams(url.search);
@ -538,6 +538,10 @@ export function urlObjectToString(o: Object): ?string {
search.set('lang', lang || defaultLanguage);
}
if (release) {
search.set('release', release);
}
const searchString = search.toString();
if (searchString) {
@ -603,3 +607,20 @@ export function addHashParamsToURL(url: URL, hashParamsToAdd: Object = {}) {
export function getDecodedURI(uri: string) {
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();
}

View File

@ -8,7 +8,11 @@ import { i18next } from '../base/i18n';
import { JitsiRecordingConstants } from '../base/lib-jitsi-meet';
import { getLocalParticipant, isLocalParticipantModerator } from '../base/participants';
import { toState } from '../base/redux';
import { parseURIString } from '../base/util';
import {
appendURLParam,
parseURIString,
parseURLParams
} from '../base/util';
import { isVpaasMeeting } from '../jaas/functions';
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}`;
return `${url}?room=${room}`;
return appendURLParam(url, 'room', room);
}
/**
@ -611,8 +615,15 @@ export function getDialInfoPageURLForURIString(
return undefined;
}
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;
}
/**