|
const WebSocket = require('ws'); |
|
const net = require('net'); |
|
const process = require('process'); |
|
|
|
// Configuration |
|
const WS_HOST = process.argv[2] || '127.0.0.1:8090'; |
|
const [HOST, PORT] = WS_HOST.split(':'); |
|
const START_PORT = 9022; |
|
|
|
// Client tracking |
|
const clients = new Map(); // identifier -> { ws, port, server, socket, lastActive } |
|
const portAllocation = new Map(); // port -> identifier |
|
const PORT_TIMEOUT = 24 * 60 * 60 * 1000; // 24 hours |
|
|
|
const wss = new WebSocket.Server({ host: HOST, port: PORT }); |
|
console.log(`WebSocket server running on ws://${HOST}:${PORT}`); |
|
|
|
// Cleanup old ports |
|
setInterval(() => { |
|
const now = Date.now(); |
|
for (const [identifier, client] of clients.entries()) { |
|
if (now - client.lastActive > PORT_TIMEOUT) { |
|
console.log(`Releasing port ${client.port} from ${identifier} (inactive 24h)`); |
|
client.server.close(); |
|
portAllocation.delete(client.port); |
|
clients.delete(identifier); |
|
} |
|
} |
|
}, 60 * 60 * 1000); // Check hourly |
|
|
|
wss.on('connection', (ws) => { |
|
ws.on('message', (message) => { |
|
try { |
|
const msg = JSON.parse(message); |
|
|
|
// Handle registration |
|
if (msg.type === 'register' && msg.identifier) { |
|
registerClient(ws, msg.identifier); |
|
return; |
|
} |
|
|
|
// Handle data forwarding |
|
const client = clients.get(msg.identifier); |
|
if (client && client.ws === ws) { |
|
client.lastActive = Date.now(); |
|
if (msg.type === 'data' && client.socket) { |
|
client.socket.write(Buffer.from(msg.data, 'base64')); |
|
} |
|
} |
|
} catch (err) { |
|
console.error('Message processing error:', err); |
|
} |
|
}); |
|
|
|
ws.on('close', () => { |
|
for (const [identifier, client] of clients.entries()) { |
|
if (client.ws === ws) { |
|
console.log(`Client ${identifier} disconnected`); |
|
// Don't close the server, just mark WS as disconnected and close socket |
|
client.ws = null; |
|
if (client.socket) { |
|
client.socket.end(); |
|
client.socket = null; |
|
} |
|
} |
|
} |
|
}); |
|
}); |
|
|
|
function registerClient(ws, identifier) { |
|
// Check if this identifier already has a port assigned |
|
const existingClient = clients.get(identifier); |
|
|
|
if (existingClient) { |
|
// Reuse the existing port |
|
existingClient.ws = ws; |
|
existingClient.lastActive = Date.now(); |
|
console.log(`[${identifier}] Reconnected, using existing port ${existingClient.port}`); |
|
|
|
ws.send(JSON.stringify({ type: 'registered', port: existingClient.port })); |
|
return; |
|
} |
|
|
|
// Find available port for new client |
|
let port = START_PORT; |
|
while (portAllocation.has(port)) port++; |
|
|
|
const server = net.createServer((socket) => { |
|
const client = clients.get(identifier); |
|
if (client) { |
|
client.socket = socket; |
|
console.log(`[${identifier}] New connection on port ${port}`); |
|
} |
|
|
|
socket.on('data', (data) => { |
|
const client = clients.get(identifier); |
|
if (client && client.ws) { |
|
client.ws.send(JSON.stringify({ |
|
type: 'data', |
|
identifier, |
|
data: data.toString('base64') |
|
})); |
|
} |
|
}); |
|
|
|
socket.on('close', () => { |
|
const client = clients.get(identifier); |
|
if (client) { |
|
client.socket = null; |
|
} |
|
}); |
|
}); |
|
|
|
server.listen(port, '0.0.0.0', () => { |
|
clients.set(identifier, { ws, port, server, socket: null, lastActive: Date.now() }); |
|
portAllocation.set(port, identifier); |
|
console.log(`[${identifier}] Assigned port ${port}`); |
|
ws.send(JSON.stringify({ type: 'registered', port })); |
|
}); |
|
} |