Refactor request messages

This commit is contained in:
sepia 2025-07-22 20:58:13 -05:00
parent 904a9f973f
commit e8bfdaaa30
3 changed files with 195 additions and 306 deletions

View File

@ -17,51 +17,63 @@ document.addEventListener('htmx:wsConfigSend', function (e) {
}; };
} else if (e.target.id == 'takeback-button') { } else if (e.target.id == 'takeback-button') {
e.detail.parameters = { e.detail.parameters = {
type: 'request_takeback', type: 'takeback',
action: 'request',
}; };
} else if (e.target.id == 'accept-takeback-button') { } else if (e.target.id == 'accept-takeback-button') {
e.detail.parameters = { e.detail.parameters = {
type: 'accept_takeback', type: 'takeback',
action: 'accept',
}; };
} else if (e.target.id == 'decline-takeback-button') { } else if (e.target.id == 'decline-takeback-button') {
e.detail.parameters = { e.detail.parameters = {
type: 'decline_takeback', type: 'takeback',
}; action: 'decline',
} else if (e.target.id == 'draw-button') {
e.detail.parameters = {
type: 'request_draw',
};
} else if (e.target.id == 'accept-draw-button') {
e.detail.parameters = {
type: 'accept_draw',
};
} else if (e.target.id == 'decline-draw-button') {
e.detail.parameters = {
type: 'decline_draw',
};
} else if (e.target.id == 'rematch-button') {
e.detail.parameters = {
type: 'request_rematch',
};
} else if (e.target.id == 'accept-rematch-button') {
e.detail.parameters = {
type: 'accept_rematch',
};
} else if (e.target.id == 'decline-rematch-button') {
e.detail.parameters = {
type: 'decline_rematch',
}; };
} else if (e.target.id == 'cancel-takeback-request-button') { } else if (e.target.id == 'cancel-takeback-request-button') {
e.detail.parameters = { e.detail.parameters = {
type: 'cancel_takeback_request', type: 'takeback',
action: 'cancel',
};
} else if (e.target.id == 'draw-button') {
e.detail.parameters = {
type: 'draw',
action: 'request',
};
} else if (e.target.id == 'accept-draw-button') {
e.detail.parameters = {
type: 'draw',
action: 'accept',
};
} else if (e.target.id == 'decline-draw-button') {
e.detail.parameters = {
type: 'draw',
action: 'decline',
}; };
} else if (e.target.id == 'cancel-draw-request-button') { } else if (e.target.id == 'cancel-draw-request-button') {
e.detail.parameters = { e.detail.parameters = {
type: 'cancel_draw_request', type: 'draw',
action: 'cancel',
};
} else if (e.target.id == 'rematch-button') {
e.detail.parameters = {
type: 'rematch',
action: 'request',
};
} else if (e.target.id == 'accept-rematch-button') {
e.detail.parameters = {
type: 'rematch',
action: 'accept',
};
} else if (e.target.id == 'decline-rematch-button') {
e.detail.parameters = {
type: 'rematch',
action: 'decline',
}; };
} else if (e.target.id == 'cancel-rematch-request-button') { } else if (e.target.id == 'cancel-rematch-request-button') {
e.detail.parameters = { e.detail.parameters = {
type: 'cancel_rematch_request', type: 'rematch',
action: 'cancel',
}; };
} }
}); });

View File

