fix: Broken voice states and connectivity drops
This commit is contained in:
@@ -37,7 +37,11 @@ export const RoomsActions = createActionGroup({
|
||||
'Create Room Success': props<{ room: Room }>(),
|
||||
'Create Room Failure': props<{ error: string }>(),
|
||||
|
||||
'Join Room': props<{ roomId: string; password?: string; serverInfo?: Partial<ServerInfo> & { name: string } }>(),
|
||||
'Join Room': props<{
|
||||
roomId: string;
|
||||
password?: string;
|
||||
serverInfo?: Partial<ServerInfo> & { name: string; signalingUrl?: string };
|
||||
}>(),
|
||||
'Join Room Success': props<{ room: Room }>(),
|
||||
'Join Room Failure': props<{ error: string }>(),
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
of,
|
||||
from,
|
||||
EMPTY,
|
||||
firstValueFrom,
|
||||
merge
|
||||
} from 'rxjs';
|
||||
import {
|
||||
@@ -43,7 +44,10 @@ import {
|
||||
saveLastViewedChatToStorage
|
||||
} from '../../infrastructure/persistence';
|
||||
import {
|
||||
areRoomSignalSourcesEqual,
|
||||
CLIENT_UPDATE_REQUIRED_MESSAGE,
|
||||
type RoomSignalSource,
|
||||
type ServerInfo,
|
||||
type ServerSourceSelector,
|
||||
ServerDirectoryFacade
|
||||
} from '../../domains/server-directory';
|
||||
@@ -169,6 +173,12 @@ interface RoomPresenceSignalingMessage {
|
||||
displayName?: string;
|
||||
}
|
||||
|
||||
interface RoomSignalConnectionPlan {
|
||||
fallbackSources: RoomSignalSource[];
|
||||
primarySource: RoomSignalSource | null;
|
||||
room: Room;
|
||||
}
|
||||
|
||||
type BlockedRoomAccessAction =
|
||||
| ReturnType<typeof RoomsActions.forgetRoom>
|
||||
| ReturnType<typeof RoomsActions.joinRoomFailure>;
|
||||
@@ -196,6 +206,7 @@ export class RoomsEffects {
|
||||
* join/leave sound within {@link RECONNECT_SOUND_GRACE_MS}.
|
||||
*/
|
||||
private recentlyLeftVoiceTimestamps = new Map<string, number>();
|
||||
private readonly roomSignalFallbackSources = new Map<string, RoomSignalSource>();
|
||||
private roomNavigationRequestVersion = 0;
|
||||
private latestNavigatedRoomId: string | null = null;
|
||||
|
||||
@@ -388,13 +399,27 @@ export class RoomsEffects {
|
||||
return from(this.db.getRoom(roomId)).pipe(
|
||||
switchMap((room) => {
|
||||
const sourceSelector = serverInfo
|
||||
? {
|
||||
? this.serverDirectory.buildRoomSignalSelector({
|
||||
sourceId: serverInfo.sourceId,
|
||||
sourceUrl: serverInfo.sourceUrl
|
||||
}
|
||||
sourceName: serverInfo.sourceName,
|
||||
sourceUrl: serverInfo.sourceUrl,
|
||||
signalingUrl: serverInfo.signalingUrl,
|
||||
fallbackName: serverInfo.sourceName ?? serverInfo.name
|
||||
}, {
|
||||
ensureEndpoint: !!(serverInfo.sourceUrl ?? serverInfo.signalingUrl)
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (room) {
|
||||
const resolvedSource = this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: serverInfo?.sourceId ?? room.sourceId,
|
||||
sourceName: serverInfo?.sourceName ?? room.sourceName,
|
||||
sourceUrl: serverInfo?.sourceUrl ?? room.sourceUrl,
|
||||
signalingUrl: serverInfo?.signalingUrl,
|
||||
fallbackName: serverInfo?.sourceName ?? room.sourceName ?? serverInfo?.name ?? room.name
|
||||
}, {
|
||||
ensureEndpoint: !!(serverInfo?.sourceUrl ?? room.sourceUrl ?? serverInfo?.signalingUrl)
|
||||
});
|
||||
const resolvedRoom: Room = {
|
||||
...room,
|
||||
isPrivate: typeof serverInfo?.isPrivate === 'boolean' ? serverInfo.isPrivate : room.isPrivate,
|
||||
@@ -403,9 +428,7 @@ export class RoomsEffects {
|
||||
roles: serverInfo?.roles ?? room.roles,
|
||||
roleAssignments: serverInfo?.roleAssignments ?? room.roleAssignments,
|
||||
channelPermissions: serverInfo?.channelPermissions ?? room.channelPermissions,
|
||||
sourceId: serverInfo?.sourceId ?? room.sourceId,
|
||||
sourceName: serverInfo?.sourceName ?? room.sourceName,
|
||||
sourceUrl: serverInfo?.sourceUrl ?? room.sourceUrl,
|
||||
...resolvedSource,
|
||||
hasPassword:
|
||||
typeof serverInfo?.hasPassword === 'boolean'
|
||||
? serverInfo.hasPassword
|
||||
@@ -430,6 +453,15 @@ export class RoomsEffects {
|
||||
|
||||
// If not in local DB but we have server info from search, create a room entry
|
||||
if (serverInfo) {
|
||||
const resolvedSource = this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: serverInfo.sourceId,
|
||||
sourceName: serverInfo.sourceName,
|
||||
sourceUrl: serverInfo.sourceUrl,
|
||||
signalingUrl: serverInfo.signalingUrl,
|
||||
fallbackName: serverInfo.sourceName ?? serverInfo.name
|
||||
}, {
|
||||
ensureEndpoint: !!(serverInfo.sourceUrl ?? serverInfo.signalingUrl)
|
||||
});
|
||||
const newRoom: Room = {
|
||||
id: roomId,
|
||||
name: serverInfo.name,
|
||||
@@ -445,9 +477,7 @@ export class RoomsEffects {
|
||||
roles: serverInfo.roles,
|
||||
roleAssignments: serverInfo.roleAssignments,
|
||||
channelPermissions: serverInfo.channelPermissions,
|
||||
sourceId: serverInfo.sourceId,
|
||||
sourceName: serverInfo.sourceName,
|
||||
sourceUrl: serverInfo.sourceUrl
|
||||
...resolvedSource
|
||||
};
|
||||
|
||||
// Save to local DB for future reference
|
||||
@@ -459,6 +489,14 @@ export class RoomsEffects {
|
||||
return this.serverDirectory.getServer(roomId, sourceSelector).pipe(
|
||||
switchMap((serverData) => {
|
||||
if (serverData) {
|
||||
const resolvedSource = this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: serverData.sourceId,
|
||||
sourceName: serverData.sourceName,
|
||||
sourceUrl: serverData.sourceUrl,
|
||||
fallbackName: serverData.sourceName ?? serverData.name
|
||||
}, {
|
||||
ensureEndpoint: !!serverData.sourceUrl
|
||||
});
|
||||
const newRoom: Room = {
|
||||
id: serverData.id,
|
||||
name: serverData.name,
|
||||
@@ -474,9 +512,7 @@ export class RoomsEffects {
|
||||
roles: serverData.roles,
|
||||
roleAssignments: serverData.roleAssignments,
|
||||
channelPermissions: serverData.channelPermissions,
|
||||
sourceId: serverData.sourceId,
|
||||
sourceName: serverData.sourceName,
|
||||
sourceUrl: serverData.sourceUrl
|
||||
...resolvedSource
|
||||
};
|
||||
|
||||
this.db.saveRoom(newRoom);
|
||||
@@ -621,16 +657,32 @@ export class RoomsEffects {
|
||||
refreshServerOwnedRoomMetadata$ = createEffect(() =>
|
||||
this.actions$.pipe(
|
||||
ofType(RoomsActions.joinRoomSuccess, RoomsActions.viewServerSuccess),
|
||||
switchMap(({ room }) =>
|
||||
this.serverDirectory.getServer(room.id, {
|
||||
sourceId: room.sourceId,
|
||||
sourceUrl: room.sourceUrl
|
||||
}).pipe(
|
||||
switchMap(({ room }) => {
|
||||
const source = this.resolveRoomSignalSource(room);
|
||||
const selector = this.resolveRoomSignalSelector(source, room.name);
|
||||
const roomRequest$ = selector
|
||||
? this.serverDirectory.getServer(room.id, selector).pipe(
|
||||
switchMap((serverData) => serverData
|
||||
? of(serverData)
|
||||
: this.serverDirectory.findServerAcrossActiveEndpoints(room.id, source))
|
||||
)
|
||||
: this.serverDirectory.findServerAcrossActiveEndpoints(room.id, source);
|
||||
|
||||
return roomRequest$.pipe(
|
||||
map((serverData) => {
|
||||
if (!serverData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const resolvedSource = this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: serverData.sourceId ?? room.sourceId,
|
||||
sourceName: serverData.sourceName ?? room.sourceName,
|
||||
sourceUrl: serverData.sourceUrl ?? room.sourceUrl,
|
||||
fallbackName: serverData.sourceName ?? room.sourceName ?? room.name
|
||||
}, {
|
||||
ensureEndpoint: !!(serverData.sourceUrl ?? room.sourceUrl)
|
||||
});
|
||||
|
||||
return RoomsActions.updateRoom({
|
||||
roomId: room.id,
|
||||
changes: {
|
||||
@@ -645,16 +697,14 @@ export class RoomsEffects {
|
||||
roles: serverData.roles ?? room.roles,
|
||||
roleAssignments: serverData.roleAssignments ?? room.roleAssignments,
|
||||
channelPermissions: serverData.channelPermissions ?? room.channelPermissions,
|
||||
sourceId: serverData.sourceId ?? room.sourceId,
|
||||
sourceName: serverData.sourceName ?? room.sourceName,
|
||||
sourceUrl: serverData.sourceUrl ?? room.sourceUrl
|
||||
...resolvedSource
|
||||
}
|
||||
});
|
||||
}),
|
||||
filter((action): action is ReturnType<typeof RoomsActions.updateRoom> => !!action),
|
||||
catchError(() => EMPTY)
|
||||
)
|
||||
)
|
||||
);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
@@ -732,6 +782,7 @@ export class RoomsEffects {
|
||||
),
|
||||
switchMap(([{ roomId }]) => {
|
||||
this.db.deleteRoom(roomId);
|
||||
this.roomSignalFallbackSources.delete(roomId);
|
||||
this.webrtc.broadcastMessage({ type: 'room-deleted',
|
||||
roomId });
|
||||
|
||||
@@ -824,6 +875,7 @@ export class RoomsEffects {
|
||||
|
||||
// Delete from local DB
|
||||
this.db.deleteRoom(roomId);
|
||||
this.roomSignalFallbackSources.delete(roomId);
|
||||
|
||||
// Leave this specific server (doesn't affect other servers)
|
||||
this.webrtc.leaveRoom(roomId);
|
||||
@@ -1322,6 +1374,12 @@ export class RoomsEffects {
|
||||
if (signalingMessage.reason !== 'SERVER_NOT_FOUND')
|
||||
return EMPTY;
|
||||
|
||||
// When multiple signal URLs are configured, the room may already
|
||||
// be successfully joined on a different signal server. Only show
|
||||
// the reconnect notice when the room is not reachable at all.
|
||||
if (signalingMessage.serverId && this.webrtc.hasJoinedServer(signalingMessage.serverId))
|
||||
return EMPTY;
|
||||
|
||||
return [RoomsActions.setSignalServerReconnecting({ isReconnecting: true })];
|
||||
}
|
||||
|
||||
@@ -1997,23 +2055,127 @@ export class RoomsEffects {
|
||||
): Promise<void> {
|
||||
const shouldShowCompatibilityError = options.showCompatibilityError ?? false;
|
||||
const navigationRequestVersion = options.navigationRequestVersion;
|
||||
const compatibilitySelector = this.resolveCompatibilitySelector(room);
|
||||
const isCompatible = compatibilitySelector === null
|
||||
? true
|
||||
: await this.serverDirectory.ensureEndpointVersionCompatibility(compatibilitySelector);
|
||||
const isViewedRoom = () => room.id === this.latestNavigatedRoomId;
|
||||
|
||||
await this.serverDirectory.awaitInitialServerHealthCheck();
|
||||
|
||||
if (!this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCompatible) {
|
||||
if (shouldShowCompatibilityError) {
|
||||
this.store.dispatch(
|
||||
RoomsActions.setSignalServerCompatibilityError({ message: CLIENT_UPDATE_REQUIRED_MESSAGE })
|
||||
);
|
||||
const connectionPlan = await this.resolveRoomSignalConnectionPlan(room);
|
||||
|
||||
if (!this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionFallbackSource = this.roomSignalFallbackSources.get(room.id);
|
||||
const connectionCandidates: {
|
||||
isExistingFallback?: boolean;
|
||||
isFallback?: boolean;
|
||||
isPrimary?: boolean;
|
||||
source: RoomSignalSource;
|
||||
}[] = [];
|
||||
const pushConnectionCandidate = (
|
||||
source: RoomSignalSource | null | undefined,
|
||||
flags: { isExistingFallback?: boolean; isFallback?: boolean; isPrimary?: boolean } = {}
|
||||
) => {
|
||||
if (!source || !this.resolveRoomSignalSelector(source, room.name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (connectionCandidates.some((candidate) => areRoomSignalSourcesEqual(candidate.source, source))) {
|
||||
return;
|
||||
}
|
||||
|
||||
connectionCandidates.push({
|
||||
...flags,
|
||||
source
|
||||
});
|
||||
};
|
||||
|
||||
if (sessionFallbackSource && this.webrtc.hasJoinedServer(room.id)) {
|
||||
pushConnectionCandidate(sessionFallbackSource, { isExistingFallback: true, isFallback: true });
|
||||
}
|
||||
|
||||
pushConnectionCandidate(connectionPlan.primarySource, { isPrimary: true });
|
||||
|
||||
for (const fallbackSource of connectionPlan.fallbackSources) {
|
||||
pushConnectionCandidate(fallbackSource, { isFallback: true });
|
||||
}
|
||||
|
||||
let attemptedFallback = false;
|
||||
|
||||
for (const candidate of connectionCandidates) {
|
||||
const selector = this.resolveRoomSignalSelector(candidate.source, connectionPlan.room.name);
|
||||
|
||||
if (!selector) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isCompatible = await this.serverDirectory.ensureEndpointVersionCompatibility(selector);
|
||||
|
||||
if (!this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCompatible) {
|
||||
if (candidate.isPrimary) {
|
||||
if (shouldShowCompatibilityError) {
|
||||
this.store.dispatch(
|
||||
RoomsActions.setSignalServerCompatibilityError({ message: CLIENT_UPDATE_REQUIRED_MESSAGE })
|
||||
);
|
||||
}
|
||||
|
||||
if (isViewedRoom()) {
|
||||
this.store.dispatch(RoomsActions.setSignalServerReconnecting({ isReconnecting: false }));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (candidate.isFallback && !candidate.isExistingFallback && !attemptedFallback) {
|
||||
attemptedFallback = true;
|
||||
|
||||
if (isViewedRoom()) {
|
||||
this.store.dispatch(RoomsActions.setSignalServerReconnecting({ isReconnecting: true }));
|
||||
}
|
||||
}
|
||||
|
||||
const connected = await this.connectRoomToSignalSource(
|
||||
connectionPlan.room,
|
||||
candidate.source,
|
||||
user,
|
||||
resolvedOderId,
|
||||
savedRooms,
|
||||
navigationRequestVersion
|
||||
);
|
||||
|
||||
if (!this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connected) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (candidate.isFallback) {
|
||||
this.roomSignalFallbackSources.set(room.id, candidate.source);
|
||||
} else {
|
||||
this.roomSignalFallbackSources.delete(room.id);
|
||||
}
|
||||
|
||||
if (shouldShowCompatibilityError) {
|
||||
this.store.dispatch(RoomsActions.setSignalServerCompatibilityError({ message: null }));
|
||||
}
|
||||
|
||||
if (isViewedRoom()) {
|
||||
this.store.dispatch(RoomsActions.setSignalServerReconnecting({ isReconnecting: false }));
|
||||
}
|
||||
|
||||
this.store.dispatch(RoomsActions.setSignalServerReconnecting({ isReconnecting: false }));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2021,49 +2183,9 @@ export class RoomsEffects {
|
||||
this.store.dispatch(RoomsActions.setSignalServerCompatibilityError({ message: null }));
|
||||
}
|
||||
|
||||
const wsUrl = this.serverDirectory.getWebSocketUrl({
|
||||
sourceId: room.sourceId,
|
||||
sourceUrl: room.sourceUrl
|
||||
});
|
||||
const oderId = resolvedOderId || user?.oderId || this.webrtc.peerId();
|
||||
const displayName = resolveUserDisplayName(user);
|
||||
const sameSignalRooms = this.getRoomsForSignalingUrl(this.includeRoom(savedRooms, room), wsUrl);
|
||||
const backgroundRooms = sameSignalRooms.filter((candidate) => candidate.id !== room.id);
|
||||
const joinCurrentEndpointRooms = () => {
|
||||
if (!this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.webrtc.setCurrentServer(room.id);
|
||||
this.webrtc.identify(oderId, displayName, wsUrl);
|
||||
|
||||
for (const backgroundRoom of backgroundRooms) {
|
||||
if (!this.webrtc.hasJoinedServer(backgroundRoom.id)) {
|
||||
this.webrtc.joinRoom(backgroundRoom.id, oderId, wsUrl);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.webrtc.hasJoinedServer(room.id)) {
|
||||
this.webrtc.switchServer(room.id, oderId, wsUrl);
|
||||
} else {
|
||||
this.webrtc.joinRoom(room.id, oderId, wsUrl);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.webrtc.isSignalingConnectedTo(wsUrl)) {
|
||||
joinCurrentEndpointRooms();
|
||||
return;
|
||||
if (isViewedRoom()) {
|
||||
this.store.dispatch(RoomsActions.setSignalServerReconnecting({ isReconnecting: true }));
|
||||
}
|
||||
|
||||
this.webrtc.connectToSignalingServer(wsUrl).subscribe({
|
||||
next: (connected) => {
|
||||
if (!connected || !this.isCurrentRoomNavigation(room.id, navigationRequestVersion))
|
||||
return;
|
||||
|
||||
joinCurrentEndpointRooms();
|
||||
},
|
||||
error: () => {}
|
||||
});
|
||||
}
|
||||
|
||||
private syncSavedRoomConnections(user: User | null, currentRoom: Room | null, savedRooms: Room[]): void {
|
||||
@@ -2076,10 +2198,12 @@ export class RoomsEffects {
|
||||
const roomsBySignalingUrl = new Map<string, Room[]>();
|
||||
|
||||
for (const room of roomsToSync) {
|
||||
const wsUrl = this.serverDirectory.getWebSocketUrl({
|
||||
sourceId: room.sourceId,
|
||||
sourceUrl: room.sourceUrl
|
||||
});
|
||||
const wsUrl = this.resolveRoomSignalingUrl(room);
|
||||
|
||||
if (!wsUrl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const groupedRooms = roomsBySignalingUrl.get(wsUrl) ?? [];
|
||||
|
||||
if (!groupedRooms.some((groupedRoom) => groupedRoom.id === room.id)) {
|
||||
@@ -2149,10 +2273,7 @@ export class RoomsEffects {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this.serverDirectory.getWebSocketUrl({
|
||||
sourceId: room.sourceId,
|
||||
sourceUrl: room.sourceUrl
|
||||
}) !== wsUrl) {
|
||||
if (this.resolveRoomSignalingUrl(room) !== wsUrl) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2202,6 +2323,175 @@ export class RoomsEffects {
|
||||
return localStorage.getItem('metoyou_currentUserId');
|
||||
}
|
||||
|
||||
private async resolveRoomSignalConnectionPlan(room: Room): Promise<RoomSignalConnectionPlan> {
|
||||
let resolvedRoom = this.repairRoomSignalSource(room, this.resolveRoomSignalSource(room));
|
||||
let primarySource = this.resolveRoomSignalSource(resolvedRoom);
|
||||
|
||||
if (!this.webrtc.hasJoinedServer(room.id)) {
|
||||
const selector = this.resolveRoomSignalSelector(primarySource, resolvedRoom.name);
|
||||
const authoritativeServer = (
|
||||
selector
|
||||
? await firstValueFrom(this.serverDirectory.getServer(room.id, selector))
|
||||
: null
|
||||
) ?? await firstValueFrom(this.serverDirectory.findServerAcrossActiveEndpoints(room.id, primarySource));
|
||||
|
||||
if (authoritativeServer) {
|
||||
const authoritativeSource = this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: authoritativeServer.sourceId ?? primarySource.sourceId,
|
||||
sourceName: authoritativeServer.sourceName ?? primarySource.sourceName,
|
||||
sourceUrl: authoritativeServer.sourceUrl ?? primarySource.sourceUrl,
|
||||
fallbackName: authoritativeServer.sourceName ?? primarySource.sourceName ?? resolvedRoom.name
|
||||
}, {
|
||||
ensureEndpoint: !!(authoritativeServer.sourceUrl ?? primarySource.sourceUrl)
|
||||
});
|
||||
|
||||
resolvedRoom = this.repairRoomSignalSource(resolvedRoom, authoritativeSource);
|
||||
primarySource = authoritativeSource;
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackSources = this.serverDirectory.getFallbackRoomEndpoints(primarySource)
|
||||
.map((endpoint) => this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: endpoint.id,
|
||||
sourceName: endpoint.name,
|
||||
sourceUrl: endpoint.url,
|
||||
fallbackName: endpoint.name
|
||||
}))
|
||||
.filter((source, index, sources) =>
|
||||
sources.findIndex((candidate) => areRoomSignalSourcesEqual(candidate, source)) === index
|
||||
);
|
||||
|
||||
return {
|
||||
fallbackSources,
|
||||
primarySource: this.resolveRoomSignalSelector(primarySource, resolvedRoom.name) ? primarySource : null,
|
||||
room: resolvedRoom
|
||||
};
|
||||
}
|
||||
|
||||
private async connectRoomToSignalSource(
|
||||
room: Room,
|
||||
source: RoomSignalSource,
|
||||
user: User | null,
|
||||
resolvedOderId: string | undefined,
|
||||
savedRooms: Room[],
|
||||
navigationRequestVersion?: number
|
||||
): Promise<boolean> {
|
||||
const selector = this.resolveRoomSignalSelector(source, room.name);
|
||||
|
||||
if (!selector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const wsUrl = this.serverDirectory.getWebSocketUrl(selector);
|
||||
const oderId = resolvedOderId || user?.oderId || this.webrtc.peerId();
|
||||
const displayName = resolveUserDisplayName(user);
|
||||
const sameSignalRooms = this.getRoomsForSignalingUrl(this.includeRoom(savedRooms, room), wsUrl);
|
||||
const backgroundRooms = sameSignalRooms.filter((candidate) => candidate.id !== room.id);
|
||||
const joinCurrentEndpointRooms = () => {
|
||||
if (!this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.webrtc.setCurrentServer(room.id);
|
||||
this.webrtc.identify(oderId, displayName, wsUrl);
|
||||
|
||||
for (const backgroundRoom of backgroundRooms) {
|
||||
this.webrtc.joinRoom(backgroundRoom.id, oderId, wsUrl);
|
||||
}
|
||||
|
||||
if (this.webrtc.hasJoinedServer(room.id)) {
|
||||
this.webrtc.switchServer(room.id, oderId, wsUrl);
|
||||
} else {
|
||||
this.webrtc.joinRoom(room.id, oderId, wsUrl);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.webrtc.isSignalingConnectedTo(wsUrl)) {
|
||||
joinCurrentEndpointRooms();
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const connected = await firstValueFrom(this.webrtc.connectToSignalingServer(wsUrl));
|
||||
|
||||
if (!connected || !this.isCurrentRoomNavigation(room.id, navigationRequestVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
joinCurrentEndpointRooms();
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private resolveRoomSignalSource(
|
||||
room: Pick<Room, 'name' | 'sourceId' | 'sourceName' | 'sourceUrl'>
|
||||
): RoomSignalSource {
|
||||
return this.serverDirectory.normaliseRoomSignalSource({
|
||||
sourceId: room.sourceId,
|
||||
sourceName: room.sourceName,
|
||||
sourceUrl: room.sourceUrl,
|
||||
fallbackName: room.sourceName ?? room.name
|
||||
}, {
|
||||
ensureEndpoint: !!room.sourceUrl
|
||||
});
|
||||
}
|
||||
|
||||
private repairRoomSignalSource(room: Room, source: RoomSignalSource | null): Room {
|
||||
if (!source || areRoomSignalSourcesEqual(room, source)) {
|
||||
return room;
|
||||
}
|
||||
|
||||
const changes: Partial<Room> = {
|
||||
sourceId: source.sourceId,
|
||||
sourceName: source.sourceName,
|
||||
sourceUrl: source.sourceUrl
|
||||
};
|
||||
|
||||
this.store.dispatch(RoomsActions.updateRoom({
|
||||
roomId: room.id,
|
||||
changes
|
||||
}));
|
||||
|
||||
return {
|
||||
...room,
|
||||
...changes
|
||||
};
|
||||
}
|
||||
|
||||
private resolveRoomSignalSelector(
|
||||
source: RoomSignalSource | null | undefined,
|
||||
fallbackName: string
|
||||
): ServerSourceSelector | undefined {
|
||||
if (!source) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.serverDirectory.buildRoomSignalSelector({
|
||||
...source,
|
||||
fallbackName: source.sourceName ?? fallbackName
|
||||
}, {
|
||||
ensureEndpoint: !!source.sourceUrl
|
||||
});
|
||||
}
|
||||
|
||||
private getPreferredRoomSignalSource(room: Room): RoomSignalSource {
|
||||
const fallbackSource = this.roomSignalFallbackSources.get(room.id);
|
||||
|
||||
if (fallbackSource && this.webrtc.hasJoinedServer(room.id)) {
|
||||
return fallbackSource;
|
||||
}
|
||||
|
||||
return this.resolveRoomSignalSource(room);
|
||||
}
|
||||
|
||||
private resolveRoomSignalingUrl(room: Room): string {
|
||||
const selector = this.resolveRoomSignalSelector(this.getPreferredRoomSignalSource(room), room.name);
|
||||
|
||||
return selector ? this.serverDirectory.getWebSocketUrl(selector) : '';
|
||||
}
|
||||
|
||||
private async getBlockedRoomAccessActions(
|
||||
roomId: string,
|
||||
currentUser: { id: string; oderId: string } | null
|
||||
|
||||
Reference in New Issue
Block a user