73 lines
1.6 KiB
TypeScript
73 lines
1.6 KiB
TypeScript
import { encodeHex } from '@std/encoding/hex';
|
|
import { LRUCache } from 'lru-cache';
|
|
import type { AudioToken } from '../domain/types.ts';
|
|
import { TOKEN_CACHE_MAX_ITEMS, TOKEN_TTL_MS } from '../shared/constants.ts';
|
|
|
|
/**
|
|
* Token store service for managing short-lived audio streaming tokens
|
|
*/
|
|
export class TokenStoreService {
|
|
private readonly tokenCache: LRUCache<string, AudioToken>;
|
|
|
|
constructor(ttlMs: number = TOKEN_TTL_MS) {
|
|
this.tokenCache = new LRUCache<string, AudioToken>({
|
|
max: TOKEN_CACHE_MAX_ITEMS,
|
|
ttl: ttlMs,
|
|
ttlAutopurge: true,
|
|
allowStale: false,
|
|
updateAgeOnGet: false,
|
|
updateAgeOnHas: false,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generate a random token
|
|
*/
|
|
private generateToken(): string {
|
|
const bytes = new Uint8Array(16);
|
|
crypto.getRandomValues(bytes);
|
|
return encodeHex(bytes);
|
|
}
|
|
|
|
/**
|
|
* Create and store a new token
|
|
*/
|
|
putToken(value: AudioToken, ttlMs?: number): string {
|
|
const token = this.generateToken();
|
|
|
|
const options = ttlMs ? { ttl: Math.max(1000, ttlMs) } : undefined;
|
|
this.tokenCache.set(token, value, options);
|
|
|
|
return token;
|
|
}
|
|
|
|
/**
|
|
* Retrieve token data
|
|
*/
|
|
getToken(token: string): AudioToken | undefined {
|
|
if (!token) return undefined;
|
|
return this.tokenCache.get(token);
|
|
}
|
|
|
|
/**
|
|
* Remove a token
|
|
*/
|
|
deleteToken(token: string): boolean {
|
|
return this.tokenCache.delete(token);
|
|
}
|
|
|
|
/**
|
|
* Clear all tokens
|
|
*/
|
|
clearAll(): void {
|
|
this.tokenCache.clear();
|
|
}
|
|
|
|
/**
|
|
* Get cache size
|
|
*/
|
|
getSize(): number {
|
|
return this.tokenCache.size;
|
|
}
|
|
}
|