feat: Add TURN server support
All checks were successful
Queue Release Build / prepare (push) Successful in 15s
Deploy Web Apps / deploy (push) Successful in 5m35s
Queue Release Build / build-linux (push) Successful in 24m45s
Queue Release Build / build-windows (push) Successful in 13m52s
Queue Release Build / finalize (push) Successful in 23s
All checks were successful
Queue Release Build / prepare (push) Successful in 15s
Deploy Web Apps / deploy (push) Successful in 5m35s
Queue Release Build / build-linux (push) Successful in 24m45s
Queue Release Build / build-windows (push) Successful in 13m52s
Queue Release Build / finalize (push) Successful in 23s
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import {
|
||||
Injectable,
|
||||
signal,
|
||||
computed,
|
||||
type Signal
|
||||
} from '@angular/core';
|
||||
import { STORAGE_KEY_ICE_SERVERS } from '../../core/constants';
|
||||
import { ICE_SERVERS } from './realtime.constants';
|
||||
|
||||
export interface IceServerEntry {
|
||||
id: string;
|
||||
type: 'stun' | 'turn';
|
||||
urls: string;
|
||||
username?: string;
|
||||
credential?: string;
|
||||
}
|
||||
|
||||
const DEFAULT_ENTRIES: IceServerEntry[] = ICE_SERVERS.map((server, index) => ({
|
||||
id: `default-stun-${index}`,
|
||||
type: 'stun' as const,
|
||||
urls: Array.isArray(server.urls) ? server.urls[0] : server.urls
|
||||
}));
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class IceServerSettingsService {
|
||||
readonly entries: Signal<IceServerEntry[]>;
|
||||
readonly rtcIceServers: Signal<RTCIceServer[]>;
|
||||
|
||||
private readonly _entries = signal<IceServerEntry[]>(this.load());
|
||||
|
||||
constructor() {
|
||||
this.entries = this._entries.asReadonly();
|
||||
this.rtcIceServers = computed<RTCIceServer[]>(() =>
|
||||
this._entries().map((entry) => {
|
||||
if (entry.type === 'turn') {
|
||||
return {
|
||||
urls: entry.urls,
|
||||
username: entry.username ?? '',
|
||||
credential: entry.credential ?? ''
|
||||
};
|
||||
}
|
||||
|
||||
return { urls: entry.urls };
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
addEntry(entry: Omit<IceServerEntry, 'id'>): void {
|
||||
const id = `${entry.type}-${Date.now()}-${Math.random().toString(36)
|
||||
.slice(2, 8)}`;
|
||||
const updated = [...this._entries(), { ...entry, id }];
|
||||
|
||||
this._entries.set(updated);
|
||||
this.save(updated);
|
||||
}
|
||||
|
||||
removeEntry(id: string): void {
|
||||
const updated = this._entries().filter((entry) => entry.id !== id);
|
||||
|
||||
this._entries.set(updated);
|
||||
this.save(updated);
|
||||
}
|
||||
|
||||
updateEntry(id: string, changes: Partial<Omit<IceServerEntry, 'id'>>): void {
|
||||
const updated = this._entries().map((entry) =>
|
||||
entry.id === id ? { ...entry, ...changes } : entry
|
||||
);
|
||||
|
||||
this._entries.set(updated);
|
||||
this.save(updated);
|
||||
}
|
||||
|
||||
moveEntry(fromIndex: number, toIndex: number): void {
|
||||
const entries = [...this._entries()];
|
||||
|
||||
if (fromIndex < 0 || fromIndex >= entries.length || toIndex < 0 || toIndex >= entries.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [moved] = entries.splice(fromIndex, 1);
|
||||
|
||||
entries.splice(toIndex, 0, moved);
|
||||
this._entries.set(entries);
|
||||
this.save(entries);
|
||||
}
|
||||
|
||||
restoreDefaults(): void {
|
||||
this._entries.set([...DEFAULT_ENTRIES]);
|
||||
this.save(DEFAULT_ENTRIES);
|
||||
}
|
||||
|
||||
private load(): IceServerEntry[] {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY_ICE_SERVERS);
|
||||
|
||||
if (!raw) {
|
||||
return [...DEFAULT_ENTRIES];
|
||||
}
|
||||
|
||||
const parsed = JSON.parse(raw);
|
||||
|
||||
if (!Array.isArray(parsed) || parsed.length === 0) {
|
||||
return [...DEFAULT_ENTRIES];
|
||||
}
|
||||
|
||||
return parsed.filter(
|
||||
(entry: unknown): entry is IceServerEntry =>
|
||||
typeof entry === 'object'
|
||||
&& entry !== null
|
||||
&& typeof (entry as IceServerEntry).id === 'string'
|
||||
&& ((entry as IceServerEntry).type === 'stun' || (entry as IceServerEntry).type === 'turn')
|
||||
&& typeof (entry as IceServerEntry).urls === 'string'
|
||||
);
|
||||
} catch {
|
||||
return [...DEFAULT_ENTRIES];
|
||||
}
|
||||
}
|
||||
|
||||
private save(entries: IceServerEntry[]): void {
|
||||
localStorage.setItem(STORAGE_KEY_ICE_SERVERS, JSON.stringify(entries));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user