Comparing version 0.0.2 to 0.0.4
250
index.js
@@ -21,13 +21,29 @@ /* | ||
var events = require('events'); | ||
var debug = require('debug')('pathfinder-pfinterface') | ||
var debug = require('debug')('pfint') | ||
// we need this which only exists in EMCA6 | ||
if (!String.prototype.endsWith) { | ||
String.prototype.endsWith = function(searchString, position) { | ||
var subjectString = this.toString(); | ||
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { | ||
position = subjectString.length | ||
} | ||
position -= searchString.length | ||
var lastIndex = subjectString.indexOf(searchString, position) | ||
return lastIndex !== -1 && lastIndex === position | ||
}; | ||
} | ||
module.exports = PFInt; | ||
module.exports = PFInt | ||
function PFInt() | ||
{ | ||
events.EventEmitter.call(this); | ||
var connected = false; | ||
var subscribed = false | ||
events.EventEmitter.call(this) | ||
} | ||
PFInt.super_ = events.EventEmitter; | ||
PFInt.super_ = events.EventEmitter | ||
PFInt.prototype = Object.create(events.EventEmitter.prototype, { | ||
@@ -40,18 +56,14 @@ constructor: { | ||
var commandQueue = [ | ||
"Version", | ||
"Subscribe Memory", | ||
"Subscribe Silence All", | ||
"GetMemorySlot All", | ||
"GetList Routers"] | ||
; | ||
var subscribed = false | ||
// We initially run these commands when we connect | ||
var commandQueue = [] | ||
var Datastore = require('nedb') | ||
var state = new Datastore(); | ||
var events = require('events'); | ||
var state = new Datastore() | ||
var events = require('events') | ||
PFInt.prototype.find = function find(query, cb) | ||
{ | ||
var self = this; | ||
var self = this | ||
state.find(query,cb) | ||
@@ -63,3 +75,4 @@ return self | ||
{ | ||
var self = this; | ||
var self = this | ||
debug(query) | ||
state.findOne(query,cb) | ||
@@ -69,6 +82,48 @@ return self | ||
PFInt.prototype.setMemorySlot = function setMemorySlot(memorySlot, memorySlotValue, cb) | ||
{ | ||
var self = this | ||
if (memorySlot === undefined || memorySlot === null || memorySlotValue === undefined || memorySlotValue === null) | ||
{ | ||
cb('passed undefined',{'error':'memorySlot or memorySlotValue not defined'}) | ||
return; | ||
} | ||
if (memorySlotValue.length > 19979) | ||
{ | ||
cb('memory slot value too long',{'error':'memoryslot value too long'}) | ||
return; | ||
} | ||
if (memorySlot.length >= 19998) // yes, you read that right, the name can actually be longer than the value. | ||
{ | ||
cb('memory slot name too long', {'error':'memory slot name too long'}) | ||
return; | ||
} | ||
if (self.connected) | ||
{ | ||
// check that the memoryslot value given is actually defined... | ||
debug('setMemorySlot',{'memorySlot':memorySlot,'memorySlotValue':memorySlotValue}) | ||
commandQueue.push("SetMemorySlot " + memorySlot + "=" + memorySlotValue + "\r\n") | ||
sendCommands(state,self.client) | ||
/* | ||
At this point, we've sent the command to Pathfinder to set the memory slot. | ||
Shortly, it'll come back with the confirmation that that MemorySlot has been set - so we subscribe to our | ||
own event listener and wait until we see the memory slot get updated. | ||
*/ | ||
var updateEvent = function (slot) | ||
{ | ||
if (slot.name == memorySlot) | ||
{ | ||
self.removeListener('memorySlot',updateEvent) | ||
self.findOne({'itemType' : 'memoryslot','name':memorySlot},cb) | ||
} | ||
} | ||
self.on('memorySlot',updateEvent) | ||
} | ||
} | ||
var linesToParse = [] | ||
PFInt.prototype.sync = function sync(config) | ||
{ | ||
debug("sync"); | ||
debug("sync") | ||
var self = this; | ||
@@ -89,5 +144,14 @@ self.config = config | ||
function() { //'connect' listener | ||
// when we first connect, we want to run all of these commands | ||
commandQueue.push("Login " + config['user'] + " " + config['password']) | ||
commandQueue.push("Version") | ||
commandQueue.push("Subscribe Memory") | ||
commandQueue.push("Subscribe Silence All") | ||
commandQueue.push("GetMemorySlot All") | ||
commandQueue.push("GetList Routers") | ||
sendCommands(state,self.client) | ||
setTimeout(function() { sendCommands(state,self.client) },1000) // in case the results of all the above commands create more commands to execute | ||
self.connected = true | ||
debug('Connected') | ||
self.emit('connected') | ||
self.client.write("Login " + config['user'] + " " + config['password'] + "\r\n"); | ||
state.update( | ||
@@ -97,4 +161,14 @@ {'itemType' : 'pathfinderserver'}, | ||
) | ||
var readBuffer = ""; | ||
self.client.on('data', function(data) { | ||
lines = data.toString().split("\r\n") | ||
//debug("From PF",data.toString()) | ||
readBuffer = readBuffer + data.toString() | ||
//debug("readBuffer",readBuffer) | ||
// if the message does not end with a \r\n>>, then there will be a continuation so wait for that. | ||
if (!readBuffer.endsWith("\r\n>>")) | ||
{ | ||
return; | ||
} | ||
lines = readBuffer.split("\r\n") | ||
readBuffer = ""; | ||
lines.forEach(function (line) { | ||
@@ -120,3 +194,5 @@ | ||
self.emit('error', error) | ||
setTimeout(function() { exports.sync(config, state) }, 10000); | ||
self.connected = false | ||
self.subscribed = false | ||
setTimeout(function() { self.sync(config, state) }, 10000) | ||
}) | ||
@@ -130,8 +206,10 @@ | ||
) | ||
self.connected = false | ||
self.subscribed = false | ||
self.emit('disconnected') | ||
debug('reconnecting in 10 seconds') | ||
setTimeout(10000, function () | ||
setTimeout(function () | ||
{ | ||
stompClient.connect(); | ||
}); | ||
self.sync(config,state); | ||
}, 10000); | ||
}) | ||
@@ -147,10 +225,11 @@ | ||
firstLine = lines.shift() | ||
if (firstLine == ">>") | ||
if (firstLine.indexOf(">>") == 0) | ||
{ | ||
firstLine = lines.shift() | ||
} | ||
// console.log("## PF: " + data.toString()) | ||
if (firstLine.indexOf("Login") >= 0) | ||
{ | ||
debug("login",firstLine) | ||
if (firstLine.indexOf("Successful") > 0) | ||
@@ -170,3 +249,3 @@ { | ||
) | ||
resync(state, client); | ||
sendCommands(state, client); | ||
return | ||
@@ -188,3 +267,3 @@ } else { | ||
debug("PF Error" + firstLine) | ||
resync(state, client); | ||
sendCommands(state, client); | ||
} | ||
@@ -194,2 +273,3 @@ | ||
{ | ||
debug("version",firstLine) | ||
state.update( | ||
@@ -199,3 +279,2 @@ {'itemType' : 'pathfinderserver'}, | ||
) | ||
resync(state, client) | ||
} | ||
@@ -214,3 +293,2 @@ | ||
}) | ||
resync(state, client) | ||
} | ||
@@ -220,34 +298,52 @@ | ||
{ | ||
debug('memoryslot') | ||
lines.push(firstLine) | ||
lines.unshift(firstLine) | ||
lines.forEach(function (line) | ||
{ | ||
if (line.indexOf(">>") == 0) | ||
{ return } | ||
// | ||
if (line.length < 2) { | ||
return | ||
if (line.length < 2) | ||
return | ||
} | ||
def = line.substring(line.indexOf(" ")+1) | ||
parts = def.split('\t'); | ||
if (parts[1] != "") | ||
//MemorySlot lines should have 3 fields, slot number, optional name, value | ||
// if the value is blank, then don't store it. | ||
if (parts.length == 3 && parts[2] != '') | ||
{ | ||
var slot = { | ||
'itemType' : 'memoryslot', | ||
'number' : parts[0], | ||
'name' : parts[1], | ||
'value' : parts[2] | ||
var slot = null | ||
if (parts[1] == '') | ||
{ // no name | ||
slot = { | ||
'itemType' : 'memoryslot', | ||
'number' : parts[0], | ||
'value' : parts[2] | ||
} | ||
debug(slot); | ||
state.update( | ||
{'itemType' : 'memoryslot', | ||
'number' : parts[0] | ||
}, | ||
slot, | ||
{'upsert' : true} | ||
) | ||
self.emit('memorySlot', slot) | ||
} else { | ||
// only has a number | ||
slot = { | ||
'itemType' : 'memoryslot', | ||
'number' : parts[0], | ||
'name' : parts[1], | ||
'value' : parts[2] | ||
} | ||
} | ||
if (slot != null) | ||
{ | ||
debug('memoryslot',slot); | ||
state.update( | ||
{'itemType' : 'memoryslot', | ||
'number' : parts[0] | ||
}, | ||
slot, | ||
{'upsert' : true} | ||
) | ||
self.emit('memorySlot', slot) | ||
} else { | ||
debug("slot error",line) | ||
} | ||
} | ||
}); | ||
resync(state, client) | ||
return | ||
@@ -257,3 +353,3 @@ } | ||
{ | ||
debug('routestat') | ||
debug('routestat',firstLine) | ||
lines.forEach(function (line) | ||
@@ -269,2 +365,3 @@ { | ||
parts = def.split('\t'); | ||
debug(parts) | ||
if (parts[1] != "") | ||
@@ -280,4 +377,4 @@ { | ||
state.update( | ||
{'itemType' : 'memoryslot', | ||
'number' : parts[0] | ||
{'itemType' : 'route', | ||
'destination': parts[2] | ||
}, | ||
@@ -290,3 +387,2 @@ slot, | ||
}); | ||
resync(state, client) | ||
return | ||
@@ -297,3 +393,3 @@ } | ||
{ | ||
debug('gpistat') | ||
debug('gpistat',firstLine) | ||
lines.push(firstLine) | ||
@@ -324,3 +420,2 @@ lines.forEach( function (line) { | ||
}); | ||
resync(state, client) | ||
} | ||
@@ -330,6 +425,5 @@ | ||
{ | ||
debug('subscribed') | ||
subscribed = true | ||
debug('subscribed',firstLine) | ||
self.subscribed = true | ||
self.emit('subscribed', firstLine) | ||
resync(state, client) | ||
} | ||
@@ -366,3 +460,2 @@ | ||
{ | ||
resync(state, client) | ||
return | ||
@@ -487,33 +580,12 @@ } | ||
/* This gets run every now and then, to keep us in sync with Pathfinder. */ | ||
function resync(state, connection) | ||
function sendCommands(state, connection) | ||
{ | ||
nextCommand = commandQueue.shift() | ||
if (nextCommand) | ||
while (nextCommand) | ||
{ | ||
debug("sending command",nextCommand) | ||
connection.write(nextCommand + "\r\n") | ||
} else {/* | ||
// requery all routers | ||
routers = state.find({'itemType' : 'router'}, | ||
function (err, routers) { | ||
// queue up GPIO stat and RouteStat for all the routers | ||
routers.forEach(function(router) { | ||
// should probably only do this for GPIO routers | ||
if(router['type'] == "AxiaGPIO") | ||
{ | ||
commandQueue.push("GPIStat " + router['id']); | ||
commandQueue.push("GPOStat " + router['id']); | ||
} | ||
commandQueue.push("GetList RouteStats " + router['id']); | ||
}) | ||
}); | ||
if (!subscribed) | ||
{ | ||
commandQueue.push("GetMemorySlot All") | ||
} | ||
commandQueue.push("GetList ProtocolTranslators") | ||
*/ | ||
setTimeout(function() {resync(state, connection)}, 2500) | ||
} | ||
nextCommand = commandQueue.shift() | ||
} | ||
} |
{ | ||
"name": "pfint", | ||
"author": "Chris Roberts <chris@naxxfish.eu>", | ||
"version": "0.0.2", | ||
"author": { | ||
"name": "Chris Roberts", | ||
"email": "chris@naxxfish.eu", | ||
"url": "http://naxxfish.eu/" | ||
}, | ||
"version": "0.0.4", | ||
"description": "A module which allows Node.js to interface with PathfinderPC Server (www.pathfinderpc.com)", | ||
"homepage": "http://github.com/naxxfish/pfint", | ||
"main": "index.js", | ||
"main": "index.js", | ||
"dependencies": { | ||
"nedb": "~0.10.4" | ||
}, | ||
"devDependencies": { | ||
"mocha": "^2.4.5", | ||
"randomstring": "^1.1.4", | ||
"should": "^8.2.2" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "http://github.com/naxxfish/pfint.git" | ||
} | ||
"type": "git", | ||
"url": "http://github.com/naxxfish/pfint.git" | ||
}, | ||
"scripts": { | ||
"test": "mocha test/test.js" | ||
}, | ||
"license": "MIT" | ||
} |
@@ -91,6 +91,9 @@ PathfinderPC Server Interface | ||
### Credits | ||
So far, all done by me (Chris) | ||
### License | ||
Copyright (c) 2015 Chris Roberts | ||
Like it? Send me some Bitcoins? 1GTw3bJ5UB7g2upzzvXarJ9VZX3gREdpgG | ||
![1GTw3bJ5UB7g2upzzvXarJ9VZX3gREdpgG](http://naxxfish.files.wordpress.com/2014/02/desktop_wallet_code.png) | ||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
22277
7
575
98
3
1