fosrl.pangolin/server/hybridServer.ts
2025-08-13 20:48:54 -07:00

97 lines
2.9 KiB
TypeScript

import next from "next";
import express from "express";
import { parse } from "url";
import logger from "@server/logger";
import config from "@server/lib/config";
import { createWebSocketClient } from "./routers/ws/client";
import { addPeer, deletePeer } from "./routers/gerbil/peers";
import { db, exitNodes } from "./db";
import { TraefikConfigManager } from "./lib/remoteTraefikConfig";
import { tokenManager } from "./lib/tokenManager";
import { APP_VERSION } from "./lib/consts";
export async function createHybridClientServer() {
const monitor = new TraefikConfigManager();
await monitor.start();
if (
!config.getRawConfig().hybrid?.id ||
!config.getRawConfig().hybrid?.secret ||
!config.getRawConfig().hybrid?.endpoint
) {
throw new Error("Hybrid configuration is not defined");
}
// Start the token manager
await tokenManager.start();
const token = await tokenManager.getToken();
// Create client
const client = createWebSocketClient(
token,
config.getRawConfig().hybrid!.endpoint!,
{
reconnectInterval: 5000,
pingInterval: 30000,
pingTimeout: 10000
}
);
// Register message handlers
client.registerHandler("remote/peers/add", async (message) => {
const { pubKey, allowedIps } = message.data;
// TODO: we are getting the exit node twice here
// NOTE: there should only be one gerbil registered so...
const [exitNode] = await db.select().from(exitNodes).limit(1);
await addPeer(exitNode.exitNodeId, {
publicKey: pubKey,
allowedIps: allowedIps || []
});
});
client.registerHandler("remote/peers/remove", async (message) => {
const { pubKey } = message.data;
// TODO: we are getting the exit node twice here
// NOTE: there should only be one gerbil registered so...
const [exitNode] = await db.select().from(exitNodes).limit(1);
await deletePeer(exitNode.exitNodeId, pubKey);
});
client.registerHandler("remote/traefik/reload", async (message) => {
await monitor.HandleTraefikConfig();
});
// Listen to connection events
client.on("connect", () => {
console.log("Connected to WebSocket server");
client.sendMessage("remoteExitNode/register", {
remoteExitNodeVersion: APP_VERSION
});
});
client.on("disconnect", () => {
console.log("Disconnected from WebSocket server");
});
client.on("message", (message) => {
console.log("Received message:", message.type, message.data);
});
// Connect to the server
try {
await client.connect();
console.log("Connection initiated");
} catch (error) {
console.error("Failed to connect:", error);
}
client.sendMessageInterval(
"remoteExitNode/ping",
{ timestamp: Date.now() / 1000 },
60000
); // send every minute
}