Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/popular-pumas-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"livekit-client": patch
---

fix: ensure udpated tokens get set on the regionUrlProvider
36 changes: 19 additions & 17 deletions src/room/RTCEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
PublishDataTrackResponse,
ReconnectReason,
type ReconnectResponse,
type RegionSettings,
RequestResponse,
Room as RoomModel,
RoomMovedResponse,
Expand Down Expand Up @@ -62,7 +63,6 @@ import { TTLMap } from '../utils/ttlmap';
import PCTransport, { PCEvents } from './PCTransport';
import { PCTransportManager, PCTransportState } from './PCTransportManager';
import type { ReconnectContext, ReconnectPolicy } from './ReconnectPolicy';
import { DEFAULT_MAX_AGE_MS, type RegionUrlProvider } from './RegionUrlProvider';
import { DataTrackInfo } from './data-track/types';
import { roomConnectOptionDefaults } from './defaults';
import {
Expand Down Expand Up @@ -222,7 +222,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit

private shouldFailOnV1Path: boolean = false;

private regionUrlProvider?: RegionUrlProvider;
private regionStrategy?: RegionStrategy;

private log = log;

Expand Down Expand Up @@ -332,7 +332,6 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
this.shouldFailOnV1Path = false;
throw ConnectionError.serviceNotFound('Simulated v1 path failure', 'v0-rtc');
}
log.warn('joining signal with ', url);
const joinResponse = await this.client.join(
url,
token,
Expand Down Expand Up @@ -532,8 +531,8 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
}

