diff options
Diffstat (limited to 'frontend/src/api')
-rw-r--r-- | frontend/src/api/model.js | 31 | ||||
-rw-r--r-- | frontend/src/api/sevenWondersApi.js | 46 | ||||
-rw-r--r-- | frontend/src/api/websocket.js | 24 |
3 files changed, 59 insertions, 42 deletions
diff --git a/frontend/src/api/model.js b/frontend/src/api/model.js index eb7ad9c5..2f9fad37 100644 --- a/frontend/src/api/model.js +++ b/frontend/src/api/model.js @@ -1,15 +1,16 @@ -export class ApiError { +// @flow +export type ApiError = { message: string; details: ApiErrorDetail[]; } -export class ApiErrorDetail { +export type ApiErrorDetail = { message: string; } export type ApiGameState = "LOBBY" | "PLAYING"; -export class ApiLobby { +export type ApiLobby = { id: number; name: string; owner: ApiPlayer; @@ -20,7 +21,7 @@ export class ApiLobby { export type ApiWonderSidePickMethod = "EACH_RANDOM" | "ALL_A" | "ALL_B" | "SAME_RANDOM_FOR_ALL"; -export class ApiSettings { +export type ApiSettings = { randomSeedForTests: number; timeLimitInSeconds: number; wonderSidePickMethod: ApiWonderSidePickMethod; @@ -32,26 +33,28 @@ export class ApiSettings { wonPointsPerVictoryPerAge: Map<number, number>; } -export class ApiPlayer { +export type ApiPlayer = { username: string; displayName: string; index: number; ready: boolean; } -export class ApiTable {} +export type ApiTable = {} -export class ApiHandCard {} +export type ApiAction = {} -export class ApiCard {} +export type ApiHandCard = {} -export class ApiPreparedCard {} +export type ApiCard = {} -export class ApiPlayerTurnInfo { +export type ApiPreparedCard = {} + +export type ApiPlayerTurnInfo = { playerIndex: number; table: ApiTable; currentAge: number; - action: Action; + action: ApiAction; hand: ApiHandCard[]; neighbourGuildCards: ApiCard[]; message: string; @@ -61,15 +64,15 @@ export type ApiMoveType = "PLAY" | "PLAY_FREE" | "UPGRADE_WONDER" | "DISCARD" | export type ApiProvider = "LEFT_NEIGHBOUR" | "RIGHT_NEIGHBOUR"; export type ApiResourceType = "WOOD" | "STONE" | "ORE" | "CLAY" | "GLASS" | "PAPYRUS" | "LOOM"; -export class ApiResources { +export type ApiResources = { quantities: Map<ApiResourceType, number>; } -export class ApiBoughtResources { +export type ApiBoughtResources = { provider: ApiProvider; resources: ApiResources; } -export class ApiPlayerMove { +export type ApiPlayerMove = { type: ApiMoveType; cardName: string; boughtResources: ApiBoughtResources[]; diff --git a/frontend/src/api/sevenWondersApi.js b/frontend/src/api/sevenWondersApi.js index 1004c81e..9a68ec66 100644 --- a/frontend/src/api/sevenWondersApi.js +++ b/frontend/src/api/sevenWondersApi.js @@ -1,5 +1,7 @@ -import { createJsonStompClient, JsonStompClient, Callback } from './websocket'; -import { ApiError, ApiLobby, ApiPlayer, ApiPlayerMove, ApiPlayerTurnInfo, ApiPreparedCard, ApiTable } from './model'; +// @flow +import { createJsonStompClient } from './websocket'; +import type { JsonStompClient, SubscribeFn } from './websocket' +import type { ApiError, ApiLobby, ApiPlayer, ApiPlayerMove, ApiPlayerTurnInfo, ApiPreparedCard, ApiTable } from './model'; const wsURL = '/seven-wonders-websocket'; @@ -10,32 +12,32 @@ export class SevenWondersSession { this.client = client; } - watchErrors(callback: Callback<ApiError>): void { - return this.client.subscribe('/user/queue/errors', callback); + watchErrors(): SubscribeFn<ApiError> { + return this.client.subscriber('/user/queue/errors'); } chooseName(displayName: string): void { this.client.send('/app/chooseName', { playerName: displayName }); } - watchNameChoice(callback: Callback<ApiPlayer>): void { - return this.client.subscribe('/user/queue/nameChoice', callback); + watchNameChoice(): SubscribeFn<ApiPlayer> { + return this.client.subscriber('/user/queue/nameChoice'); } - watchGames(callback: Callback<ApiLobby[]>): void { - return this.client.subscribe('/topic/games', callback); + watchGames(): SubscribeFn<ApiLobby[]> { + return this.client.subscriber('/topic/games'); } - watchLobbyJoined(callback: Callback<Object>): void { - return this.client.subscribe('/user/queue/lobby/joined', callback); + watchLobbyJoined(): SubscribeFn<Object> { + return this.client.subscriber('/user/queue/lobby/joined'); } - watchLobbyUpdated(currentGameId: number, callback: Callback<Object>): void { - return this.client.subscribe(`/topic/lobby/${currentGameId}/updated`, callback); + watchLobbyUpdated(currentGameId: number): SubscribeFn<Object> { + return this.client.subscriber(`/topic/lobby/${currentGameId}/updated`); } - watchGameStarted(currentGameId: number, callback: Callback<Object>): void { - return this.client.subscribe(`/topic/lobby/${currentGameId}/started`, callback); + watchGameStarted(currentGameId: number): SubscribeFn<Object> { + return this.client.subscriber(`/topic/lobby/${currentGameId}/started`); } createGame(gameName: string): void { @@ -50,20 +52,20 @@ export class SevenWondersSession { this.client.send('/app/lobby/startGame'); } - watchPlayerReady(currentGameId: number, callback: Callback<string>): void { - return this.client.subscribe(`/topic/game/${currentGameId}/playerReady`, callback); + watchPlayerReady(currentGameId: number): SubscribeFn<string> { + return this.client.subscriber(`/topic/game/${currentGameId}/playerReady`); } - watchTableUpdates(currentGameId: number, callback: Callback<ApiTable>): void { - return this.client.subscribe(`/topic/game/${currentGameId}/tableUpdates`, callback); + watchTableUpdates(currentGameId: number): SubscribeFn<ApiTable> { + return this.client.subscriber(`/topic/game/${currentGameId}/tableUpdates`); } - watchPreparedMove(currentGameId: number, callback: Callback<ApiPreparedCard>): void { - return this.client.subscribe(`/topic/game/${currentGameId}/prepared`, callback); + watchPreparedMove(currentGameId: number): SubscribeFn<ApiPreparedCard> { + return this.client.subscriber(`/topic/game/${currentGameId}/prepared`); } - watchTurnInfo(callback: Callback<ApiPlayerTurnInfo>): void { - return this.client.subscribe('/user/queue/game/turnInfo', callback); + watchTurnInfo(): SubscribeFn<ApiPlayerTurnInfo> { + return this.client.subscriber('/user/queue/game/turnInfo'); } sayReady(): void { diff --git a/frontend/src/api/websocket.js b/frontend/src/api/websocket.js index d411587a..8a893a87 100644 --- a/frontend/src/api/websocket.js +++ b/frontend/src/api/websocket.js @@ -7,9 +7,9 @@ const DEFAULT_DEBUG_OPTIONS = { debug: process.env.NODE_ENV !== 'production', }; -export type Callback<T> = (value: T) => void; - -export type Callable = () => void; +export type Callback<T> = (value?: T) => void; +export type UnsubscribeFn = () => void; +export type SubscribeFn<T> = (callback: Callback<T>) => UnsubscribeFn; export class JsonStompClient { client: Client; @@ -24,16 +24,28 @@ export class JsonStompClient { }); } - subscribe<T>(path: string, callback: Callback<T>): Callable { + subscribe<T>(path: string, callback: Callback<T>): UnsubscribeFn { const socketSubscription: Subscription = this.client.subscribe(path, (frame: Frame) => { // not all frames have a JSON body - const value = frame && frame.body && JSON.parse(frame.body); + const value: T = frame && JsonStompClient.parseBody(frame); callback(value); }); return () => socketSubscription.unsubscribe(); } - send(url: string, body: Object) { + static parseBody<T>(frame: Frame): T | void { + try { + return frame.body && JSON.parse(frame.body); + } catch (jsonParseError) { + throw new Error('Cannot parse websocket message as JSON: ' + jsonParseError.message); + } + } + + subscriber<T>(path: string): SubscribeFn<T> { + return (callback: Callback<T>) => this.subscribe(path, callback); + } + + send(url: string, body?: Object) { const strBody = body ? JSON.stringify(body) : ''; this.client.send(url, strBody); } |