From 7b5e0a1aa6cbe805b924e16eba2a4ada5972b6df Mon Sep 17 00:00:00 2001 From: abdou6666 Date: Thu, 1 May 2025 16:48:03 +0100 Subject: [PATCH] fix: retries,acktimeout configuration socketio --- frontend/src/pages/api/config.ts | 20 ++++++++++++------ frontend/src/utils/env.ts | 27 ++++++++++++++++++++++++ frontend/src/websocket/SocketIoClient.ts | 10 ++++----- widget/src/providers/ChatProvider.tsx | 24 +++++++++++++-------- widget/src/types/config.types.ts | 2 +- widget/src/utils/SocketIoClient.ts | 7 +++--- 6 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 frontend/src/utils/env.ts diff --git a/frontend/src/pages/api/config.ts b/frontend/src/pages/api/config.ts index fe3653c5..42ec4f23 100644 --- a/frontend/src/pages/api/config.ts +++ b/frontend/src/pages/api/config.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. @@ -8,6 +8,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import { parseEnvBoolean, parseEnvNumber } from "@/utils/env"; + type ResponseData = { apiUrl: string; ssoEnabled: boolean; @@ -18,11 +20,15 @@ export default function handler( req: NextApiRequest, res: NextApiResponse, ) { - res.status(200).json({ + const MB = 1024 * 1024; + const config: ResponseData = { apiUrl: process.env.NEXT_PUBLIC_API_ORIGIN || "http://localhost:4000", - ssoEnabled: process.env.NEXT_PUBLIC_SSO_ENABLED === "true" || false, - maxUploadSize: process.env.UPLOAD_MAX_SIZE_IN_BYTES - ? Number(process.env.UPLOAD_MAX_SIZE_IN_BYTES) - : 20 * 1024 * 1024, // 20 MB in bytes - }); + ssoEnabled: parseEnvBoolean(process.env.NEXT_PUBLIC_SSO_ENABLED, false), + maxUploadSize: parseEnvNumber( + process.env.UPLOAD_MAX_SIZE_IN_BYTES, + 20 * MB, + ), + }; + + res.status(200).json(config); } diff --git a/frontend/src/utils/env.ts b/frontend/src/utils/env.ts new file mode 100644 index 00000000..6783d2de --- /dev/null +++ b/frontend/src/utils/env.ts @@ -0,0 +1,27 @@ +/* + * Copyright © 2025 Hexastack. All rights reserved. + * + * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: + * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. + * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). + */ + +export const parseEnvNumber = ( + value: string | undefined, + fallback: number, +): number => { + const parsed = Number(value); + + return isNaN(parsed) ? fallback : parsed; +}; +// Utility to parse environment variable as boolean +export const parseEnvBoolean = ( + value: string | undefined, + fallback: boolean, +): boolean => { + if (typeof value !== "string") { + return fallback; + } + + return value.toLowerCase() === "true"; +}; diff --git a/frontend/src/websocket/SocketIoClient.ts b/frontend/src/websocket/SocketIoClient.ts index 1829d4cb..bb8ff2aa 100644 --- a/frontend/src/websocket/SocketIoClient.ts +++ b/frontend/src/websocket/SocketIoClient.ts @@ -1,12 +1,12 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). */ -import { io, Socket, ManagerOptions, SocketOptions } from "socket.io-client"; +import { io, ManagerOptions, Socket, SocketOptions } from "socket.io-client"; import { IOIncomingMessage, IOOutgoingMessage } from "./types/io-message"; @@ -19,19 +19,19 @@ export class SocketIoClient { */ static defaultConfig: SocketIoClientConfig = { // Socket options - ackTimeout: 1000, // auth: undefined, - retries: 3, // Manager options autoConnect: true, // parser: undefined, - // randomizationFactor:0.5, + randomizationFactor: 0.5, reconnection: true, reconnectionAttempts: 100, reconnectionDelay: 1000, reconnectionDelayMax: 5000, timeout: 20000, + retries: 0, + ackTimeout: 15_000, // Low Level Options addTrailingSlash: true, // eg: https://domain.path/ => https://domain.path/ diff --git a/widget/src/providers/ChatProvider.tsx b/widget/src/providers/ChatProvider.tsx index 77f51bb0..0ab9220f 100644 --- a/widget/src/providers/ChatProvider.tsx +++ b/widget/src/providers/ChatProvider.tsx @@ -293,17 +293,23 @@ const ChatProvider: React.FC<{ : OutgoingMessageState.sending, ); setMessage(""); - const sentMessage = await socketCtx.socket.post( - `/webhook/${config.channel}/`, - { - data: { - ...data, - author: data.author ?? participants[1].id, + try { + // when the request timeout it throws exception & break frontend + const sentMessage = await socketCtx.socket.post( + `/webhook/${config.channel}/`, + { + data: { + ...data, + author: data.author ?? participants[1].id, + }, }, - }, - ); + ); - handleNewIOMessage(sentMessage.body); + handleNewIOMessage(sentMessage.body); + } catch (error) { + // eslint-disable-next-line no-console + console.error("Unable to subscribe user", error); + } }; const handleSubscription = useCallback( async (firstName?: string, lastName?: string) => { diff --git a/widget/src/types/config.types.ts b/widget/src/types/config.types.ts index 694a9442..19f2c154 100644 --- a/widget/src/types/config.types.ts +++ b/widget/src/types/config.types.ts @@ -1,5 +1,5 @@ /* - * Copyright © 2024 Hexastack. All rights reserved. + * Copyright © 2025 Hexastack. All rights reserved. * * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. diff --git a/widget/src/utils/SocketIoClient.ts b/widget/src/utils/SocketIoClient.ts index 958a8d77..0aedac5f 100644 --- a/widget/src/utils/SocketIoClient.ts +++ b/widget/src/utils/SocketIoClient.ts @@ -29,19 +29,19 @@ export class SocketIoClient { */ static defaultConfig: SocketIoClientConfig = { // Socket options - ackTimeout: 1000, // auth: undefined, - retries: 3, // Manager options autoConnect: true, // parser: undefined, - // randomizationFactor:0.5, + randomizationFactor: 0.5, reconnection: true, reconnectionAttempts: 100, reconnectionDelay: 1000, reconnectionDelayMax: 5000, timeout: 20000, + retries: 0, + ackTimeout: 15_000, // Low Level Options addTrailingSlash: true, // eg: https://domain.path/ => https://domain.path/ @@ -154,6 +154,7 @@ export class SocketIoClient { if (response.statusCode >= 200 && response.statusCode < 300) { return response; } + throw new Error( `Request failed with status code ${response.statusCode}: ${JSON.stringify( response.body,