Files
NowChess-Frontend/src/app/services/stream-handler.service.ts
T
LQ63 68395f820c fix(ncs-122): send WS token via first-message auth instead of query param
Remove token from WebSocket URL query parameters in ChallengeWebSocketService
and GameApiService. Instead, send {"type":"auth","token":"..."} as the first
text frame after the connection opens, matching the new backend auth protocol.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 10:42:38 +02:00

73 lines
2.1 KiB
TypeScript

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { GameStreamEvent, ErrorEvent } from '../models/game.models';
const WS_CONNECT_TIMEOUT_MS = 3000;
@Injectable({ providedIn: 'root' })
export class StreamHandlerService {
createGameStream(wsUrl: string, gameId: string, token: string): Observable<GameStreamEvent> {
return new Observable<GameStreamEvent>((observer) => {
const ws = new WebSocket(wsUrl);
let connected = false;
const emitErrorEvent = (message: string): void => {
const errorEvent: ErrorEvent = {
type: 'error',
error: { code: 'STREAM_ERROR', message },
};
observer.next(errorEvent);
};
const failAndComplete = (reason: string): void => {
console.warn(`[StreamHandler] WebSocket failed for ${gameId}: ${reason}`);
emitErrorEvent(reason);
observer.complete();
};
const connectionTimeoutId = setTimeout(() => {
if (!connected) {
ws.close();
failAndComplete('WebSocket connection timed out — falling back to polling');
}
}, WS_CONNECT_TIMEOUT_MS);
ws.onopen = () => {
connected = true;
clearTimeout(connectionTimeoutId);
console.log(`[StreamHandler] WebSocket connected for ${gameId}`);
ws.send(JSON.stringify({ type: 'auth', token }));
};
ws.onmessage = (message) => {
const payload = typeof message.data === 'string' ? message.data : '';
if (!payload.trim()) return;
try {
const event = JSON.parse(payload) as GameStreamEvent;
observer.next(event);
} catch {
// ignore malformed frames
}
};
ws.onerror = () => {
clearTimeout(connectionTimeoutId);
if (!connected) {
failAndComplete('WebSocket connection error — falling back to polling');
}
};
ws.onclose = () => {
clearTimeout(connectionTimeoutId);
if (connected) {
observer.complete();
}
};
return () => {
ws.close();
};
});
}
}