/* @internal */
setRegionUrlProvider(provider: RegionUrlProvider) {
this.regionUrlProvider = provider;
setRegionStrategy(strategy: RegionStrategy | undefined) {
this.regionStrategy = strategy;
}

private async configure(joinResponse?: JoinResponse, useSinglePeerConnection?: boolean) {
Expand Down Expand Up @@ -684,7 +683,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit

this.client.onTokenRefresh = (token: string) => {
this.token = token;
this.regionUrlProvider?.updateToken(token);
this.emit(EngineEvent.TokenRefreshed, token);
};

this.client.onRemoteMuteChanged = (trackSid: string, muted: boolean) => {
Expand Down Expand Up @@ -726,13 +725,9 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit

this.client.onLeave = (leave: LeaveRequest) => {
this.log.debug('client leave request', { ...this.logContext, reason: leave?.reason });
if (leave.regions && this.regionUrlProvider) {
if (leave.regions) {
this.log.debug('updating regions', this.logContext);
this.regionUrlProvider.setServerReportedRegions({
updatedAtInMs: Date.now(),
maxAgeInMs: DEFAULT_MAX_AGE_MS,
regionSettings: leave.regions,
});
this.emit(EngineEvent.ServerRegionsReported, leave.regions);
}
switch (leave.action) {
case LeaveRequest_Action.DISCONNECT:
Expand Down Expand Up @@ -1137,10 +1132,10 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
this.log.debug(`reconnecting in ${delay}ms`, this.logContext);

this.clearReconnectTimeout();
if (this.token && this.regionUrlProvider) {
if (this.token) {
// token may have been refreshed, we do not want to recreate the regionUrlProvider
// since the current engine may have inherited a regional url
this.regionUrlProvider.updateToken(this.token);
this.emit(EngineEvent.TokenRefreshed, this.token);
}
this.reconnectTimeout = CriticalTimers.setTimeout(
() =>
Expand Down Expand Up @@ -1273,17 +1268,17 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
throw new SignalReconnectError('Signal connection got severed during reconnect');
}

this.regionUrlProvider?.resetAttempts();
this.regionStrategy?.resetAttempts();
// reconnect success
this.emit(EngineEvent.Restarted);
} catch (error) {
const nextRegionUrl = await this.regionUrlProvider?.getNextBestRegionUrl();
const nextRegionUrl = await this.regionStrategy?.getNextUrl();
if (nextRegionUrl) {
await this.restartConnection(nextRegionUrl);
return;
} else {
// no more regions to try (or we're not on cloud)
this.regionUrlProvider?.resetAttempts();
this.regionStrategy?.resetAttempts();
throw error;
}
}
Expand Down Expand Up @@ -2023,8 +2018,15 @@ export type EngineEventCallbacks = {
dataTrackSubscriberHandles: (event: DataTrackSubscriberHandles) => void;
dataTrackPacketReceived: (packet: Uint8Array) => void;
joined: (joinResponse: JoinResponse) => void;
tokenRefreshed: (token: string) => void;
serverRegionsReported: (regions: RegionSettings) => void;
};

export interface RegionStrategy {
getNextUrl(abortSignal?: AbortSignal): Promise<string | null>;
resetAttempts(): void;
}

function applyUserDataCompat(newObj: DataPacket, oldObj: UserPacket) {
const participantIdentity = newObj.participantIdentity
? newObj.participantIdentity
Expand Down
7 changes: 7 additions & 0 deletions src/room/RegionUrlProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ export class RegionUrlProvider {

updateToken(token: string) {
this.token = token;
const url = this.getServerUrl();
const settings = RegionUrlProvider.cache.get(url.hostname);
RegionUrlProvider.scheduleRefetch(
this.serverUrl,
this.token,
settings?.maxAgeInMs ?? DEFAULT_MAX_AGE_MS,
);
}

isCloud() {
Expand Down
26 changes: 23 additions & 3 deletions src/room/Room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ import TypedPromise from '../utils/TypedPromise';
import { getBrowser } from '../utils/browserParser';
import { BackOffStrategy } from './BackOffStrategy';
import DeviceManager from './DeviceManager';
import RTCEngine, { DataChannelKind } from './RTCEngine';
import { RegionUrlProvider } from './RegionUrlProvider';
import RTCEngine, { DataChannelKind, type RegionStrategy } from './RTCEngine';
import { DEFAULT_MAX_AGE_MS, RegionUrlProvider } from './RegionUrlProvider';
import IncomingDataStreamManager from './data-stream/incoming/IncomingDataStreamManager';
import {
type ByteStreamHandler,
Expand Down Expand Up @@ -668,6 +668,16 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
}),
);
this.incomingDataTrackManager.receiveSfuPublicationUpdates(mapped);
})
.on(EngineEvent.TokenRefreshed, (token) => {
this.regionUrlProvider?.updateToken(token);
})
.on(EngineEvent.ServerRegionsReported, (regions) => {
this.regionUrlProvider?.setServerReportedRegions({
regionSettings: regions,
updatedAtInMs: Date.now(),
maxAgeInMs: DEFAULT_MAX_AGE_MS,
});
});

if (this.localParticipant) {
Expand All @@ -681,6 +691,14 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
}
}

private createRegionStrategy(): RegionStrategy {
return {
getNextUrl: async (signal?: AbortSignal) =>
this.regionUrlProvider ? this.regionUrlProvider.getNextBestRegionUrl(signal) : null,
resetAttempts: () => this.regionUrlProvider?.resetAttempts(),
};
}

/**
* getLocalDevices abstracts navigator.mediaDevices.enumerateDevices.
* In particular, it requests device permissions by default if needed
Expand Down Expand Up @@ -764,10 +782,12 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
if (this.regionUrlProvider?.getServerUrl().toString() !== ensureTrailingSlash(url)) {
this.regionUrl = undefined;
this.regionUrlProvider = undefined;
this.engine.setRegionStrategy(undefined);
}
if (isCloud(new URL(url))) {
if (this.regionUrlProvider === undefined) {
this.regionUrlProvider = new RegionUrlProvider(url, token);
this.engine.setRegionStrategy(this.createRegionStrategy());
} else {
this.regionUrlProvider.updateToken(token);
}
Expand Down Expand Up @@ -965,7 +985,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
this.maybeCreateEngine();
}
if (this.regionUrlProvider?.isCloud()) {
this.engine.setRegionUrlProvider(this.regionUrlProvider);
this.engine.setRegionStrategy(this.createRegionStrategy());
}

this.acquireAudioContext();
Expand Down
2 changes: 2 additions & 0 deletions src/room/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,8 @@ export enum EngineEvent {
DataTrackSubscriberHandles = 'dataTrackSubscriberHandles',
DataTrackPacketReceived = 'dataTrackPacketReceived',
Joined = 'joined',
TokenRefreshed = 'tokenRefreshed',
ServerRegionsReported = 'serverRegionsReported',
}

export enum TrackEvent {
Expand Down
Loading