Code cleanup
Much better organization and ease-of-use now that the proof of concept is established. Still an awful lot to do here, but I'm getting the hang of the whole node.js thing. Also moved the actual test functionality out to a test script so the module itself doesn't execute anything.
This commit is contained in:
238
index.js
238
index.js
@ -1,108 +1,186 @@
|
|||||||
var dgram = require('dgram');
|
var dgram = require('dgram');
|
||||||
var net = require('net');
|
var net = require('net');
|
||||||
|
const SmartBuffer = require('smart-buffer').SmartBuffer;
|
||||||
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
var server = dgram.createSocket("udp4");
|
class SLMessage extends SmartBuffer {
|
||||||
server.bind( function() {
|
constructor(senderId, messageId) {
|
||||||
server.setBroadcast(true)
|
super();
|
||||||
server.setMulticastTTL(128);
|
this.writeUInt16LE(senderId);
|
||||||
broadcastNew();
|
this.writeUInt16LE(messageId);
|
||||||
});
|
|
||||||
|
|
||||||
server.on('message', function (message, remote) {
|
this._wroteSize = false;
|
||||||
console.log('Got a response.');
|
|
||||||
var server = {
|
|
||||||
address: remote.address,
|
|
||||||
type: message.readInt32LE(0),
|
|
||||||
port: message.readInt16LE(8),
|
|
||||||
gatewayType: message.readUInt8(10),
|
|
||||||
gatewaySubtype: message.readUInt8(11),
|
|
||||||
gatewayName: message.toString('utf8', 12, 28)
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log(' type: ' + server.type + ', host: ' + server.address + ':' + server.port + ', identified as ' + server.gatewayName);
|
|
||||||
if (server.type === 2) {
|
|
||||||
connectTo(server);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
function broadcastNew() {
|
toBuffer() {
|
||||||
var message = new Uint8Array(8);
|
if (this._wroteSize === false) {
|
||||||
message[0] = 1;
|
this.insertInt32LE(this.length - 4, 4);
|
||||||
server.send(message, 0, message.length, 1444, "255.255.255.255");
|
this._wroteSize = true;
|
||||||
console.log("Looking for ScreenLogic hosts...");
|
} else {
|
||||||
|
this.writeInt32LE(this.length - 8, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.toBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSLString(str) {
|
||||||
|
this.writeInt32LE(str.length);
|
||||||
|
this.writeString(str);
|
||||||
|
this.skip(4 - (str.length % 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSLBuffer(buf) {
|
||||||
|
this.writeInt32LE(buf.length);
|
||||||
|
this.writeBuffer(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
skip(num) {
|
||||||
|
if (num > 0) {
|
||||||
|
this.writeBuffer(Buffer.alloc(num));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectTo(server) {
|
class FindUnits extends EventEmitter {
|
||||||
console.log("connecting...");
|
constructor() {
|
||||||
var client = new net.Socket();
|
super();
|
||||||
client.connect(server.port, server.address, function() {
|
this.finder = dgram.createSocket('udp4');
|
||||||
|
var _this = this;
|
||||||
|
this.finder.on('message', function (message, remote) {
|
||||||
|
_this.foundServer(message, remote);
|
||||||
|
}).on('close', function() {
|
||||||
|
console.log('finder closed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
search() {
|
||||||
|
var _this = this;
|
||||||
|
this.finder.bind(function() {
|
||||||
|
_this.finder.setBroadcast(true);
|
||||||
|
_this.finder.setMulticastTTL(128);
|
||||||
|
_this.sendServerBroadcast();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foundServer(message, remote) {
|
||||||
|
console.log('Found something');
|
||||||
|
var server = {
|
||||||
|
address: remote.address,
|
||||||
|
type: message.readInt32LE(0),
|
||||||
|
port: message.readInt16LE(8),
|
||||||
|
gatewayType: message.readUInt8(10),
|
||||||
|
gatewaySubtype: message.readUInt8(11),
|
||||||
|
gatewayName: message.toString('utf8', 12, 28)
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(' type: ' + server.type + ', host: ' + server.address + ':' + server.port + ', identified as ' + server.gatewayName);
|
||||||
|
if (server.type === 2) {
|
||||||
|
this.emit('serverFound', server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendServerBroadcast() {
|
||||||
|
var message = new Uint8Array(8);
|
||||||
|
message[0] = 1;
|
||||||
|
this.finder.send(message, 0, message.length, 1444, "255.255.255.255");
|
||||||
|
console.log("Looking for ScreenLogic hosts...");
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.finder.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnitConnection extends EventEmitter {
|
||||||
|
constructor(server) {
|
||||||
|
super();
|
||||||
|
this.server = server;
|
||||||
|
|
||||||
|
this.client = new net.Socket();
|
||||||
|
var _this = this;
|
||||||
|
this.client.on('data', function(msg) {
|
||||||
|
_this.onClientMessage(msg);
|
||||||
|
}).on('close', function(had_error) {
|
||||||
|
console.log('unit connection closed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.client.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
console.log("connecting...");
|
||||||
|
var _this = this;
|
||||||
|
this.client.connect(this.server.port, this.server.address, function() {
|
||||||
|
_this.onConnected();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onConnected() {
|
||||||
console.log('connected');
|
console.log('connected');
|
||||||
|
|
||||||
console.log('sending connection string...');
|
console.log('sending init message...');
|
||||||
var buf = Buffer.from('CONNECTSERVERHOST\r\n\r\n');
|
this.client.write('CONNECTSERVERHOST\r\n\r\n');
|
||||||
client.write(buf);
|
|
||||||
|
|
||||||
console.log('sending challenge string...');
|
console.log('sending challenge message...');
|
||||||
buf = Buffer.alloc(8);
|
var buf = new SLMessage(0, 14);
|
||||||
buf.writeUInt16LE(14, 2);
|
this.client.write(buf.toBuffer());
|
||||||
client.write(buf);
|
}
|
||||||
|
|
||||||
console.log('sending login string...');
|
login() {
|
||||||
buf = Buffer.alloc(72);
|
console.log('sending login message...');
|
||||||
buf.writeUInt16LE(0);
|
var buf = new SLMessage(0, 27);
|
||||||
buf.writeUInt16LE(27, 2);
|
buf.writeInt32LE(348); // schema
|
||||||
buf.writeInt32LE(64, 4); // length
|
buf.writeInt32LE(0); // connection type
|
||||||
buf.writeInt32LE(348, 8); // schema
|
buf.writeSLString('ScreenLogicConnect library'); // version
|
||||||
buf.writeInt32LE(0, 12); // connection type
|
buf.writeSLBuffer(Buffer.alloc(16)); // encoded password. empty/unused for local connections
|
||||||
var name = 'ScreenLogicConnect library';
|
buf.writeInt32LE(2); // procID
|
||||||
buf.writeInt32LE(name.length, 16);
|
this.client.write(buf.toBuffer());
|
||||||
buf.write(name, 20);
|
}
|
||||||
var pos = 20 + name.length;
|
|
||||||
for (var i = 0; i < 4 - (name.length % 4); i++) {
|
|
||||||
buf.writeUInt8(0, 20 + name.length + i);
|
|
||||||
pos = pos + 1;
|
|
||||||
}
|
|
||||||
buf.writeInt32LE(16, pos);
|
|
||||||
pos += 4;
|
|
||||||
pos += 16;
|
|
||||||
buf.writeInt32LE(2, pos);
|
|
||||||
client.write(buf);
|
|
||||||
|
|
||||||
|
getPoolStatus() {
|
||||||
console.log('sending pool status query...');
|
console.log('sending pool status query...');
|
||||||
buf = Buffer.alloc(12);
|
var buf = new SLMessage(0, 12526);
|
||||||
buf.writeUInt16LE(12526, 2);
|
buf.writeInt32LE(0);
|
||||||
buf.writeInt32LE(4, 4);
|
this.client.write(buf.toBuffer());
|
||||||
client.write(buf);
|
}
|
||||||
|
|
||||||
|
parsePoolStatus(msg) {
|
||||||
|
// todo: actually parse the message
|
||||||
|
this.emit('poolStatus', {});
|
||||||
|
}
|
||||||
|
|
||||||
|
getControllerConfig() {
|
||||||
console.log('sending controller config query...');
|
console.log('sending controller config query...');
|
||||||
buf = Buffer.alloc(16);
|
var buf = new SLMessage(0, 12532);
|
||||||
buf.writeUInt16LE(12532, 2);
|
buf.writeInt32LE(0);
|
||||||
buf.writeInt32LE(8, 4);
|
buf.writeInt32LE(0);
|
||||||
client.write(buf);
|
this.client.write(buf.toBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(function() {
|
parseControllerConfig(msg) {
|
||||||
console.log('destroying');
|
// todo: actually parse the message
|
||||||
client.destroy();
|
this.emit('controllerConfig', {});
|
||||||
}, 3000);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
client.on('close', function() {
|
onClientMessage(msg) {
|
||||||
console.log('closed');
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('data', function(msg) {
|
|
||||||
console.log('received message of length ' + msg.length);
|
console.log('received message of length ' + msg.length);
|
||||||
var msgType = msg.readInt16LE(2);
|
var msgType = msg.readInt16LE(2);
|
||||||
if (msgType === 15) {
|
if (msgType === 15) {
|
||||||
console.log(" it's a challenge response");
|
console.log(" it's a challenge response");
|
||||||
|
this.login();
|
||||||
} else if (msgType === 28) {
|
} else if (msgType === 28) {
|
||||||
console.log(" it's a login response");
|
console.log(" it's a login response");
|
||||||
|
this.emit('loggedIn');
|
||||||
} else if (msgType === 12527) {
|
} else if (msgType === 12527) {
|
||||||
console.log(" it's pool status");
|
console.log(" it's pool status");
|
||||||
|
this.parsePoolStatus(msg);
|
||||||
} else if (msgType === 12533) {
|
} else if (msgType === 12533) {
|
||||||
console.log(" it's controller configuration");
|
console.log(" it's controller configuration");
|
||||||
|
this.parseControllerConfig(msg);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* debug print full buffer contents:
|
/* debug print full buffer contents:
|
||||||
@ -110,3 +188,9 @@ for (const value of buf.values()) {
|
|||||||
console.log(value.toString(16));
|
console.log(value.toString(16));
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
FindUnits,
|
||||||
|
SLMessage,
|
||||||
|
UnitConnection
|
||||||
|
}
|
||||||
|
18
test.js
Executable file
18
test.js
Executable file
@ -0,0 +1,18 @@
|
|||||||
|
const ScreenLogic = require('./index');
|
||||||
|
|
||||||
|
var finder = new ScreenLogic.FindUnits();
|
||||||
|
finder.on('serverFound', function(server) {
|
||||||
|
var client = new ScreenLogic.UnitConnection(server);
|
||||||
|
client.on('loggedIn', function() {
|
||||||
|
this.getPoolStatus();
|
||||||
|
this.getControllerConfig();
|
||||||
|
}).on('poolStatus', function(status) {
|
||||||
|
}).on('controllerConfig', function(config) {
|
||||||
|
client.close();
|
||||||
|
finder.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.connect();
|
||||||
|
});
|
||||||
|
|
||||||
|
finder.search();
|
Reference in New Issue
Block a user