diff --git a/server/private/routers/remoteExitNode/exitNodeEvents.ts b/server/private/routers/remoteExitNode/exitNodeEvents.ts new file mode 100644 index 000000000..ee5c753e4 --- /dev/null +++ b/server/private/routers/remoteExitNode/exitNodeEvents.ts @@ -0,0 +1,23 @@ +/* + * This file is part of a proprietary work. + * + * Copyright (c) 2025-2026 Fossorial, Inc. + * All rights reserved. + * + * This file is licensed under the Fossorial Commercial License. + * You may not use this file except in compliance with the License. + * Unauthorized use, copying, modification, or distribution is strictly prohibited. + * + * This file is not licensed under the AGPLv3. + */ + +import { EventEmitter } from "events"; + +export interface ExitNodeOnlineEvent { + exitNodeId: number; + endpoint: string; +} + +export const EXIT_NODE_ONLINE_EVENT = "exit-node-online"; + +export const exitNodeEvents = new EventEmitter(); diff --git a/server/private/routers/remoteExitNode/exitNodeReconnectScheduler.ts b/server/private/routers/remoteExitNode/exitNodeReconnectScheduler.ts index 5d920fd3f..8e4d1158a 100644 --- a/server/private/routers/remoteExitNode/exitNodeReconnectScheduler.ts +++ b/server/private/routers/remoteExitNode/exitNodeReconnectScheduler.ts @@ -17,6 +17,22 @@ import { eq } from "drizzle-orm"; import logger from "@server/logger"; import redisManager from "#private/lib/redis"; import { sendToClient } from "../ws"; +import { + exitNodeEvents, + EXIT_NODE_ONLINE_EVENT, + ExitNodeOnlineEvent +} from "./exitNodeEvents"; + +exitNodeEvents.on( + EXIT_NODE_ONLINE_EVENT, + ({ exitNodeId, endpoint }: ExitNodeOnlineEvent) => { + scheduleExitNodeReconnect(exitNodeId, endpoint).catch((error) => { + logger.error("Failed to schedule exit node reconnect", { + error + }); + }); + } +); const INITIAL_DELAY_MS = 15 * 1000; // 15 seconds before first check const CHECK_INTERVAL_MS = 10 * 1000; // Check every 10 seconds diff --git a/server/private/routers/remoteExitNode/handleRemoteExitNodePingMessage.ts b/server/private/routers/remoteExitNode/handleRemoteExitNodePingMessage.ts index 14a777684..fcb094c5e 100644 --- a/server/private/routers/remoteExitNode/handleRemoteExitNodePingMessage.ts +++ b/server/private/routers/remoteExitNode/handleRemoteExitNodePingMessage.ts @@ -16,7 +16,7 @@ import { MessageHandler } from "@server/routers/ws"; import { RemoteExitNode } from "@server/db"; import { eq } from "drizzle-orm"; import logger from "@server/logger"; -import { scheduleExitNodeReconnect } from "./exitNodeReconnectScheduler"; +import { exitNodeEvents, EXIT_NODE_ONLINE_EVENT } from "./exitNodeEvents"; /** * Handles ping messages from clients and responds with pong @@ -60,13 +60,9 @@ export const handleRemoteExitNodePingMessage: MessageHandler = async ( !currentExitNode.online && currentExitNode.endpoint ) { - scheduleExitNodeReconnect( - remoteExitNode.exitNodeId, - currentExitNode.endpoint - ).catch((error) => { - logger.error("Failed to schedule exit node reconnect", { - error - }); + exitNodeEvents.emit(EXIT_NODE_ONLINE_EVENT, { + exitNodeId: remoteExitNode.exitNodeId, + endpoint: currentExitNode.endpoint }); } } catch (error) {