const net = require('net'); var clients = {}; function Client(sock) { var _this = this; this.id = sock.remoteAddress; this.name = this.id; this.sock = sock; this.active = true; this.volumeControl = true; this.status = { battery: undefined, plugged: undefined, volume: undefined, lastUpdate: 0 }; this.ping = { duration: 0, lastUpdate: 0, pending: 0 }; this.sock.on('data', (data) => { var dataStr = data.toString("utf-8"); dataStr.split(/[\r\n]/).forEach(i => i.length ? _this.onData(i) : i); }); this.sock.on('close', () => { if (this.active) { delete clients[this.id]; require("./outputs.js").unregisterOutput(this.id); this.sock = null; } }); this.radios = {}; var allRadios = require("./config.js").RADIOS; for (var i in allRadios) this.radios[i] = { address: allRadios[i], state: false }; this.sendInputStates(); } Client.prototype.onData = function(data) { if (data.startsWith("HELO")) this.name = data.substr("HELO".length).trim() +" (" +this.sock.remoteAddress +")"; else if (data.startsWith("STATUS")) { data = JSON.parse(data.substr("STATUS".length)); if (data) { this.status.battery = data.battery !== undefined ? data.battery :this.status.battery; this.status.plugged = data.plugged !== undefined ? data.plugged :this.status.plugged; this.status.volume = data.volume !== undefined ? data.volume :this.status.volume; this.status.lastUpdate = Date.now(); } } else if (data.startsWith("PONG")) { if (this.ping.pending) { const now = Date.now(); this.ping = { lastUpdate: now, duration: now -this.ping.pending, pending: 0 }; this.scheduleNextPing(); } } } Client.prototype.requestPing = function() { if (this.sock) { this.ping.pending = Date.now(); this.sock.write("PING\n"); } } Client.prototype.scheduleNextPing = function() { setTimeout(() => {this.requestPing();}, 90000); // 1 min 30 sec } Client.prototype.getName = function() { return this.name; } Client.prototype.kill = function() { this.sock.destroy(); this.active = false; } Client.prototype.getInputs = function() { var result = {}; for (var i in this.radios) result[i] = this.radios[i].state; return result; } Client.prototype.sendInputStates = function() { this.sock.write("SET" +JSON.stringify(this.radios) +"\n"); } Client.prototype.setState = function(inputId, state) { if (!this.radios[inputId]) return false; if (this.radios[inputId].state !== !!state) { this.radios[inputId].state = !!state; this.sendInputStates(); } return true; } Client.prototype.getStatus = function() { return { status: this.status.lastUpdate ? this.status : undefined, ping: this.ping.lastUpdate ? { lastUpdate: this.ping.lastUpdate, duration: this.ping.duration, pending: !!this.ping.pending } : undefined }; } Client.prototype.setVolume = function(volume) { this.sock.write("SETVOL" +volume +"\n"); } function onClientConnection(sock) { var cli = new Client(sock); if (clients[cli.id]) clients[cli.id].kill(); clients[cli.id] = cli; cli.requestPing(); require("./outputs.js").registerOutput(cli.id, cli); } module.exports.init = function() { net.createServer(onClientConnection).listen(require('./config.js').TCP_PORT, require('./config.js').TCP_LISTEN); }