Files
NowChess-Frontend/src/app/services/stream-handler.service.ts
T
shosho996 c02414ea40 fix: NCWF-2 bugs and desing fixes (#7)
Co-authored-by: Lala, Shahd <Shahd.Lala@sybit.de>
Reviewed-on: #7
2026-05-15 02:16:43 +02:00

72 lines
2.0 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): 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.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();
};
});
}
}