@ -1,20 +1,13 @@
export type ActionType = 'request' | 'accept' | 'decline' | 'cancel';
export interface Message { export interface Message {
type: type:
| 'make_move' | 'make_move'
| 'resign' | 'resign'
| 'request_takeback' | 'takeback'
| 'accept_takeback' | 'draw'
| 'decline_takeback' | 'rematch'
| 'request_draw' | 'redirect_to_game';
| 'accept_draw'
| 'decline_draw'
| 'request_rematch'
| 'accept_rematch'
| 'decline_rematch'
| 'redirect_to_game'
| 'cancel_takeback_request'
| 'cancel_draw_request'
| 'cancel_rematch_request';
} }
export interface MakeMoveMessage extends Message { export interface MakeMoveMessage extends Message {
@ -24,30 +17,18 @@ export interface MakeMoveMessage extends Message {
export interface ResignationMessage extends Message {} export interface ResignationMessage extends Message {}
export interface RequestTakebackMessage extends Message {} export interface TakebackMessage extends Message {
action: ActionType;
}
export interface AcceptTakebackMessage extends Message {} export interface DrawMessage extends Message {
action: ActionType;
}
export interface DeclineTakebackMessage extends Message {} export interface RematchMessage extends Message {
action: ActionType;
export interface RequestDrawMessage extends Message {} }
export interface AcceptDrawMessage extends Message {}
export interface DeclineDrawMessage extends Message {}
export interface RequestRematchMessage extends Message {}
export interface AcceptRematchMessage extends Message {}
export interface DeclineRematchMessage extends Message {}
export interface RedirectToGameMessage extends Message { export interface RedirectToGameMessage extends Message {
gameId: string; gameId: string;
} }
export interface CancelTakebackRequestMessage extends Message {}
export interface CancelDrawRequestMessage extends Message {}
export interface CancelRematchRequestMessage extends Message {}

View File

@ -6,19 +6,10 @@ import {
Message, Message,
MakeMoveMessage, MakeMoveMessage,
ResignationMessage, ResignationMessage,
RequestTakebackMessage, TakebackMessage,
AcceptTakebackMessage, DrawMessage,
DeclineTakebackMessage, RematchMessage,
RequestDrawMessage,
AcceptDrawMessage,
DeclineDrawMessage,
RequestRematchMessage,
AcceptRematchMessage,
DeclineRematchMessage,
RedirectToGameMessage, RedirectToGameMessage,
CancelTakebackRequestMessage,
CancelDrawRequestMessage,
CancelRematchRequestMessage,
} from './messages'; } from './messages';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@ -271,58 +262,16 @@ class GameServer {
this.handleResignation(conn, message as ResignationMessage); this.handleResignation(conn, message as ResignationMessage);
break; break;
} }
case 'request_takeback': { case 'takeback': {
this.handleRequestTakeback(conn, message as RequestTakebackMessage); this.handleTakebackMessage(conn, message as TakebackMessage);
break; break;
} }
case 'accept_takeback': { case 'draw': {
this.handleAcceptTakeback(conn, message as AcceptTakebackMessage); this.handleDrawMessage(conn, message as DrawMessage);
break; break;
} }
case 'decline_takeback': { case 'rematch': {
this.handleDeclineTakeback(conn, message as DeclineTakebackMessage); this.handleRematchMessage(conn, message as RematchMessage);
break;
}
case 'request_draw': {
this.handleRequestDraw(conn, message as RequestDrawMessage);
break;
}
case 'accept_draw': {
this.handleAcceptDraw(conn, message as AcceptDrawMessage);
break;
}
case 'decline_draw': {
this.handleDeclineDraw(conn, message as DeclineDrawMessage);
break;
}
case 'request_rematch': {
this.handleRequestRematch(conn, message as RequestRematchMessage);
break;
}
case 'accept_rematch': {
this.handleAcceptRematch(conn, message as AcceptRematchMessage);
break;
}
case 'decline_rematch': {
this.handleDeclineRematch(conn, message as DeclineRematchMessage);
break;
}
case 'cancel_takeback_request': {
this.handleCancelTakebackRequest(
conn,
message as CancelTakebackRequestMessage,
);
break;
}
case 'cancel_draw_request': {
this.handleCancelDrawRequest(conn, message as CancelDrawRequestMessage);
break;
}
case 'cancel_rematch_request': {
this.handleCancelRematchRequest(
conn,
message as CancelRematchRequestMessage,
);
break; break;
} }
} }
@ -411,18 +360,133 @@ class GameServer {
console.log(`Player ${conn.id} resigned from game ${this.id}`); console.log(`Player ${conn.id} resigned from game ${this.id}`);
} }
private handleRequestTakeback( private handleTakebackMessage(
conn: PlayerConnection, conn: PlayerConnection,
message: RequestTakebackMessage, message: TakebackMessage,
): void { ): void {
if (this.gomoku.status !== 'playing') { if (this.gomoku.status !== 'playing') {
conn.sendMessage( conn.sendMessage(
'error', 'error',
'You can only request a takeback in an active game.', 'You can only perform this action in an active game.',
); );
return; return;
} }
switch (message.action) {
case 'request':
this.handleRequestTakeback(conn);
break;
case 'accept':
if (!this.takebackRequesterId) {
conn.sendMessage('error', 'No takeback has been requested.');
return;
}
this.handleAcceptTakeback();
break;
case 'decline':
if (!this.takebackRequesterId) {
conn.sendMessage('error', 'No takeback has been requested.');
return;
}
this.handleDeclineTakeback();
break;
case 'cancel':
if (this.takebackRequesterId !== conn.id) {
conn.sendMessage(
'error',
'You are not the one who requested a takeback.',
);
return;
}
this.handleCancelTakebackRequest();
break;
}
}
private handleDrawMessage(
conn: PlayerConnection,
message: DrawMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only perform this action in an active game.',
);
return;
}
switch (message.action) {
case 'request':
this.handleRequestDraw(conn);
break;
case 'accept':
if (!this.drawRequesterId) {
conn.sendMessage('error', 'No draw has been requested.');
return;
}
this.handleAcceptDraw();
break;
case 'decline':
if (!this.drawRequesterId) {
conn.sendMessage('error', 'No draw has been requested.');
return;
}
this.handleDeclineDraw();
break;
case 'cancel':
if (this.drawRequesterId !== conn.id) {
conn.sendMessage(
'error',
'You are not the one who requested a draw.',
);
return;
}
this.handleCancelDrawRequest();
break;
}
}
private handleRematchMessage(
conn: PlayerConnection,
message: RematchMessage,
): void {
if (this.gomoku.status !== 'finished') {
conn.sendMessage(
'error',
'You can only perform this action in a finished game.',
);
return;
}
switch (message.action) {
case 'request':
this.handleRequestRematch(conn);
break;
case 'accept':
if (!this.rematchRequesterId) {
conn.sendMessage('error', 'No rematch has been requested.');
return;
}
this.handleAcceptRematch();
break;
case 'decline':
if (!this.rematchRequesterId) {
conn.sendMessage('error', 'No rematch has been requested.');
return;
}
this.handleDeclineRematch();
break;
case 'cancel':
if (this.rematchRequesterId !== conn.id) {
conn.sendMessage(
'error',
'You are not the one who requested a rematch.',
);
return;
}
this.handleCancelRematchRequest();
break;
}
}
private handleRequestTakeback(conn: PlayerConnection): void {
if (this.gomoku.history.length === 0) { if (this.gomoku.history.length === 0) {
conn.sendMessage('error', 'There are no moves to take back.'); conn.sendMessage('error', 'There are no moves to take back.');
return; return;
@ -436,23 +500,7 @@ class GameServer {
this.broadcastButtons(); this.broadcastButtons();
} }
private handleAcceptTakeback( private handleAcceptTakeback(): void {
conn: PlayerConnection,
message: AcceptTakebackMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only accept a takeback in an active game.',
);
return;
}
if (!this.takebackRequesterId) {
conn.sendMessage('error', 'No takeback has been requested.');
return;
}
this.gomoku.undoMove(); this.gomoku.undoMove();
this.takebackRequesterId = null; this.takebackRequesterId = null;
this.broadcastBoard(); this.broadcastBoard();
@ -460,38 +508,12 @@ class GameServer {
this.broadcastTitle(); this.broadcastTitle();
} }
private handleDeclineTakeback( private handleDeclineTakeback(): void {
conn: PlayerConnection,
message: DeclineTakebackMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only decline a takeback in an active game.',
);
return;
}
if (!this.takebackRequesterId) {
conn.sendMessage('error', 'No takeback has been requested.');
return;
}
this.takebackRequesterId = null; this.takebackRequesterId = null;
this.broadcastButtons(); this.broadcastButtons();
} }
private handleRequestDraw( private handleRequestDraw(conn: PlayerConnection): void {
conn: PlayerConnection,
message: RequestDrawMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only request a draw in an active game.',
);
return;
}
if (this.takebackRequesterId) { if (this.takebackRequesterId) {
conn.sendMessage('error', 'A takeback has already been requested.'); conn.sendMessage('error', 'A takeback has already been requested.');
return; return;
@ -501,23 +523,7 @@ class GameServer {
this.broadcastButtons(); this.broadcastButtons();
} }
private handleAcceptDraw( private handleAcceptDraw(): void {
conn: PlayerConnection,
message: AcceptDrawMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only accept a draw in an active game.',
);
return;
}
if (!this.drawRequesterId) {
conn.sendMessage('error', 'No draw has been requested.');
return;
}
this.gomoku.declareDraw(); this.gomoku.declareDraw();
this.drawRequesterId = null; this.drawRequesterId = null;
this.broadcastBoard(); this.broadcastBoard();
@ -525,60 +531,17 @@ class GameServer {
this.broadcastTitle(); this.broadcastTitle();
} }
private handleDeclineDraw( private handleDeclineDraw(): void {
conn: PlayerConnection,
message: DeclineDrawMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only decline a draw in an active game.',
);
return;
}
if (!this.drawRequesterId) {
conn.sendMessage('error', 'No draw has been requested.');
return;
}
this.drawRequesterId = null; this.drawRequesterId = null;
this.broadcastButtons(); this.broadcastButtons();
} }
private handleRequestRematch( private handleRequestRematch(conn: PlayerConnection): void {
conn: PlayerConnection,
message: RequestRematchMessage,
): void {
if (this.gomoku.status !== 'finished') {
conn.sendMessage(
'error',
'You can only request a rematch in a finished game.',
);
return;
}
this.rematchRequesterId = conn.id; this.rematchRequesterId = conn.id;
this.broadcastButtons(); this.broadcastButtons();
} }
private handleAcceptRematch( private handleAcceptRematch(): void {
conn: PlayerConnection,
message: AcceptRematchMessage,
): void {
if (this.gomoku.status !== 'finished') {
conn.sendMessage(
'error',
'You can only accept a rematch in a finished game.',
);
return;
}
if (!this.rematchRequesterId) {
conn.sendMessage('error', 'No rematch has been requested.');
return;
}
const newGameId = this.webSocketHandler.createGame( const newGameId = this.webSocketHandler.createGame(
undefined, undefined,
this.whitePlayerId, this.whitePlayerId,
@ -593,89 +556,22 @@ class GameServer {
}); });
} }
private handleDeclineRematch( private handleDeclineRematch(): void {
conn: PlayerConnection,
message: DeclineRematchMessage,
): void {
if (this.gomoku.status !== 'finished') {
conn.sendMessage(
'error',
'You can only decline a rematch in a finished game.',
);
return;
}
if (!this.rematchRequesterId) {
conn.sendMessage('error', 'No rematch has been requested.');
return;
}
this.rematchRequesterId = null; this.rematchRequesterId = null;
this.broadcastButtons(); this.broadcastButtons();
} }
private handleCancelTakebackRequest( private handleCancelTakebackRequest(): void {
conn: PlayerConnection,
message: CancelTakebackRequestMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only cancel a takeback request in an active game.',
);
return;
}
if (this.takebackRequesterId !== conn.id) {
conn.sendMessage(
'error',
'You are not the one who requested a takeback.',
);
return;
}
this.takebackRequesterId = null; this.takebackRequesterId = null;
this.broadcastButtons(); this.broadcastButtons();
} }
private handleCancelDrawRequest( private handleCancelDrawRequest(): void {
conn: PlayerConnection,
message: CancelDrawRequestMessage,
): void {
if (this.gomoku.status !== 'playing') {
conn.sendMessage(
'error',
'You can only cancel a draw request in an active game.',
);
return;
}
if (this.drawRequesterId !== conn.id) {
conn.sendMessage('error', 'You are not the one who requested a draw.');
return;
}
this.drawRequesterId = null; this.drawRequesterId = null;
this.broadcastButtons(); this.broadcastButtons();
} }
private handleCancelRematchRequest( private handleCancelRematchRequest(): void {
conn: PlayerConnection,
message: CancelRematchRequestMessage,
): void {
if (this.gomoku.status !== 'finished') {
conn.sendMessage(
'error',
'You can only cancel a rematch request in a finished game.',
);
return;
}
if (this.rematchRequesterId !== conn.id) {
conn.sendMessage('error', 'You are not the one who requested a rematch.');
return;
}
this.rematchRequesterId = null; this.rematchRequesterId = null;
this.broadcastButtons(); this.broadcastButtons();
} }