diff --git a/front/src/Components/images/button-large.png b/front/src/Components/images/button-large.png deleted file mode 100644 index f1d52f50..00000000 Binary files a/front/src/Components/images/button-large.png and /dev/null differ diff --git a/messages/JsonMessages/ErrorApiData.ts b/messages/JsonMessages/ErrorApiData.ts new file mode 100644 index 00000000..31dd3cb4 --- /dev/null +++ b/messages/JsonMessages/ErrorApiData.ts @@ -0,0 +1,21 @@ +import { z } from "zod"; + +/* + * WARNING! The original file is in /messages/JsonMessages. + * All other files are automatically copied from this file on container startup / build + */ + +export const isErrorApiData = z.object({ + type: z.string(), + code: z.string(), + title: z.string(), + subtitle: z.string(), + details: z.string(), + image: z.string(), + urlToRedirect: z.optional(z.nullable(z.string())), + buttonTitle: z.optional(z.nullable(z.string())), + timeToRetry: z.optional(z.nullable(z.bigint())), + canRetryManual: z.optional(z.nullable(z.boolean())) +}); + +export type ErrorApiData = z.infer; diff --git a/pusher/src/Controller/BaseHttpController.ts b/pusher/src/Controller/BaseHttpController.ts index d12345c2..3f961c5d 100644 --- a/pusher/src/Controller/BaseHttpController.ts +++ b/pusher/src/Controller/BaseHttpController.ts @@ -1,6 +1,7 @@ import { Server } from "hyper-express"; import Response from "hyper-express/types/components/http/Response"; import axios from "axios"; +import {isErrorApiData} from "../Messages/JsonMessages/ErrorApiData"; export class BaseHttpController { constructor(protected app: Server) { @@ -31,14 +32,15 @@ export class BaseHttpController { if (axios.isAxiosError(e) && e.response) { res.status(e.response.status); - if (!e.response.data?.code) { + const errorType = isErrorApiData.safeParse(e?.response?.data); + if (!errorType.success) { res.send( "An error occurred: " + e.response.status + " " + (e.response.data && e.response.data.message ? e.response.data.message : e.response.statusText) ); - } else res.json(e.response.data); + } else res.json(errorType.data); return; } else { res.status(500); diff --git a/pusher/src/Controller/IoSocketController.ts b/pusher/src/Controller/IoSocketController.ts index 20847c74..df21d301 100644 --- a/pusher/src/Controller/IoSocketController.ts +++ b/pusher/src/Controller/IoSocketController.ts @@ -41,6 +41,7 @@ import { localWokaService } from "../Services/LocalWokaService"; import { WebSocket } from "uWebSockets.js"; import { WokaDetail } from "../Messages/JsonMessages/PlayerTextures"; import { z } from "zod"; +import {ErrorApiData, isErrorApiData} from "../Messages/JsonMessages/ErrorApiData"; /** * The object passed between the "open" and the "upgrade" methods when opening a websocket @@ -68,13 +69,21 @@ interface UpgradeData { }; } -interface UpgradeFailedData { +interface UpgradeFailedInvalidData { rejected: true; - reason: "tokenInvalid" | "textureInvalid" | "error" | null; + reason: "tokenInvalid" | "textureInvalid" | null; message: string; roomId: string; } +interface UpgradeFailedErrorData { + rejected: true; + reason: "error"; + error: ErrorApiData; +} + +type UpgradeFailedData = UpgradeFailedErrorData | UpgradeFailedInvalidData; + export class IoSocketController { private nextUserId: number = 1; @@ -314,35 +323,23 @@ export class IoSocketController { ); } catch (err) { if (Axios.isAxiosError(err)) { - if (err?.response?.status == 404 || !err?.response?.data.code) { - // If we get an HTTP 404, the token is invalid. Let's perform an anonymous login! - - console.warn( - 'Cannot find user with email "' + - (userIdentifier || "anonymous") + - '". Performing an anonymous login instead.' - ); - } else if (err?.response?.data.code) { - //OLD // If we get an HTTP 403, the world is full. We need to broadcast a special error to the client. - //OLD // we finish immediately the upgrade then we will close the socket as soon as it starts opening. - return res.upgrade( - { - rejected: true, - reason: "error", - message: err?.response?.data.code, - status: err?.response?.status, - error: err?.response?.data, - roomId, - } as UpgradeFailedData, - websocketKey, - websocketProtocol, - websocketExtensions, - context - ); - } - } else { - throw err; + const errorType = isErrorApiData.safeParse(err?.response?.data); + if(errorType.success) { + return res.upgrade( + { + rejected: true, + reason: "error", + status: err?.response?.status, + error: errorType.data, + } as UpgradeFailedData, + websocketKey, + websocketProtocol, + websocketExtensions, + context + ); + } } + throw err; } memberMessages = userData.messages; memberTags = userData.tags; @@ -487,7 +484,7 @@ export class IoSocketController { } else if (ws.reason === "textureInvalid") { socketManager.emitInvalidTextureMessage(ws); } else if (ws.reason === "error") { - socketManager.emitErrorScreenMessage(ws, ws.error as ErrorScreenMessage); + socketManager.emitErrorScreenMessage(ws, ws.error); } else { socketManager.emitConnexionErrorMessage(ws, ws.message); } diff --git a/pusher/src/Services/SocketManager.ts b/pusher/src/Services/SocketManager.ts index 0dcd5cc5..02d1c467 100644 --- a/pusher/src/Services/SocketManager.ts +++ b/pusher/src/Services/SocketManager.ts @@ -55,6 +55,7 @@ import Debug from "debug"; import { ExAdminSocketInterface } from "../Model/Websocket/ExAdminSocketInterface"; import { compressors } from "hyper-express"; import { isMapDetailsData } from "../Messages/JsonMessages/MapDetailsData"; +import {ErrorApiData} from "../Messages/JsonMessages/ErrorApiData"; const debug = Debug("socket"); @@ -644,9 +645,22 @@ export class SocketManager implements ZoneEventListener { client.send(serverToClientMessage.serializeBinary().buffer, true); } - public emitErrorScreenMessage(client: compressors.WebSocket, error: ErrorScreenMessage) { + public emitErrorScreenMessage(client: compressors.WebSocket, error: ErrorApiData) { + const errorMessage = new ErrorScreenMessage(); + errorMessage.setType(error.type); + errorMessage.setCode(error.code); + errorMessage.setTitle(error.title); + errorMessage.setSubtitle(error.subtitle); + errorMessage.setDetails(error.details); + errorMessage.setImage(error.image); + + if(error.urlToRedirect) errorMessage.setUrltoredirect(error.urlToRedirect); + if(error.buttonTitle) errorMessage.setButtontitle(error.buttonTitle); + if(!!error.canRetryManual) errorMessage.setCanretrymanual(error.canRetryManual); + if(error.timeToRetry) errorMessage.setTimetoretry(error.timeToRetry); + const serverToClientMessage = new ServerToClientMessage(); - serverToClientMessage.setErrorscreenmessage(error); + serverToClientMessage.setErrorscreenmessage(errorMessage); //if (!client.disconnecting) { client.send(serverToClientMessage.serializeBinary().buffer, true);