Calling: Add cache for relay server requests
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
parent
38d5e50175
commit
e22c700237
3 changed files with 77 additions and 29 deletions
|
@ -63,6 +63,8 @@ import { isMe } from '../util/whatTypeOfConversation';
|
||||||
import type {
|
import type {
|
||||||
AvailableIODevicesType,
|
AvailableIODevicesType,
|
||||||
CallEndedReason,
|
CallEndedReason,
|
||||||
|
IceServerType,
|
||||||
|
IceServerCacheType,
|
||||||
MediaDeviceSettings,
|
MediaDeviceSettings,
|
||||||
PresentedSource,
|
PresentedSource,
|
||||||
} from '../types/Calling';
|
} from '../types/Calling';
|
||||||
|
@ -180,6 +182,7 @@ const CLEAN_EXPIRED_GROUP_CALL_RINGS_INTERVAL = 10 * durations.MINUTE;
|
||||||
const OUTGOING_SIGNALING_WAIT = 15 * durations.SECOND;
|
const OUTGOING_SIGNALING_WAIT = 15 * durations.SECOND;
|
||||||
|
|
||||||
const ICE_SERVER_IS_IP_LIKE = /(turn|turns|stun):[.\d]+/;
|
const ICE_SERVER_IS_IP_LIKE = /(turn|turns|stun):[.\d]+/;
|
||||||
|
|
||||||
const MAX_CALL_DEBUG_STATS_TABS = 5;
|
const MAX_CALL_DEBUG_STATS_TABS = 5;
|
||||||
|
|
||||||
// We send group call update messages to tell other clients to peek, which triggers
|
// We send group call update messages to tell other clients to peek, which triggers
|
||||||
|
@ -417,6 +420,9 @@ export class CallingClass {
|
||||||
|
|
||||||
public _iceServerOverride?: GetIceServersResultType | string;
|
public _iceServerOverride?: GetIceServersResultType | string;
|
||||||
|
|
||||||
|
// A cache to limit requests for relay servers.
|
||||||
|
#iceServersCache: IceServerCacheType | undefined;
|
||||||
|
|
||||||
#lastMediaDeviceSettings?: MediaDeviceSettings;
|
#lastMediaDeviceSettings?: MediaDeviceSettings;
|
||||||
#deviceReselectionTimer?: NodeJS.Timeout;
|
#deviceReselectionTimer?: NodeJS.Timeout;
|
||||||
#callsLookup: { [key: string]: Call | GroupCall };
|
#callsLookup: { [key: string]: Call | GroupCall };
|
||||||
|
@ -3396,17 +3402,10 @@ export class CallingClass {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #handleStartCall(call: Call): Promise<boolean> {
|
async #getIceServers(): Promise<Array<IceServerType>> {
|
||||||
type IceServer = {
|
|
||||||
username?: string;
|
|
||||||
password?: string;
|
|
||||||
hostname?: string;
|
|
||||||
urls: Array<string>;
|
|
||||||
};
|
|
||||||
|
|
||||||
function iceServerConfigToList(
|
function iceServerConfigToList(
|
||||||
iceServerConfig: GetIceServersResultType
|
iceServerConfig: GetIceServersResultType
|
||||||
): Array<IceServer> {
|
): Array<IceServerType> {
|
||||||
if (!iceServerConfig.relays) {
|
if (!iceServerConfig.relays) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -3427,6 +3426,61 @@ export class CallingClass {
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const currentTime = Date.now();
|
||||||
|
if (
|
||||||
|
this.#iceServersCache &&
|
||||||
|
currentTime < this.#iceServersCache.expirationTimestamp
|
||||||
|
) {
|
||||||
|
// Use the cached value for iceServers.
|
||||||
|
return this.#iceServersCache.iceServers;
|
||||||
|
}
|
||||||
|
|
||||||
|
let iceServers: Array<IceServerType> = [];
|
||||||
|
// Set the default cache expiration time to now + 0.
|
||||||
|
let expirationTimestamp = currentTime;
|
||||||
|
|
||||||
|
// The messaging context should have already been checked before entering
|
||||||
|
// this function, so this should be a noop.
|
||||||
|
const { messaging } = window.textsecure;
|
||||||
|
strictAssert(messaging, 'textsecure messaging not available');
|
||||||
|
|
||||||
|
const iceServerConfig = await messaging.server.getIceServers();
|
||||||
|
|
||||||
|
// Advance the next expiration time to the minimum provided ttl value,
|
||||||
|
// or if there were none, use 0 to disable the cache.
|
||||||
|
const minTtl = (iceServerConfig.relays ?? []).reduce(
|
||||||
|
(min, { ttl }) => Math.min(min, ttl ?? 0),
|
||||||
|
Infinity
|
||||||
|
);
|
||||||
|
|
||||||
|
expirationTimestamp += minTtl !== Infinity ? minTtl * durations.SECOND : 0;
|
||||||
|
|
||||||
|
// Prioritize ice servers with IPs to avoid DNS entries and only include
|
||||||
|
// hostname with urlsWithIps.
|
||||||
|
iceServers = iceServerConfigToList(iceServerConfig);
|
||||||
|
|
||||||
|
if (this._iceServerOverride) {
|
||||||
|
if (typeof this._iceServerOverride === 'string') {
|
||||||
|
if (ICE_SERVER_IS_IP_LIKE.test(this._iceServerOverride)) {
|
||||||
|
iceServers[0].urls = [this._iceServerOverride];
|
||||||
|
iceServers = [iceServers[0]];
|
||||||
|
} else {
|
||||||
|
iceServers[1].urls = [this._iceServerOverride];
|
||||||
|
iceServers = [iceServers[1]];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
iceServers = iceServerConfigToList(this._iceServerOverride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iceServers.length > 0) {
|
||||||
|
// Update the cached value for iceServers.
|
||||||
|
this.#iceServersCache = { iceServers, expirationTimestamp };
|
||||||
|
}
|
||||||
|
return iceServers;
|
||||||
|
}
|
||||||
|
|
||||||
|
async #handleStartCall(call: Call): Promise<boolean> {
|
||||||
if (!window.textsecure.messaging) {
|
if (!window.textsecure.messaging) {
|
||||||
log.error('CallingClass.handleStartCall: offline!');
|
log.error('CallingClass.handleStartCall: offline!');
|
||||||
return false;
|
return false;
|
||||||
|
@ -3453,8 +3507,7 @@ export class CallingClass {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const iceServerConfig =
|
const iceServers = await this.#getIceServers();
|
||||||
await window.textsecure.messaging.server.getIceServers();
|
|
||||||
|
|
||||||
// We do this again, since getIceServers is a call that can take some time
|
// We do this again, since getIceServers is a call that can take some time
|
||||||
if (call.endedReason) {
|
if (call.endedReason) {
|
||||||
|
@ -3470,24 +3523,6 @@ export class CallingClass {
|
||||||
// If the peer is not a Signal Connection, force IP hiding.
|
// If the peer is not a Signal Connection, force IP hiding.
|
||||||
const isContactUntrusted = !isSignalConnection(conversation.attributes);
|
const isContactUntrusted = !isSignalConnection(conversation.attributes);
|
||||||
|
|
||||||
// Prioritize ice servers with IPs to avoid DNS only include
|
|
||||||
// hostname with urlsWithIps.
|
|
||||||
let iceServers = iceServerConfigToList(iceServerConfig);
|
|
||||||
|
|
||||||
if (this._iceServerOverride) {
|
|
||||||
if (typeof this._iceServerOverride === 'string') {
|
|
||||||
if (ICE_SERVER_IS_IP_LIKE.test(this._iceServerOverride)) {
|
|
||||||
iceServers[0].urls = [this._iceServerOverride];
|
|
||||||
iceServers = [iceServers[0]];
|
|
||||||
} else {
|
|
||||||
iceServers[1].urls = [this._iceServerOverride];
|
|
||||||
iceServers = [iceServers[1]];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
iceServers = iceServerConfigToList(this._iceServerOverride);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const callSettings = {
|
const callSettings = {
|
||||||
iceServers,
|
iceServers,
|
||||||
hideIp: shouldRelayCalls || isContactUntrusted,
|
hideIp: shouldRelayCalls || isContactUntrusted,
|
||||||
|
|
|
@ -923,6 +923,7 @@ export type IceServerGroupType = Readonly<{
|
||||||
urls?: ReadonlyArray<string>;
|
urls?: ReadonlyArray<string>;
|
||||||
urlsWithIps?: ReadonlyArray<string>;
|
urlsWithIps?: ReadonlyArray<string>;
|
||||||
hostname?: string;
|
hostname?: string;
|
||||||
|
ttl?: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type GetSenderCertificateResultType = Readonly<{ certificate: string }>;
|
export type GetSenderCertificateResultType = Readonly<{ certificate: string }>;
|
||||||
|
|
|
@ -208,3 +208,15 @@ export enum ScreenShareStatus {
|
||||||
Reconnecting = 'Reconnecting',
|
Reconnecting = 'Reconnecting',
|
||||||
Disconnected = 'Disconnected',
|
Disconnected = 'Disconnected',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type IceServerType = {
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
hostname?: string;
|
||||||
|
urls: Array<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type IceServerCacheType = {
|
||||||
|
iceServers: Array<IceServerType>;
|
||||||
|
expirationTimestamp: number;
|
||||||
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue