octopus-gps-tracking
Version:
Let you work with some GPS trackers that connects through tcp.
399 lines (322 loc) • 11 kB
JavaScript
util = require('util');
EventEmitter = require('events').EventEmitter;
net = require('net');
extend = require('node.extend');
functions = require('./functions');
util.inherits(Device, EventEmitter);
util.inherits(server, EventEmitter);
function server(opts, callback) {
if (!(this instanceof server)) {
return new server(opts, callback);
}
EventEmitter.call(this);
var defaults = {
debug: false,
port: 8080,
device_adapter: false
};
//Merge default options with user options
this.opts = extend(defaults, opts);
var thisServer = this;
this.devices = [];
this.db = false;
this.server = false;
this.availableAdapters = {
TK103: './adapters/tk103',
TK103_2: './adapters/tk103-2'
};
/****************************
SOME FUNCTIONS
*****************************/
/* */
this.setAdapter = function(adapter){
if (typeof adapter.adapter != 'function') {
throw 'The adapter needs an adpater() method to start an instance of it';
}
this.device_adapter = adapter;
};
this.getAdapter = function() {
return this.device_adapter;
};
this.addAdaptar = function(model) {
this.availableAdapters.push(model);
};
this.init = function(cb) {
//Set debug
thisServer.setDebug(this.opts.debug);
/*****************************
DEVICE ADAPTER INITIALIZATION
******************************/
if (thisServer.opts.device_adapter === false) {
throw 'The app don\'t set the device_adapter to use. Which model is sending data to this server?';
}
if (typeof thisServer.opts.device_adapter == 'string') {
//Check if the selected model has an available adapter registered
if (typeof this.availableAdapters[this.opts.device_adapter] == 'undefined') {
throw 'The class adapter for ' + this.opts.device_adapter + ' doesn\'t exists';
}
//Get the adapter
var adapterFile = (this.availableAdapters[this.opts.device_adapter]);
this.setAdapter(require(adapterFile));
} else {
//IF THE APP PASS THE ADAPTER DIRECTLY
thisServer.setAdapter(this.opts.device_adapter);
}
thisServer.emit('before_init');
if (typeof cb == 'function') cb();
thisServer.emit('init');
/* FINAL INIT MESSAGE */
console.log('\n=================================================');
console.log('FRESHWORK GPS LISTENER running at port ' + thisServer.opts.port );
console.log('EXPECTING DEVICE MODEL: ' + thisServer.getAdapter().model_name );
console.log('=================================================\n');
};
this.addAdaptar = function(model){
this.adapters.push(model);
};
this.do_log = function (msg,from){
//If debug is disabled, return false
if (this.getDebug() === false) {
return false;
}
//If from parameter is not set, default is server.
if (typeof(from) == "undefined") {
from = "SERVER";
}
msg = "#" + from + ": " + msg;
console.log(msg);
};
/****************************************
SOME SETTERS & GETTERS
****************************************/
this.setDebug = function(val){
this.debug = (val === true);
};
this.getDebug = function(){
return this.debug;
};
//Init app
this.init(function(){
/*************************************
AFTER INITIALIZING THE APP...
*************************************/
thisServer.server = net.createServer(function (connection) {
//Now we are listening!
//We create an new device and give the an adapter to parse the incomming messages
connection.device = new Device(thisServer.getAdapter(),connection,thisServer);
thisServer.devices.push(connection);
// connection timeout
connection.setTimeout(30000);
//Once we receive data...
connection.on('data', function (data) {
try {
connection.device.emit("data",data);
} catch(error) {
console.log("Gps tracker hata: \n", error);
connection.end();
};
});
// Remove the device from the list when it leaves
connection.on('end', function () {
thisServer.devices.splice(thisServer.devices.indexOf(connection), 1);
connection.device.emit("disconnected");
});
connection.on("error", function(err) {
console.log("Caught flash policy server connection error: \n", err)
});
connection.on('close', function (){
console.log('Socket is closed');
connection.end();
});
connection.on('timeout', function () {
console.log('Socket did timeout');
connection.end();
});
callback(connection.device,connection);
connection.device.emit('connected');
}).listen(opts.port);
});
/* Search a device by ID */
this.find_device = function(device_id){
for (var i in this.devices) {
var dev = this.devices[i].device;
if(dev.uid == device_id) {
return dev;
}
}
return false;
};
/* SEND A MESSAGE TO DEVICE ID X */
this.send_to = function(device_id,msg){
var dev = this.find_device(device_id);
if (dev) {
dev.send(msg);
} else {
throw 'We cannot find device with device_id = ' + device_id;
}
};
return this;
}
/*************************************************************
THE DEVICE CLASS
**************************************************************/
function Device(adapter,connection,gps_server){
/* Inherits EventEmitter class */
EventEmitter.call(this);
var this_device = this;
this.connection = connection;
this.server = gps_server;
this.adapter = adapter.adapter(this);
this.uid = false;
this.ip = connection.ip;
this.port = connection.port;
this.name = false;
this.loged = false;
init();
/* init */
function init(){
}
/****************************************
RECEIVING DATA FROM THE DEVICE
****************************************/
this.on("data",function(data) {
msg_parts = this_device.adapter.parse_data(data);
if(this.getUID() === false && typeof(msg_parts.device_id) == "undefined"){
throw "The adapter doesn't return the device_id and is not defined";
}
if(msg_parts === false) { //something bad happened
this_device.do_log("The message (" + data + ") can't be parsed. Discarding...");
return;
}
if(typeof(msg_parts.cmd) == "undefined")throw "The adapter doesn't return the command (cmd) parameter";
//If the UID of the devices it hasn't been setted, do it now.
if(this.getUID() === false)
this.setUID(msg_parts.device_id);
/************************************
EXECUTE ACTION
************************************/
this_device.make_action(msg_parts.action,msg_parts);
});
this.make_action = function(action, msg_parts) {
//If we're not loged
if(action != "login_request" && !this_device.loged){
this_device.adapter.request_login_to_device();
console.log(this_device.getUID()+" is trying to '" + action + "' but it isn't loged. Action wasn't executed");
return false;
}
switch(action){
case "login_request":
this_device.login_request(msg_parts);
break;
case "ping":
this_device.ping(msg_parts);
break;
case "alarm":
this_device.receive_alarm(msg_parts);
break;
case "command_response":
this_device.command_response(msg_parts);
break;
case "other":
this_device.adapter.run_other(msg_parts.cmd,msg_parts);
break;
}
};
/****************************************
LOGIN & LOGOUT
****************************************/
this.login_request = function(msg_parts) {
this_device.do_log("I'm requesting to be loged.");
this_device.emit("login_request",this.getUID(),msg_parts);
};
this.login_authorized = function(val, msg_parts) {
if(val){
this.do_log("Device " + this_device.getUID() + " has been authorized. Welcome!");
this.loged = true;
this.adapter.authorize(msg_parts);
}else{
this.do_log("Device " + this_device.getUID() + " not authorized. Login request rejected");
}
};
this.logout = function(){
this.loged = false;
this.adapter.logout();
};
/****************************************
RECEIVING GPS POSITION FROM THE DEVICE
****************************************/
this.ping = function(msg_parts){
var gps_data = this.adapter.get_ping_data(msg_parts);
if(gps_data === false){
//Something bad happened
this_device.do_log("GPS Data can't be parsed. Discarding packet...");
return false;
}
/* Needs:
latitude, longitude, time
Optionals:
orientation, speed, mileage, etc */
gps_data.inserted = new Date();
gps_data.from_cmd = msg_parts.cmd;
this_device.emit("ping", gps_data);
};
/****************************************
RECEIVING ALARM
****************************************/
this.receive_alarm = function(msg_parts) {
//We pass the message parts to the adapter and they have to say wich type of alarm it is.
var alarm_data = this_device.adapter.receive_alarm(msg_parts);
/* Alarm data must return an object with at least:
alarm_type: object with this format:
{'code':'sos_alarm','msg':'SOS Alarm activated by the driver'}
*/
this_device.emit("alarm", alarm_data.code, alarm_data, msg_parts);
};
/****************************************
RECEIVING COMMAND RESPONSE FROM THE DEVICE
****************************************/
this.command_response = function(msg_parts) {
this_device.emit("command_response", msg_parts);
};
/****************************************
SET REFRESH TIME
****************************************/
this.set_refresh_time = function(interval, duration) {
this_device.adapter.set_refresh_time(interval, duration);
};
/* adding methods to the adapter */
this.adapter.get_device = function(){
return device;
};
this.send = function(msg){
this.emit("send_data",msg);
this.connection.write(msg);
this.do_log("Sending to "+this_device.getUID() + ": " + msg);
};
this.do_log = function (msg){
this_device.server.do_log(msg,this_device.getUID());
};
this.send_byte_array = function(array){
this.emit("send_byte_data",array);
var buff = new Buffer(array);
console.log(buff);
this.do_log("Sending to " + this_device.uid + ": <Array: [" + array + "]>");
};
/****************************************
SOME SETTERS & GETTERS
****************************************/
this.getName = function(){
return this.name;
};
this.setName = function(name) {
this.name = name;
};
this.getUID = function() {
return this.uid;
};
this.setUID = function(uid) {
this.uid = uid;
};
}
exports.server = server;
exports.version = require('../package').version;