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 Driver target server: ${targetUrl}`); targetSocket = new WebSocket(targetUrl, { rejectUnauthorized: false }); targetSocket.on("open", () => { console.log("✅ Connected to Driver target server"); }); targetSocket.on("message", (msg) => { const data = msg.toString(); console.log("⬅️ Message from Driver to Sim:", data, "→ clients:", clients.size); // Broadcast to all connected browsers for (const client of clients) { if (client.readyState === WebSocket.OPEN) { try { client.send(data); } catch (err) { console.error("❌ Error sending to client:", err.message); } } } }); targetSocket.on("close", () => { console.warn("⚠️ Target Driver connection closed. Reconnecting in 5s..."); setTimeout(connectTarget, 5000); }); targetSocket.on("error", (err) => { console.error("❌ Target Driver 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 };