const WebSocket = require("ws"); /** * Forwards WebSocket messages between browser clients (/robot) * and a target WebSocket server (behind a firewall). * * @param {WebSocket.Server} wssInput - Local WebSocket server for browser clients * @param {string} targetUrl - URL of target WebSocket server, e.g. "wss://internal.local:8080" */ function setupCommandForwarding(wssInput, targetUrl) { let targetSocket; const clients = new Set(); function connectTarget() { console.log(`🔌 Connecting to target server: ${targetUrl}`); targetSocket = new WebSocket(targetUrl); targetSocket.on("open", () => { console.log("✅ Connected to target server"); }); targetSocket.on("message", (msg) => { const data = msg.toString(); if (data !== "Ping") { console.log("⬅️ Message from target:", data); } // Broadcast to all connected browsers for (const client of clients) { if (client.readyState === WebSocket.OPEN) { client.send(data); } } }); targetSocket.on("close", () => { console.warn("⚠️ Target connection closed. Reconnecting in 5s..."); setTimeout(connectTarget, 5000); }); targetSocket.on("error", (err) => { console.error("❌ Target connection error:", err.message); }); } connectTarget(); // When a browser connects to /robot wssInput.on("connection", (ws, req) => { console.log("🤖 Browser connected:", req.socket.remoteAddress); clients.add(ws); ws.on("message", (msg) => { const data = msg.toString(); console.log("➡️ From browser → target:", data); if (targetSocket?.readyState === WebSocket.OPEN) { targetSocket.send(data); } else { console.warn("⚠️ Target not connected. Message dropped."); } }); ws.on("close", () => { clients.delete(ws); console.log("🔌 Browser disconnected"); }); ws.on("error", (err) => { console.error("❌ Browser socket error:", err.message); }); }); } module.exports = { setupCommandForwarding };