213 lines
5.3 KiB
TypeScript
213 lines
5.3 KiB
TypeScript
import _ from 'lodash';
|
|
|
|
import { IReduxState } from '../../app/types';
|
|
import {
|
|
appendURLParam,
|
|
getBackendSafeRoomName,
|
|
parseURIString
|
|
} from '../util/uri';
|
|
|
|
import {
|
|
CONNECTION_DISCONNECTED,
|
|
CONNECTION_ESTABLISHED,
|
|
CONNECTION_FAILED,
|
|
SET_LOCATION_URL
|
|
} from './actionTypes';
|
|
import logger from './logger';
|
|
|
|
/**
|
|
* The error structure passed to the {@link connectionFailed} action.
|
|
*
|
|
* Note there was an intention to make the error resemble an Error instance (to
|
|
* the extent that jitsi-meet needs it).
|
|
*/
|
|
export type ConnectionFailedError = {
|
|
|
|
/**
|
|
* The invalid credentials that were used to authenticate and the
|
|
* authentication failed.
|
|
*/
|
|
credentials?: {
|
|
|
|
/**
|
|
* The XMPP user's ID.
|
|
*/
|
|
jid: string;
|
|
|
|
/**
|
|
* The XMPP user's password.
|
|
*/
|
|
password: string;
|
|
};
|
|
|
|
/**
|
|
* The details about the connection failed event.
|
|
*/
|
|
details?: Object;
|
|
|
|
/**
|
|
* Error message.
|
|
*/
|
|
message?: string;
|
|
|
|
/**
|
|
* One of {@link JitsiConnectionError} constants (defined in
|
|
* lib-jitsi-meet).
|
|
*/
|
|
name: string;
|
|
|
|
/**
|
|
* Indicates whether this event is recoverable or not.
|
|
*/
|
|
recoverable?: boolean;
|
|
};
|
|
|
|
/**
|
|
* Create an action for when the signaling connection has been lost.
|
|
*
|
|
* @param {JitsiConnection} connection - The {@code JitsiConnection} which
|
|
* disconnected.
|
|
* @private
|
|
* @returns {{
|
|
* type: CONNECTION_DISCONNECTED,
|
|
* connection: JitsiConnection
|
|
* }}
|
|
*/
|
|
export function connectionDisconnected(connection: Object) {
|
|
return {
|
|
type: CONNECTION_DISCONNECTED,
|
|
connection
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create an action for when the signaling connection has been established.
|
|
*
|
|
* @param {JitsiConnection} connection - The {@code JitsiConnection} which was
|
|
* established.
|
|
* @param {number} timeEstablished - The time at which the
|
|
* {@code JitsiConnection} which was established.
|
|
* @public
|
|
* @returns {{
|
|
* type: CONNECTION_ESTABLISHED,
|
|
* connection: JitsiConnection,
|
|
* timeEstablished: number
|
|
* }}
|
|
*/
|
|
export function connectionEstablished(
|
|
connection: Object, timeEstablished: number) {
|
|
return {
|
|
type: CONNECTION_ESTABLISHED,
|
|
connection,
|
|
timeEstablished
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Create an action for when the signaling connection could not be created.
|
|
*
|
|
* @param {JitsiConnection} connection - The {@code JitsiConnection} which
|
|
* failed.
|
|
* @param {ConnectionFailedError} error - Error.
|
|
* @public
|
|
* @returns {{
|
|
* type: CONNECTION_FAILED,
|
|
* connection: JitsiConnection,
|
|
* error: ConnectionFailedError
|
|
* }}
|
|
*/
|
|
export function connectionFailed(
|
|
connection: Object,
|
|
error: ConnectionFailedError) {
|
|
const { credentials } = error;
|
|
|
|
if (credentials && !Object.keys(credentials).length) {
|
|
error.credentials = undefined;
|
|
}
|
|
|
|
return {
|
|
type: CONNECTION_FAILED,
|
|
connection,
|
|
error
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 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: IReduxState) {
|
|
// 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;
|
|
}
|
|
|
|
/**
|
|
* Sets the location URL of the application, connection, conference, etc.
|
|
*
|
|
* @param {URL} [locationURL] - The location URL of the application,
|
|
* connection, conference, etc.
|
|
* @returns {{
|
|
* type: SET_LOCATION_URL,
|
|
* locationURL: URL
|
|
* }}
|
|
*/
|
|
export function setLocationURL(locationURL?: URL) {
|
|
return {
|
|
type: SET_LOCATION_URL,
|
|
locationURL
|
|
};
|
|
}
|