56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
import { Injectable } from '@angular/core';
|
|
|
|
interface RegisterResponse {
|
|
id: string;
|
|
token: string;
|
|
}
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class TournamentAuthService {
|
|
private readonly inflight = new Map<string, Promise<string>>();
|
|
|
|
async getToken(serverUrl: string): Promise<string> {
|
|
const key = this.cacheKey(serverUrl);
|
|
const cached = localStorage.getItem(key);
|
|
if (cached) return cached;
|
|
|
|
const existing = this.inflight.get(key);
|
|
if (existing) return existing;
|
|
|
|
const promise = this.register(serverUrl)
|
|
.then(token => {
|
|
localStorage.setItem(key, token);
|
|
this.inflight.delete(key);
|
|
return token;
|
|
})
|
|
.catch(err => {
|
|
this.inflight.delete(key);
|
|
throw err;
|
|
});
|
|
|
|
this.inflight.set(key, promise);
|
|
return promise;
|
|
}
|
|
|
|
clearToken(serverUrl: string): void {
|
|
localStorage.removeItem(this.cacheKey(serverUrl));
|
|
}
|
|
|
|
private async register(serverUrl: string): Promise<string> {
|
|
const base = serverUrl.replace(/\/+$/, '');
|
|
const localName = localStorage.getItem('username') ?? 'viewer';
|
|
const res = await fetch(`${base}/api/auth/register`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name: `${localName}-watch`, isBot: false })
|
|
});
|
|
if (!res.ok) throw new Error(`tournament-server register failed: ${res.status}`);
|
|
const body = (await res.json()) as RegisterResponse;
|
|
return body.token;
|
|
}
|
|
|
|
private cacheKey(serverUrl: string): string {
|
|
return `tournament-token:${serverUrl.replace(/\/+$/, '')}`;
|
|
}
|
|
}
|