fix: Broken voice states and connectivity drops
This commit is contained in:
@@ -29,6 +29,7 @@ import type {
|
||||
ServerSourceSelector,
|
||||
UnbanServerMemberRequest
|
||||
} from '../domain/server-directory.models';
|
||||
import type { RoomSignalSourceInput } from '../domain/room-signal-source';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ServerDirectoryApiService {
|
||||
@@ -45,14 +46,16 @@ export class ServerDirectoryApiService {
|
||||
|
||||
resolveEndpoint(selector?: ServerSourceSelector): ServerEndpoint | null {
|
||||
if (selector?.sourceId) {
|
||||
return this.endpointState.servers().find((endpoint) => endpoint.id === selector.sourceId) ?? null;
|
||||
const endpoint = this.endpointState.servers().find((candidate) => candidate.id === selector.sourceId) ?? null;
|
||||
|
||||
return this.endpointState.resolveCanonicalEndpoint(endpoint);
|
||||
}
|
||||
|
||||
if (selector?.sourceUrl) {
|
||||
return this.endpointState.findServerByUrl(selector.sourceUrl) ?? null;
|
||||
return this.endpointState.resolveCanonicalEndpoint(this.endpointState.findServerByUrl(selector.sourceUrl) ?? null);
|
||||
}
|
||||
|
||||
return (
|
||||
return this.endpointState.resolveCanonicalEndpoint(
|
||||
this.endpointState.activeServer() ??
|
||||
this.endpointState.servers().find((endpoint) => endpoint.status !== 'incompatible') ??
|
||||
this.endpointState.servers()[0] ??
|
||||
@@ -92,6 +95,45 @@ export class ServerDirectoryApiService {
|
||||
);
|
||||
}
|
||||
|
||||
findServerAcrossActiveEndpoints(serverId: string, source?: RoomSignalSourceInput): Observable<ServerInfo | null> {
|
||||
const candidateEndpoints = this.getSearchableEndpoints();
|
||||
const preferredSourceUrl = source?.sourceUrl ? this.endpointState.sanitiseUrl(source.sourceUrl) : undefined;
|
||||
const prioritizedEndpoints = [...candidateEndpoints].sort((left, right) => {
|
||||
if (preferredSourceUrl) {
|
||||
const leftMatches = this.endpointState.sanitiseUrl(left.url) === preferredSourceUrl;
|
||||
const rightMatches = this.endpointState.sanitiseUrl(right.url) === preferredSourceUrl;
|
||||
|
||||
if (leftMatches !== rightMatches) {
|
||||
return leftMatches ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (source?.sourceId) {
|
||||
const leftMatches = left.id === source.sourceId;
|
||||
const rightMatches = right.id === source.sourceId;
|
||||
|
||||
if (leftMatches !== rightMatches) {
|
||||
return leftMatches ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (prioritizedEndpoints.length === 0) {
|
||||
return this.getServer(serverId, this.resolveSelector(source));
|
||||
}
|
||||
|
||||
return forkJoin(
|
||||
prioritizedEndpoints.map((endpoint) => this.getServer(serverId, {
|
||||
sourceId: endpoint.id,
|
||||
sourceUrl: endpoint.url
|
||||
}))
|
||||
).pipe(
|
||||
map((servers) => servers.find((server): server is ServerInfo => !!server) ?? null)
|
||||
);
|
||||
}
|
||||
|
||||
registerServer(
|
||||
server: Omit<ServerInfo, 'createdAt'> & { id?: string; password?: string | null },
|
||||
selector?: ServerSourceSelector
|
||||
@@ -221,11 +263,17 @@ export class ServerDirectoryApiService {
|
||||
}
|
||||
|
||||
private resolveBaseServerUrl(selector?: ServerSourceSelector): string {
|
||||
const resolvedEndpoint = this.resolveEndpoint(selector);
|
||||
|
||||
if (resolvedEndpoint) {
|
||||
return resolvedEndpoint.url;
|
||||
}
|
||||
|
||||
if (selector?.sourceUrl) {
|
||||
return this.endpointState.sanitiseUrl(selector.sourceUrl);
|
||||
}
|
||||
|
||||
return this.resolveEndpoint(selector)?.url ?? this.endpointState.getPrimaryDefaultServerUrl();
|
||||
return this.endpointState.getPrimaryDefaultServerUrl();
|
||||
}
|
||||
|
||||
private unwrapServersResponse(response: { servers: ServerInfo[]; total: number } | ServerInfo[]): ServerInfo[] {
|
||||
@@ -245,7 +293,7 @@ export class ServerDirectoryApiService {
|
||||
}
|
||||
|
||||
private searchAllEndpoints(query: string): Observable<ServerInfo[]> {
|
||||
const onlineEndpoints = this.endpointState.activeServers().filter((endpoint) => endpoint.status !== 'offline');
|
||||
const onlineEndpoints = this.getSearchableEndpoints();
|
||||
|
||||
if (onlineEndpoints.length === 0) {
|
||||
return this.searchSingleEndpoint(query, this.getApiBaseUrl(), this.endpointState.activeServer());
|
||||
@@ -258,7 +306,7 @@ export class ServerDirectoryApiService {
|
||||
}
|
||||
|
||||
private getAllServersFromAllEndpoints(): Observable<ServerInfo[]> {
|
||||
const onlineEndpoints = this.endpointState.activeServers().filter((endpoint) => endpoint.status !== 'offline');
|
||||
const onlineEndpoints = this.getSearchableEndpoints();
|
||||
|
||||
if (onlineEndpoints.length === 0) {
|
||||
return this.http.get<{ servers: ServerInfo[]; total: number }>(`${this.getApiBaseUrl()}/servers`).pipe(
|
||||
@@ -277,6 +325,30 @@ export class ServerDirectoryApiService {
|
||||
).pipe(map((resultArrays) => resultArrays.flat()));
|
||||
}
|
||||
|
||||
private getSearchableEndpoints(): ServerEndpoint[] {
|
||||
const activeEndpoints = this.endpointState.activeServers().filter((endpoint) => endpoint.status !== 'offline');
|
||||
|
||||
if (activeEndpoints.length > 0) {
|
||||
return activeEndpoints;
|
||||
}
|
||||
|
||||
const activeServer = this.endpointState.activeServer();
|
||||
|
||||
return activeServer ? [activeServer] : [];
|
||||
}
|
||||
|
||||
private resolveSelector(source?: RoomSignalSourceInput): ServerSourceSelector | undefined {
|
||||
if (source?.sourceId) {
|
||||
return { sourceId: source.sourceId };
|
||||
}
|
||||
|
||||
if (source?.sourceUrl) {
|
||||
return { sourceUrl: source.sourceUrl };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private deduplicateById<T extends { id: string }>(items: T[]): T[] {
|
||||
const seen = new Set<string>();
|
||||
|
||||
@@ -298,13 +370,14 @@ export class ServerDirectoryApiService {
|
||||
const candidate = server as Record<string, unknown>;
|
||||
const sourceName = this.getStringValue(candidate['sourceName']);
|
||||
const sourceUrl = this.getStringValue(candidate['sourceUrl']);
|
||||
const resolvedSource = this.endpointState.resolveCanonicalEndpoint(source);
|
||||
|
||||
return {
|
||||
id: this.getStringValue(candidate['id']) ?? '',
|
||||
name: this.getStringValue(candidate['name']) ?? 'Unnamed server',
|
||||
description: this.getStringValue(candidate['description']),
|
||||
topic: this.getStringValue(candidate['topic']),
|
||||
hostName: this.getStringValue(candidate['hostName']) ?? sourceName ?? source?.name ?? 'Unknown API',
|
||||
hostName: this.getStringValue(candidate['hostName']) ?? sourceName ?? resolvedSource?.name ?? 'Unknown API',
|
||||
ownerId: this.getStringValue(candidate['ownerId']),
|
||||
ownerName: this.getStringValue(candidate['ownerName']),
|
||||
ownerPublicKey: this.getStringValue(candidate['ownerPublicKey']),
|
||||
@@ -319,9 +392,13 @@ export class ServerDirectoryApiService {
|
||||
roleAssignments: this.getRoleAssignmentsValue(candidate['roleAssignments']),
|
||||
channelPermissions: this.getChannelPermissionOverridesValue(candidate['channelPermissions']),
|
||||
createdAt: this.getNumberValue(candidate['createdAt'], Date.now()),
|
||||
sourceId: this.getStringValue(candidate['sourceId']) ?? source?.id,
|
||||
sourceName: sourceName ?? source?.name,
|
||||
sourceUrl: sourceUrl ? this.endpointState.sanitiseUrl(sourceUrl) : source ? this.endpointState.sanitiseUrl(source.url) : undefined
|
||||
sourceId: this.getStringValue(candidate['sourceId']) ?? resolvedSource?.id,
|
||||
sourceName: sourceName ?? resolvedSource?.name,
|
||||
sourceUrl: sourceUrl
|
||||
? this.endpointState.sanitiseUrl(sourceUrl)
|
||||
: resolvedSource
|
||||
? this.endpointState.sanitiseUrl(resolvedSource.url)
|
||||
: undefined
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,16 @@ export class ServerEndpointHealthService {
|
||||
payload.serverVersion,
|
||||
clientVersion
|
||||
);
|
||||
const serverInstanceId = typeof payload.serverInstanceId === 'string' && payload.serverInstanceId.trim().length > 0
|
||||
? payload.serverInstanceId.trim()
|
||||
: undefined;
|
||||
|
||||
if (!versionCompatibility.isCompatible) {
|
||||
return {
|
||||
status: 'incompatible',
|
||||
latency,
|
||||
versions: {
|
||||
serverInstanceId,
|
||||
serverVersion: versionCompatibility.serverVersion,
|
||||
clientVersion
|
||||
}
|
||||
@@ -46,6 +50,7 @@ export class ServerEndpointHealthService {
|
||||
status: 'online',
|
||||
latency,
|
||||
versions: {
|
||||
serverInstanceId,
|
||||
serverVersion: versionCompatibility.serverVersion,
|
||||
clientVersion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user