chess-board/src/client.ts

172 lines
3.8 KiB
TypeScript
Raw Normal View History

2022-01-08 04:08:09 +00:00
import { Coordinates } from "./boardState";
2022-01-02 18:52:39 +00:00
import { Selected } from "./Board";
2022-01-08 04:08:09 +00:00
import BoardState, { fromWireFormat } from "./boardState";
import { COLOR, PIECE } from "./primitives";
import validateBoardResponse from "./boardResponse.validator";
import validateStartMessage from "./startMessage.validator";
2022-01-08 04:08:09 +00:00
import GAME_STATE from "./gameState";
export type ValidBoardResponse = {
boardState: BoardState;
gameState: GAME_STATE;
2022-01-08 04:25:01 +00:00
};
2021-12-30 17:39:21 +00:00
export type StartGame = (
playerColor: COLOR
) => Promise<[string, BoardState] | null>;
2022-01-02 16:55:40 +00:00
2021-12-30 17:39:37 +00:00
export type MakeMove = (
selected: Selected,
destination: Coordinates,
gameId: string,
kind?: PIECE
) => Promise<void>;
2021-12-30 17:39:21 +00:00
2022-01-08 04:08:09 +00:00
export type Poll = (gameId: string) => Promise<ValidBoardResponse | null>;
2022-01-02 16:55:40 +00:00
2021-12-30 17:39:21 +00:00
export type Api = {
2021-12-30 17:39:37 +00:00
startGame: StartGame;
makeMove: MakeMove;
poll: Poll;
2021-12-30 17:39:21 +00:00
};
2022-01-02 17:19:27 +00:00
export type ApiMessage<T> = {
data: T;
gameId: string;
};
const apiMessage = <T>(gameId: string, data: T): ApiMessage<T> => {
return {
data,
gameId,
};
};
const makeBody = <T>(gameId: string, data: T): string => {
return JSON.stringify(apiMessage(gameId, data));
};
2022-01-02 17:19:27 +00:00
2021-12-30 17:39:21 +00:00
const init = (baseUri: string): Api => {
return {
startGame: startGame(baseUri),
makeMove: makeMove(baseUri),
poll: poll(baseUri),
2021-12-30 17:39:21 +00:00
};
};
const startGame = (baseUri: string): StartGame => {
return async (playerColor: COLOR): Promise<[string, BoardState] | null> => {
2021-12-30 17:39:21 +00:00
const startUri = `${baseUri}/start`;
2021-12-30 22:51:36 +00:00
const payload = {
playerColor,
};
2021-12-30 17:39:21 +00:00
const fetchOptions = {
method: "POST",
2021-12-30 17:59:44 +00:00
headers: {
Accept: "application/json",
2021-12-30 22:51:36 +00:00
"Content-Type": "application/json",
2021-12-30 17:59:44 +00:00
},
2021-12-30 22:51:36 +00:00
body: JSON.stringify(payload),
2021-12-30 17:39:21 +00:00
};
try {
const response = await fetch(startUri, fetchOptions);
if (!response.ok) {
console.error("Failed to start game,", response.status);
return null;
}
const json: unknown = await response.json();
2021-12-30 17:39:21 +00:00
const startMessage = validateStartMessage(json);
2022-01-08 04:08:09 +00:00
return [startMessage.gameId, fromWireFormat(startMessage.board)];
2021-12-30 17:39:21 +00:00
} catch (error) {
console.error("Failed to start game,", error);
return null;
}
};
};
const makeMove = (baseUri: string): MakeMove => {
2021-12-30 17:39:37 +00:00
return async (
selected: Selected,
destination: Coordinates,
gameId: string,
kind?: PIECE
): Promise<void> => {
2021-12-30 17:39:21 +00:00
const moveUri = `${baseUri}/move`;
2022-01-02 17:19:27 +00:00
const body = makeBody(gameId, {
2021-12-30 17:39:21 +00:00
piece: selected.piece,
from: selected.location,
to: destination,
kind,
2022-01-02 17:19:27 +00:00
});
2021-12-30 17:39:21 +00:00
const fetchOptions = {
method: "POST",
headers: {
2021-12-30 17:59:44 +00:00
Accept: "application/json",
2021-12-30 17:39:21 +00:00
"Content-Type": "application/json",
},
2022-01-02 17:19:27 +00:00
body,
2021-12-30 17:39:21 +00:00
};
try {
await fetch(moveUri, fetchOptions);
2021-12-30 17:39:21 +00:00
} catch (error) {
console.error("Failed to make move,", error);
}
};
};
const poll = (baseUri: string): Poll => {
return async (gameId: string) => {
const pollUri = `${baseUri}/poll/${gameId}`;
2022-01-02 16:55:40 +00:00
const fetchOptions = {
method: "GET",
2022-01-02 16:55:40 +00:00
headers: {
Accept: "application/json",
},
};
try {
const result = await fetch(pollUri, fetchOptions);
2022-01-02 16:55:40 +00:00
if (!result.ok) {
2022-01-08 03:15:30 +00:00
if (result.status >= 400 && result.status < 500) {
throw new Error("Invalid status for long poll");
}
console.error("Failed to long poll,", result.status);
2022-01-02 16:55:40 +00:00
return null;
}
if (result.status === 204) {
return null;
}
const json: unknown = await result.json();
2022-01-02 16:55:40 +00:00
2022-01-08 04:08:09 +00:00
const boardResponse = validateBoardResponse(json);
const boardState = fromWireFormat(boardResponse.boardState);
2022-01-02 16:55:40 +00:00
2022-01-08 04:08:09 +00:00
return {
boardState,
gameState: boardResponse.gameState,
};
2022-01-02 16:55:40 +00:00
} catch (error) {
console.error("Failed to long poll,", error);
throw new Error("Failed to long poll");
2022-01-02 16:55:40 +00:00
}
};
2022-01-02 16:56:39 +00:00
};
2022-01-02 16:55:40 +00:00
2021-12-30 17:39:21 +00:00
export { init };