mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:30:45 +00:00
have worker send error back to client (#1178)
## Description: On error, send the message back to the client before closing the websocket. ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: <DISCORD USERNAME> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
@@ -453,6 +453,7 @@
|
||||
},
|
||||
"error_modal": {
|
||||
"crashed": "Game crashed!",
|
||||
"connection_error": "Connection error!",
|
||||
"paste_discord": "Please paste the following in your bug report in Discord:",
|
||||
"copy_clipboard": "Copy to clipboard",
|
||||
"copied": "Copied!",
|
||||
|
||||
@@ -99,6 +99,17 @@ export function joinLobby(
|
||||
terrainLoad,
|
||||
).then((r) => r.start());
|
||||
}
|
||||
if (message.type === "error") {
|
||||
showErrorModal(
|
||||
message.error,
|
||||
"",
|
||||
lobbyConfig.gameID,
|
||||
lobbyConfig.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
}
|
||||
};
|
||||
transport.connect(onconnect, onmessage);
|
||||
return () => {
|
||||
@@ -309,7 +320,19 @@ export class ClientGameRunner {
|
||||
this.lobby.gameStartInfo.gameID,
|
||||
this.lobby.clientID,
|
||||
true,
|
||||
translateText("error_modal.desync_notice"),
|
||||
false,
|
||||
"error_modal.desync_notice",
|
||||
);
|
||||
}
|
||||
if (message.type === "error") {
|
||||
showErrorModal(
|
||||
message.error,
|
||||
"",
|
||||
this.lobby.gameID,
|
||||
this.lobby.clientID,
|
||||
true,
|
||||
false,
|
||||
"error_modal.connection_error",
|
||||
);
|
||||
}
|
||||
if (message.type === "turn") {
|
||||
@@ -538,7 +561,8 @@ function showErrorModal(
|
||||
gameID: GameID,
|
||||
clientID: ClientID,
|
||||
closable = false,
|
||||
heading = translateText("error_modal.crashed"),
|
||||
showDiscord = true,
|
||||
heading = "error_modal.crashed",
|
||||
) {
|
||||
const errorText = `Error: ${errMsg}\nStack: ${stack}`;
|
||||
|
||||
@@ -550,7 +574,9 @@ function showErrorModal(
|
||||
|
||||
modal.id = "error-modal";
|
||||
|
||||
const content = `${translateText(heading)}\n game id: ${gameID}, client id: ${clientID}\n${translateText("error_modal.paste_discord")}\n${errorText}`;
|
||||
const discord = showDiscord ? translateText("error_modal.paste_discord") : "";
|
||||
|
||||
const content = `${discord}\n${translateText(heading)}\n game id: ${gameID}, client id: ${clientID}\n${errorText}`;
|
||||
|
||||
// Create elements
|
||||
const pre = document.createElement("pre");
|
||||
|
||||
@@ -327,8 +327,8 @@ export class Transport {
|
||||
console.log(
|
||||
`WebSocket closed. Code: ${event.code}, Reason: ${event.reason}`,
|
||||
);
|
||||
if (event.code !== 1000) {
|
||||
console.log(`reconnecting`);
|
||||
if (event.code !== 1000 && event.code !== 1002) {
|
||||
console.log(`recieved error code ${event.code}, reconnecting`);
|
||||
this.reconnect();
|
||||
}
|
||||
};
|
||||
|
||||
+10
-2
@@ -80,7 +80,8 @@ export type ServerMessage =
|
||||
| ServerStartGameMessage
|
||||
| ServerPingMessage
|
||||
| ServerDesyncMessage
|
||||
| ServerPrestartMessage;
|
||||
| ServerPrestartMessage
|
||||
| ServerErrorMessage;
|
||||
|
||||
export type ServerSyncMessage = z.infer<typeof ServerTurnMessageSchema>;
|
||||
export type ServerStartGameMessage = z.infer<
|
||||
@@ -89,6 +90,7 @@ export type ServerStartGameMessage = z.infer<
|
||||
export type ServerPingMessage = z.infer<typeof ServerPingMessageSchema>;
|
||||
export type ServerDesyncMessage = z.infer<typeof ServerDesyncSchema>;
|
||||
export type ServerPrestartMessage = z.infer<typeof ServerPrestartMessageSchema>;
|
||||
export type ServerErrorMessage = z.infer<typeof ServerErrorSchema>;
|
||||
export type ClientSendWinnerMessage = z.infer<typeof ClientSendWinnerSchema>;
|
||||
export type ClientPingMessage = z.infer<typeof ClientPingMessageSchema>;
|
||||
export type ClientIntentMessage = z.infer<typeof ClientIntentMessageSchema>;
|
||||
@@ -330,7 +332,7 @@ export const TurnSchema = z.object({
|
||||
// Server
|
||||
|
||||
const ServerBaseMessageSchema = z.object({
|
||||
type: z.enum(["turn", "ping", "prestart", "start", "desync"]),
|
||||
type: z.enum(["turn", "ping", "prestart", "start", "desync", "error"]),
|
||||
});
|
||||
|
||||
export const ServerTurnMessageSchema = ServerBaseMessageSchema.extend({
|
||||
@@ -375,12 +377,18 @@ export const ServerDesyncSchema = ServerBaseMessageSchema.extend({
|
||||
yourHash: z.number().optional(),
|
||||
});
|
||||
|
||||
export const ServerErrorSchema = ServerBaseMessageSchema.extend({
|
||||
type: z.literal("error"),
|
||||
error: z.string(),
|
||||
});
|
||||
|
||||
export const ServerMessageSchema = z.discriminatedUnion("type", [
|
||||
ServerTurnMessageSchema,
|
||||
ServerPrestartMessageSchema,
|
||||
ServerStartGameMessageSchema,
|
||||
ServerPingMessageSchema,
|
||||
ServerDesyncSchema,
|
||||
ServerErrorSchema,
|
||||
]);
|
||||
|
||||
// Client
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
Intent,
|
||||
PlayerRecord,
|
||||
ServerDesyncSchema,
|
||||
ServerErrorMessage,
|
||||
ServerPrestartMessageSchema,
|
||||
ServerStartGameMessageSchema,
|
||||
ServerTurnMessageSchema,
|
||||
@@ -195,7 +196,16 @@ export class GameServer {
|
||||
this.log.error("Failed to parse client message", error, {
|
||||
clientID: client.clientID,
|
||||
});
|
||||
client.ws.close(1002, "ClientMessageSchema");
|
||||
client.ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error: error.toString(),
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
// Add a small delay before closing the connection to ensure the error message is received
|
||||
setTimeout(() => {
|
||||
client.ws.close(1002, "ClientMessageSchema");
|
||||
}, 100);
|
||||
return;
|
||||
}
|
||||
const clientMsg = parsed.data;
|
||||
@@ -543,11 +553,20 @@ export class GameServer {
|
||||
clientID: client.clientID,
|
||||
persistentID: client.persistentID,
|
||||
});
|
||||
client.ws.close(1000, "Kicked from game");
|
||||
this.activeClients = this.activeClients.filter(
|
||||
(c) => c.clientID !== clientID,
|
||||
client.ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error: "Kicked from game (you may have been playing on another tab)",
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
this.kickedClients.add(clientID);
|
||||
// Add a small delay before closing the connection to ensure the error message is received
|
||||
setTimeout(() => {
|
||||
client.ws.close(1000, "Kicked from game");
|
||||
this.activeClients = this.activeClients.filter(
|
||||
(c) => c.clientID !== clientID,
|
||||
);
|
||||
this.kickedClients.add(clientID);
|
||||
}, 100);
|
||||
} else {
|
||||
this.log.warn(`cannot kick client, not found in game`, {
|
||||
clientID,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
ClientJoinMessageSchema,
|
||||
GameRecord,
|
||||
GameRecordSchema,
|
||||
ServerErrorMessage,
|
||||
} from "../core/Schemas";
|
||||
import { CreateGameInputSchema, GameInputSchema } from "../core/WorkerSchemas";
|
||||
import { archive, readGameRecord } from "./Archive";
|
||||
@@ -300,6 +301,12 @@ export function startWorker() {
|
||||
if (!parsed.success) {
|
||||
const error = z.prettifyError(parsed.error);
|
||||
log.warn("Error parsing join message client", error);
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error: error.toString(),
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
ws.close(1002, "ClientJoinMessageSchema");
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user