Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 74f82bc0ba | |||
| 1d2c217da8 |
@@ -71,3 +71,8 @@
|
|||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* **auth:** attach Bearer token to /api/bots requests ([#12](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/issues/12)) ([a54957a](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/commit/a54957aa74ef15bf2dd439d386e221ac134c5c5c))
|
* **auth:** attach Bearer token to /api/bots requests ([#12](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/issues/12)) ([a54957a](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/commit/a54957aa74ef15bf2dd439d386e221ac134c5c5c))
|
||||||
|
## [0.0.0](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/compare/0.4.1...0.0.0) (2026-06-17)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* NCS-122 send WS token via first-message auth instead of query param ([#13](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/issues/13)) ([1d2c217](https://git.janis-eccarius.de/NowChess/NowChess-Frontend/commit/1d2c217da8982d361e2eb7de26f6447171a1dd43))
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class ChallengeWebSocketService {
|
|||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (!token) return;
|
if (!token) return;
|
||||||
|
|
||||||
const url = `${environment.userWsBaseUrl}/api/user/ws?token=${encodeURIComponent(token)}`;
|
const url = `${environment.userWsBaseUrl}/api/user/ws`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.intentionalClose = false;
|
this.intentionalClose = false;
|
||||||
@@ -30,6 +30,7 @@ export class ChallengeWebSocketService {
|
|||||||
|
|
||||||
this.ws.onopen = () => {
|
this.ws.onopen = () => {
|
||||||
this.reconnectAttempts = 0;
|
this.reconnectAttempts = 0;
|
||||||
|
this.ws?.send(JSON.stringify({ type: 'auth', token }));
|
||||||
};
|
};
|
||||||
|
|
||||||
this.ws.onmessage = (event) => {
|
this.ws.onmessage = (event) => {
|
||||||
@@ -76,8 +77,10 @@ export class ChallengeWebSocketService {
|
|||||||
const challengeId = message['challengeId'] as string | undefined;
|
const challengeId = message['challengeId'] as string | undefined;
|
||||||
if (challengeId) {
|
if (challengeId) {
|
||||||
this.challengeService.getChallenge(challengeId).subscribe({
|
this.challengeService.getChallenge(challengeId).subscribe({
|
||||||
next: challenge => this.challengeEventService.onChallengeReceived(challenge),
|
next: (challenge) => this.challengeEventService.onChallengeReceived(challenge),
|
||||||
error: () => { /* challenge may have already expired */ }
|
error: () => {
|
||||||
|
/* challenge may have already expired */
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -110,6 +113,8 @@ export class ChallengeWebSocketService {
|
|||||||
private attemptReconnect(): void {
|
private attemptReconnect(): void {
|
||||||
if (this.intentionalClose || this.reconnectAttempts >= this.maxReconnectAttempts) return;
|
if (this.intentionalClose || this.reconnectAttempts >= this.maxReconnectAttempts) return;
|
||||||
this.reconnectAttempts++;
|
this.reconnectAttempts++;
|
||||||
setTimeout(() => { this.connect(); }, this.reconnectDelay);
|
setTimeout(() => {
|
||||||
|
this.connect();
|
||||||
|
}, this.reconnectDelay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
GameState,
|
GameState,
|
||||||
GameStreamEvent,
|
GameStreamEvent,
|
||||||
LegalMovesResponse,
|
LegalMovesResponse,
|
||||||
PlayerInfo
|
PlayerInfo,
|
||||||
} from '../models/game.models';
|
} from '../models/game.models';
|
||||||
import { AnalysisRequest, AnalysisResponse } from '../models/analysis.models';
|
import { AnalysisRequest, AnalysisResponse } from '../models/analysis.models';
|
||||||
import { StreamHandlerService } from './stream-handler.service';
|
import { StreamHandlerService } from './stream-handler.service';
|
||||||
@@ -29,11 +29,11 @@ export class GameApiService {
|
|||||||
const playerColor = Math.random() > 0.5 ? 'white' : 'black';
|
const playerColor = Math.random() > 0.5 ? 'white' : 'black';
|
||||||
const playerInfo: PlayerInfo = {
|
const playerInfo: PlayerInfo = {
|
||||||
id: `player-${Date.now()}`,
|
id: `player-${Date.now()}`,
|
||||||
displayName: 'You'
|
displayName: 'You',
|
||||||
};
|
};
|
||||||
const botInfo: PlayerInfo = {
|
const botInfo: PlayerInfo = {
|
||||||
id: `bot-${difficulty}`,
|
id: `bot-${difficulty}`,
|
||||||
displayName: `Bot (${difficulty})`
|
displayName: `Bot (${difficulty})`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const payload =
|
const payload =
|
||||||
@@ -57,7 +57,9 @@ export class GameApiService {
|
|||||||
if (square) {
|
if (square) {
|
||||||
params = params.set('square', square);
|
params = params.set('square', square);
|
||||||
}
|
}
|
||||||
return this.http.get<LegalMovesResponse>(`${this.apiBase}${this.apiPath}/${gameId}/moves`, { params });
|
return this.http.get<LegalMovesResponse>(`${this.apiBase}${this.apiPath}/${gameId}/moves`, {
|
||||||
|
params,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
importFen(fen: string): Observable<GameFull> {
|
importFen(fen: string): Observable<GameFull> {
|
||||||
@@ -90,11 +92,8 @@ export class GameApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
streamGame(gameId: string): Observable<GameStreamEvent> {
|
streamGame(gameId: string): Observable<GameStreamEvent> {
|
||||||
const token = localStorage.getItem('token');
|
const wsUrl = `${this.resolveWsBase()}${this.apiPath}/${gameId}/ws`;
|
||||||
let wsUrl = `${this.resolveWsBase()}${this.apiPath}/${gameId}/ws`;
|
const token = localStorage.getItem('token') ?? '';
|
||||||
if (token) {
|
return this.streamHandler.createGameStream(wsUrl, gameId, token);
|
||||||
wsUrl += `?token=${encodeURIComponent(token)}`;
|
|
||||||
}
|
|
||||||
return this.streamHandler.createGameStream(wsUrl, gameId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const WS_CONNECT_TIMEOUT_MS = 3000;
|
|||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class StreamHandlerService {
|
export class StreamHandlerService {
|
||||||
createGameStream(wsUrl: string, gameId: string): Observable<GameStreamEvent> {
|
createGameStream(wsUrl: string, gameId: string, token: string): Observable<GameStreamEvent> {
|
||||||
return new Observable<GameStreamEvent>((observer) => {
|
return new Observable<GameStreamEvent>((observer) => {
|
||||||
const ws = new WebSocket(wsUrl);
|
const ws = new WebSocket(wsUrl);
|
||||||
let connected = false;
|
let connected = false;
|
||||||
@@ -14,7 +14,7 @@ export class StreamHandlerService {
|
|||||||
const emitErrorEvent = (message: string): void => {
|
const emitErrorEvent = (message: string): void => {
|
||||||
const errorEvent: ErrorEvent = {
|
const errorEvent: ErrorEvent = {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
error: { code: 'STREAM_ERROR', message }
|
error: { code: 'STREAM_ERROR', message },
|
||||||
};
|
};
|
||||||
observer.next(errorEvent);
|
observer.next(errorEvent);
|
||||||
};
|
};
|
||||||
@@ -36,6 +36,7 @@ export class StreamHandlerService {
|
|||||||
connected = true;
|
connected = true;
|
||||||
clearTimeout(connectionTimeoutId);
|
clearTimeout(connectionTimeoutId);
|
||||||
console.log(`[StreamHandler] WebSocket connected for ${gameId}`);
|
console.log(`[StreamHandler] WebSocket connected for ${gameId}`);
|
||||||
|
ws.send(JSON.stringify({ type: 'auth', token }));
|
||||||
};
|
};
|
||||||
|
|
||||||
ws.onmessage = (message) => {
|
ws.onmessage = (message) => {
|
||||||
|
|||||||
+1
-1
@@ -1,3 +1,3 @@
|
|||||||
MAJOR=0
|
MAJOR=0
|
||||||
MINOR=4
|
MINOR=4
|
||||||
PATCH=1
|
PATCH=2
|
||||||
|
|||||||
Reference in New Issue
Block a user