Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c76d101b9 | ||
|
|
91f9a8f54b | ||
|
|
68b6a786bf | ||
|
|
9fde3ad5d5 | ||
|
|
3fa299cbee | ||
|
|
b8e3260e75 | ||
|
|
47f7282a27 | ||
|
|
4e57b7124a | ||
|
|
650efa9bec | ||
|
|
4284fded99 | ||
|
|
4bede83ccd | ||
|
|
fe8e782e9f | ||
|
|
3eb89e5dc6 | ||
|
|
1362eb4cd9 | ||
|
|
a47811d20f | ||
|
|
86833a7011 | ||
|
|
7032f273db | ||
|
|
6ae4728ded | ||
|
|
cda98e3145 | ||
|
|
b2609c228a | ||
|
|
52fb326942 | ||
|
|
28c5dc0d46 | ||
|
|
a02e3ecf17 | ||
|
|
b91bcb7442 | ||
|
|
a0c0a7938b | ||
|
|
82f354bf2b | ||
|
|
7f64b567db | ||
|
|
b17f842de7 | ||
|
|
ff68553bd7 | ||
|
|
22b11d6103 | ||
|
|
00987ea8e2 | ||
|
|
f0a1289818 | ||
|
|
38840d5b8d | ||
|
|
74008bc7de | ||
|
|
305558f186 | ||
|
|
4ad8aa5a1b | ||
|
|
c70354997a | ||
|
|
c88e5d6fe8 | ||
|
|
4e9186812c | ||
|
|
41740cbf0b | ||
|
|
2932b9ab6d | ||
|
|
3625f26134 | ||
|
|
c1d486b776 | ||
|
|
ae441beda0 | ||
|
|
6afe793c52 | ||
|
|
233daee88f | ||
|
|
91417a5c7e |
No files matched your search
@@ -1,3 +1,4 @@
|
|||||||
*~
|
*~
|
||||||
*.js
|
*.js
|
||||||
node_modules
|
node_modules
|
||||||
|
debug/*
|
||||||
@@ -19,10 +19,10 @@ Install [Node.js](http://nodejs.org/), [Redis](http://redis.io/), and [MongoDB](
|
|||||||
|
|
||||||
You may need to modify the configuration files under "config" directory (in /lib/node_modules/genieacs/config) depending on your setup.
|
You may need to modify the configuration files under "config" directory (in /lib/node_modules/genieacs/config) depending on your setup.
|
||||||
|
|
||||||
Alternatively, you can use git to get the latest development version (not recommended for production use):
|
Alternatively, you can install from source by cloning the git repository:
|
||||||
|
|
||||||
cd /opt
|
cd /opt
|
||||||
git clone https://github.com/zaidka/genieacs.git
|
git clone https://github.com/zaidka/genieacs.git --branch v1.0
|
||||||
cd genieacs
|
cd genieacs
|
||||||
npm install
|
npm install
|
||||||
npm run configure
|
npm run configure
|
||||||
@@ -54,13 +54,12 @@ You may now proceed with installing [GenieACS GUI front end](https://github.com/
|
|||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
Documentation is still work in progress. Feel free to contact me if you require any assistance in installation, configuration, or using the APIs.
|
The [Users mailing list](http://lists.genieacs.com) is a good place to get guidance and help from the community. Head on over and join the conversation! In addition, the [wiki](https://github.com/zaidka/genieacs/wiki) provides useful documentation and tips from GenieACS users.
|
||||||
|
|
||||||
You may submit bug reports or feature requests [here](https://github.com/zaidka/genieacs/issues).
|
You may submit bug reports or feature requests [here](https://github.com/zaidka/genieacs/issues). For device interoperability issues, please consult the mailing list first — it's likely that a workaround already exists.
|
||||||
|
|
||||||
For commercial support options, please contact me.
|
For commercial support options and professional services, please visit [genieacs.com](https://genieacs.com).
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Contributions are welcome. Fork this repo and open a pull request and wait for feedback. You can also contribute by enhancing the documentation in the [wiki section](https://github.com/zaidka/genieacs/wiki).
|
Contributions are welcome. Fork this repo and open a pull request and wait for feedback. You can also contribute by enhancing the documentation in the [wiki section](https://github.com/zaidka/genieacs/wiki).
|
||||||
|
|
||||||
@@ -8,12 +8,20 @@
|
|||||||
"_deviceId._Manufacturer" : {"alias" : "summary.manufacturer"},
|
"_deviceId._Manufacturer" : {"alias" : "summary.manufacturer"},
|
||||||
"InternetGatewayDevice.DeviceInfo.HardwareVersion" : {"alias" : "summary.hardwareVersion"},
|
"InternetGatewayDevice.DeviceInfo.HardwareVersion" : {"alias" : "summary.hardwareVersion"},
|
||||||
"InternetGatewayDevice.DeviceInfo.SoftwareVersion" : {"alias" : "summary.softwareVersion"},
|
"InternetGatewayDevice.DeviceInfo.SoftwareVersion" : {"alias" : "summary.softwareVersion"},
|
||||||
|
"Device.DeviceInfo.HardwareVersion" : {"alias" : "summary.hardwareVersion"},
|
||||||
|
"Device.DeviceInfo.SoftwareVersion" : {"alias" : "summary.softwareVersion"},
|
||||||
|
|
||||||
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANIPConnection./^\\d+$/.MACAddress" : {"alias" : "summary.mac", "type" : "mac"},
|
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANIPConnection./^\\d+$/.MACAddress" : {"alias" : "summary.mac", "type" : "mac"},
|
||||||
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANIPConnection./^\\d+$/.ExternalIPAddress" : {"alias" : "summary.ip"},
|
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANIPConnection./^\\d+$/.ExternalIPAddress" : {"alias" : "summary.ip"},
|
||||||
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANPPPConnection./^\\d+$/.MACAddress" : {"alias" : "summary.mac", "type" : "mac"},
|
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANPPPConnection./^\\d+$/.MACAddress" : {"alias" : "summary.mac", "type" : "mac"},
|
||||||
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANPPPConnection./^\\d+$/.ExternalIPAddress" : {"alias" : "summary.ip"},
|
"InternetGatewayDevice.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANPPPConnection./^\\d+$/.ExternalIPAddress" : {"alias" : "summary.ip"},
|
||||||
|
"Device.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANIPConnection./^\\d+$/.MACAddress" : {"alias" : "summary.mac", "type" : "mac"},
|
||||||
|
"Device.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANIPConnection./^\\d+$/.ExternalIPAddress" : {"alias" : "summary.ip"},
|
||||||
|
"Device.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANPPPConnection./^\\d+$/.MACAddress" : {"alias" : "summary.mac", "type" : "mac"},
|
||||||
|
"Device.WANDevice./^\\d+$/.WANConnectionDevice./^\\d+$/.WANPPPConnection./^\\d+$/.ExternalIPAddress" : {"alias" : "summary.ip"},
|
||||||
|
|
||||||
"InternetGatewayDevice.LANDevice./^\\d+$/.WLANConfiguration./^\\d+$/.SSID" : {"alias" : "summary.wlanSsid"},
|
"InternetGatewayDevice.LANDevice./^\\d+$/.WLANConfiguration./^\\d+$/.SSID" : {"alias" : "summary.wlanSsid"},
|
||||||
"InternetGatewayDevice.LANDevice./^\\d+$/.WLANConfiguration./^\\d+$/.PreSharedKey.1.KeyPassphrase" : {"alias" : "summary.wlanPassphrase"}
|
"InternetGatewayDevice.LANDevice./^\\d+$/.WLANConfiguration./^\\d+$/.PreSharedKey.1.KeyPassphrase" : {"alias" : "summary.wlanPassphrase"},
|
||||||
|
"Device.LANDevice./^\\d+$/.WLANConfiguration./^\\d+$/.SSID" : {"alias" : "summary.wlanSsid"},
|
||||||
|
"Device.LANDevice./^\\d+$/.WLANConfiguration./^\\d+$/.PreSharedKey.1.KeyPassphrase" : {"alias" : "summary.wlanPassphrase"}
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ connectionRequest = (deviceId, callback) ->
|
|||||||
)
|
)
|
||||||
|
|
||||||
request.on('socket', (socket) ->
|
request.on('socket', (socket) ->
|
||||||
socket.setTimeout(2000)
|
socket.setTimeout(config.get('CONNECTION_REQUEST_TIMEOUT', deviceId))
|
||||||
socket.on('timeout', () ->
|
socket.on('timeout', () ->
|
||||||
request.abort()
|
request.abort()
|
||||||
)
|
)
|
||||||
@@ -117,6 +117,9 @@ connectionRequest = (deviceId, callback) ->
|
|||||||
authString = auth.digest(username, password, uri.path, 'GET', null, authHeader)
|
authString = auth.digest(username, password, uri.path, 'GET', null, authHeader)
|
||||||
|
|
||||||
conReq(connectionRequestUrl, authString, (statusCode, authHeader) ->
|
conReq(connectionRequestUrl, authString, (statusCode, authHeader) ->
|
||||||
|
if statusCode == 0
|
||||||
|
# Workaround for some devices unexpectedly closing the connection
|
||||||
|
return conReq(connectionRequestUrl, authString, (statusCode) -> callback(statusToError(statusCode)))
|
||||||
callback(statusToError(statusCode))
|
callback(statusToError(statusCode))
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
@@ -127,15 +130,19 @@ connectionRequest = (deviceId, callback) ->
|
|||||||
|
|
||||||
watchTask = (taskId, timeout, callback) ->
|
watchTask = (taskId, timeout, callback) ->
|
||||||
setTimeout( () ->
|
setTimeout( () ->
|
||||||
db.tasksCollection.findOne({_id : taskId}, {'_id' : 1}, (err, task) ->
|
db.tasksCollection.findOne({_id : taskId}, {'_id' : 1, 'fault' : 1}, (err, task) ->
|
||||||
|
return callback(err) if err
|
||||||
|
|
||||||
if task
|
if task
|
||||||
timeout -= 500
|
timeout -= 500
|
||||||
if timeout < 0
|
if task.fault?
|
||||||
callback('timeout')
|
callback(null, 'fault')
|
||||||
|
else if timeout <= 0
|
||||||
|
callback(null, 'timeout')
|
||||||
else
|
else
|
||||||
watchTask(taskId, timeout, callback)
|
watchTask(taskId, timeout, callback)
|
||||||
else
|
else
|
||||||
callback(err)
|
callback(null, 'completed')
|
||||||
)
|
)
|
||||||
, 500)
|
, 500)
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,18 @@ exports.extend = (obj, mixin) ->
|
|||||||
obj
|
obj
|
||||||
|
|
||||||
|
|
||||||
|
exports.flattenObject = (object) ->
|
||||||
|
newObj = {}
|
||||||
|
f = (obj, prefix) ->
|
||||||
|
for k, v of obj
|
||||||
|
if typeof(v) is 'object'
|
||||||
|
f(v, "#{prefix}#{k}.")
|
||||||
|
else
|
||||||
|
newObj["#{prefix}#{k}"] = v
|
||||||
|
f(object, '')
|
||||||
|
return newObj
|
||||||
|
|
||||||
|
|
||||||
exports.getParamValueFromPath = (obj, path) ->
|
exports.getParamValueFromPath = (obj, path) ->
|
||||||
pp = path.split('.')
|
pp = path.split('.')
|
||||||
ref = obj
|
ref = obj
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ options = {
|
|||||||
GET_PARAMETER_NAMES_DEPTH_THRESHOLD : {type : 'int', default : 0},
|
GET_PARAMETER_NAMES_DEPTH_THRESHOLD : {type : 'int', default : 0},
|
||||||
TASK_PARAMETERS_BATCH_SIZE : {type : 'int', default : 32},
|
TASK_PARAMETERS_BATCH_SIZE : {type : 'int', default : 32},
|
||||||
COOKIES_PATH : {type : 'string'},
|
COOKIES_PATH : {type : 'string'},
|
||||||
|
CONNECTION_REQUEST_TIMEOUT : {type : 'int', default : 2000},
|
||||||
|
|
||||||
# Libxml related configuration
|
# Libxml related configuration
|
||||||
XML_PARSE_RECOVER : {type : 'bool'},
|
XML_PARSE_RECOVER : {type : 'bool'},
|
||||||
|
|||||||
@@ -15,22 +15,31 @@
|
|||||||
# along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
|
# along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
###
|
###
|
||||||
|
|
||||||
|
path = require 'path'
|
||||||
config = require './config'
|
config = require './config'
|
||||||
common = require './common'
|
common = require './common'
|
||||||
|
|
||||||
|
|
||||||
|
FILES = {}
|
||||||
|
getFile = (filename) ->
|
||||||
|
if filename not of FILES
|
||||||
|
FILES[filename] = require(path.resolve(config.get('CONFIG_DIR'), "custom_commands/#{filename}"))
|
||||||
|
|
||||||
|
return FILES[filename]
|
||||||
|
|
||||||
|
|
||||||
exports.execute = (deviceId, command, callback) ->
|
exports.execute = (deviceId, command, callback) ->
|
||||||
args = command.split(/\s+/)
|
args = command.split(/\s+/)
|
||||||
f = args.shift()
|
f = args.shift()
|
||||||
c = args.shift()
|
c = args.shift()
|
||||||
|
|
||||||
file = require "../config/custom_commands/#{f}"
|
file = getFile(f)
|
||||||
file[c](deviceId, args.join(' '), callback)
|
file[c](deviceId, args.join(' '), callback)
|
||||||
|
|
||||||
|
|
||||||
exports.getFileCommands = (filename) ->
|
exports.getFileCommands = (filename) ->
|
||||||
commands = []
|
commands = []
|
||||||
f = require("../config/custom_commands/#{filename}")
|
f = getFile(filename)
|
||||||
for k,v of f
|
for k,v of f
|
||||||
commands.push(k)
|
commands.push(k)
|
||||||
return commands
|
return commands
|
||||||
|
|||||||
+7
-5
@@ -173,7 +173,7 @@ inform = (currentRequest, cwmpRequest) ->
|
|||||||
for k of reference
|
for k of reference
|
||||||
continue if k[0] == '_'
|
continue if k[0] == '_'
|
||||||
if not actual[k]?._timestamp? or actual[k]._timestamp < lastBootstrap
|
if not actual[k]?._timestamp? or actual[k]._timestamp < lastBootstrap
|
||||||
_tasks.push({device: currentRequest.session.deviceId, name : 'refreshObject', objectName : reference[k]._path})
|
_tasks.push({device: currentRequest.session.deviceId, name : 'refreshObject', objectName : reference[k]._path, timestamp : now})
|
||||||
else
|
else
|
||||||
traverse(reference[k], actual[k])
|
traverse(reference[k], actual[k])
|
||||||
|
|
||||||
@@ -185,8 +185,9 @@ inform = (currentRequest, cwmpRequest) ->
|
|||||||
deviceCustomCommands[k] = v._timestamp for k,v of device._customCommands
|
deviceCustomCommands[k] = v._timestamp for k,v of device._customCommands
|
||||||
|
|
||||||
for cmd in customCommands.getDeviceCustomCommandNames(currentRequest.session.deviceId)
|
for cmd in customCommands.getDeviceCustomCommandNames(currentRequest.session.deviceId)
|
||||||
if not (deviceCustomCommands[cmd]?._timestamp < lastBootstrap)
|
if not deviceCustomCommands[cmd]? or deviceCustomCommands[cmd] < lastBootstrap
|
||||||
_tasks.push({device: currentRequest.session.deviceId, name: 'customCommand', command: "#{cmd} init"})
|
# Increment timestamp by one millisecond to ensure it runs after any refresh task
|
||||||
|
_tasks.push({device: currentRequest.session.deviceId, name: 'customCommand', command: "#{cmd} init", timestamp: new Date(now.getTime() + 1)})
|
||||||
delete deviceCustomCommands[cmd]
|
delete deviceCustomCommands[cmd]
|
||||||
|
|
||||||
for cmd of deviceCustomCommands
|
for cmd of deviceCustomCommands
|
||||||
@@ -210,10 +211,11 @@ inform = (currentRequest, cwmpRequest) ->
|
|||||||
db.devicesCollection.insert({_id : currentRequest.session.deviceId, _registered : now, _deviceId : deviceIdDetails}, (err) ->
|
db.devicesCollection.insert({_id : currentRequest.session.deviceId, _registered : now, _deviceId : deviceIdDetails}, (err) ->
|
||||||
throw err if err
|
throw err if err
|
||||||
util.log("#{currentRequest.session.deviceId}: New device registered")
|
util.log("#{currentRequest.session.deviceId}: New device registered")
|
||||||
_tasks.push({device: currentRequest.session.deviceId, name : 'refreshObject', objectName : ''})
|
_tasks.push({device: currentRequest.session.deviceId, name : 'refreshObject', objectName : '', timestamp : now})
|
||||||
|
|
||||||
for cmd in customCommands.getDeviceCustomCommandNames(currentRequest.session.deviceId)
|
for cmd in customCommands.getDeviceCustomCommandNames(currentRequest.session.deviceId)
|
||||||
_tasks.push({device: currentRequest.session.deviceId, name: 'customCommand', command: "#{cmd} init"})
|
# Increment timestamp by one millisecond to ensure it runs after any refresh task
|
||||||
|
_tasks.push({device: currentRequest.session.deviceId, name: 'customCommand', command: "#{cmd} init", timestamp: new Date(now.getTime() + 1)})
|
||||||
|
|
||||||
apiFunctions.insertTasks(_tasks, {}, () ->
|
apiFunctions.insertTasks(_tasks, {}, () ->
|
||||||
updateAndRespond()
|
updateAndRespond()
|
||||||
|
|||||||
+120
-29
@@ -61,6 +61,10 @@ DEVICE_PRESET_REGEX = /^\/devices\/([a-zA-Z0-9\-\_\%]+)\/preset\/?$/
|
|||||||
DELETE_DEVICE_REGEX = /^\/devices\/([a-zA-Z0-9\-\_\%]+)\/?$/
|
DELETE_DEVICE_REGEX = /^\/devices\/([a-zA-Z0-9\-\_\%]+)\/?$/
|
||||||
|
|
||||||
|
|
||||||
|
errorToString = (err) ->
|
||||||
|
"#{err.name}: #{err.message}"
|
||||||
|
|
||||||
|
|
||||||
listener = (request, response) ->
|
listener = (request, response) ->
|
||||||
chunks = []
|
chunks = []
|
||||||
bytes = 0
|
bytes = 0
|
||||||
@@ -94,7 +98,7 @@ listener = (request, response) ->
|
|||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
@@ -106,8 +110,14 @@ listener = (request, response) ->
|
|||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if removedCount == 0
|
||||||
|
response.writeHead(404)
|
||||||
|
response.end()
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
@@ -126,7 +136,7 @@ listener = (request, response) ->
|
|||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
@@ -138,8 +148,14 @@ listener = (request, response) ->
|
|||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if removedCount == 0
|
||||||
|
response.writeHead(404)
|
||||||
|
response.end()
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
@@ -151,26 +167,38 @@ listener = (request, response) ->
|
|||||||
deviceId = querystring.unescape(r[1])
|
deviceId = querystring.unescape(r[1])
|
||||||
tag = querystring.unescape(r[2])
|
tag = querystring.unescape(r[2])
|
||||||
if request.method == 'POST'
|
if request.method == 'POST'
|
||||||
db.devicesCollection.update({'_id' : deviceId}, {'$addToSet' : {'_tags' : tag}}, {safe: true}, (err) ->
|
db.devicesCollection.update({'_id' : deviceId}, {'$addToSet' : {'_tags' : tag}}, {safe: true}, (err, updatedCount) ->
|
||||||
db.redisClient.del("#{deviceId}_presets_hash", (err) ->
|
db.redisClient.del("#{deviceId}_presets_hash", (err) ->
|
||||||
throw err if err
|
throw err if err
|
||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if updatedCount == 0
|
||||||
|
response.writeHead(404)
|
||||||
|
response.end()
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
else if request.method == 'DELETE'
|
else if request.method == 'DELETE'
|
||||||
db.devicesCollection.update({'_id' : deviceId}, {'$pull' : {'_tags' : tag}}, {safe: true}, (err) ->
|
db.devicesCollection.update({'_id' : deviceId}, {'$pull' : {'_tags' : tag}}, {safe: true}, (err, updatedCount) ->
|
||||||
db.redisClient.del("#{deviceId}_presets_hash", (err) ->
|
db.redisClient.del("#{deviceId}_presets_hash", (err) ->
|
||||||
throw err if err
|
throw err if err
|
||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if updatedCount == 0
|
||||||
|
response.writeHead(404)
|
||||||
|
response.end()
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
@@ -190,27 +218,42 @@ listener = (request, response) ->
|
|||||||
)
|
)
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
|
|
||||||
if urlParts.query.connection_request?
|
if urlParts.query.connection_request?
|
||||||
apiFunctions.connectionRequest(deviceId, (err) ->
|
apiFunctions.connectionRequest(deviceId, (err) ->
|
||||||
if err
|
if err
|
||||||
response.writeHead(202)
|
response.writeHead(202, err.message, {'Content-Type' : 'application/json'})
|
||||||
response.end()
|
response.end(JSON.stringify(task))
|
||||||
else
|
else
|
||||||
apiFunctions.watchTask(task._id, config.get('DEVICE_ONLINE_THRESHOLD', deviceId), (err) ->
|
apiFunctions.watchTask(task._id, config.get('DEVICE_ONLINE_THRESHOLD', deviceId), (err, status) ->
|
||||||
if err
|
if err
|
||||||
response.writeHead(202)
|
response.writeHead(500)
|
||||||
response.end()
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
response.writeHead(200)
|
|
||||||
response.end()
|
if status is 'timeout'
|
||||||
|
response.writeHead(202, 'Task queued but not processed', {'Content-Type' : 'application/json'})
|
||||||
|
response.end(JSON.stringify(task))
|
||||||
|
else if status is 'fault'
|
||||||
|
db.tasksCollection.findOne({_id : task._id}, (err, task) ->
|
||||||
|
if err
|
||||||
|
response.writeHead(500)
|
||||||
|
response.end(errorToString(err))
|
||||||
|
return
|
||||||
|
|
||||||
|
response.writeHead(202, 'Task faulted', {'Content-Type' : 'application/json'})
|
||||||
|
response.end(JSON.stringify(task))
|
||||||
|
)
|
||||||
|
else
|
||||||
|
response.writeHead(200, {'Content-Type' : 'application/json'})
|
||||||
|
response.end(JSON.stringify(task))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
response.writeHead(202)
|
response.writeHead(202, {'Content-Type' : 'application/json'})
|
||||||
response.end()
|
response.end(JSON.stringify(task))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else if urlParts.query.connection_request?
|
else if urlParts.query.connection_request?
|
||||||
@@ -218,7 +261,7 @@ listener = (request, response) ->
|
|||||||
apiFunctions.connectionRequest(deviceId, (err) ->
|
apiFunctions.connectionRequest(deviceId, (err) ->
|
||||||
if err
|
if err
|
||||||
response.writeHead 504
|
response.writeHead 504
|
||||||
response.end()
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
response.writeHead 200
|
response.writeHead 200
|
||||||
response.end()
|
response.end()
|
||||||
@@ -244,24 +287,42 @@ listener = (request, response) ->
|
|||||||
else if TASKS_REGEX.test(urlParts.pathname)
|
else if TASKS_REGEX.test(urlParts.pathname)
|
||||||
r = TASKS_REGEX.exec(urlParts.pathname)
|
r = TASKS_REGEX.exec(urlParts.pathname)
|
||||||
taskId = mongodb.ObjectID(querystring.unescape(r[1]))
|
taskId = mongodb.ObjectID(querystring.unescape(r[1]))
|
||||||
action = try querystring.unescape(r[2])
|
action = r[2]
|
||||||
if not action? or action is '/'
|
if not action? or action is '/'
|
||||||
if request.method == 'DELETE'
|
if request.method == 'DELETE'
|
||||||
db.tasksCollection.remove({'_id' : taskId}, (err, removedCount) ->
|
db.tasksCollection.findOne({'_id' : taskId}, {'device' : 1}, (err, task) ->
|
||||||
if err
|
throw err if err
|
||||||
response.writeHead(500)
|
|
||||||
response.end(err)
|
if not task
|
||||||
|
response.writeHead(404)
|
||||||
|
response.end()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
deviceId = task.device
|
||||||
|
db.tasksCollection.remove({'_id' : taskId}, (err, removedCount) ->
|
||||||
|
throw err if err
|
||||||
|
|
||||||
|
db.redisClient.del("#{deviceId}_presets_hash", (err) ->
|
||||||
|
throw err if err
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
else
|
else
|
||||||
response.writeHead 405, {'Allow': 'PUT DELETE'}
|
response.writeHead 405, {'Allow': 'PUT DELETE'}
|
||||||
response.end('405 Method Not Allowed')
|
response.end('405 Method Not Allowed')
|
||||||
else if action is '/retry'
|
else if action is '/retry'
|
||||||
if request.method == 'POST'
|
if request.method == 'POST'
|
||||||
db.tasksCollection.update({_id : taskId}, {$unset : {fault : 1}, $set : {timestamp : new Date()}}, (err, count) ->
|
db.tasksCollection.update({_id : taskId}, {$unset : {fault : 1}, $set : {timestamp : new Date()}}, (err, updatedCount) ->
|
||||||
# TODO need to invalidate presets hash for the device
|
# TODO need to invalidate presets hash for the device
|
||||||
|
throw err if err
|
||||||
|
if updatedCount == 0
|
||||||
|
response.writeHead(404)
|
||||||
|
response.end()
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
@@ -283,6 +344,11 @@ listener = (request, response) ->
|
|||||||
|
|
||||||
gs = new mongodb.GridStore(db.mongoDb, filename, 'w', {metadata : metadata})
|
gs = new mongodb.GridStore(db.mongoDb, filename, 'w', {metadata : metadata})
|
||||||
gs.open((err, gs) ->
|
gs.open((err, gs) ->
|
||||||
|
if err
|
||||||
|
response.writeHead(500)
|
||||||
|
response.end(errorToString(err))
|
||||||
|
return
|
||||||
|
|
||||||
gs.write(body, (err, res) ->
|
gs.write(body, (err, res) ->
|
||||||
throw err if err
|
throw err if err
|
||||||
gs.close((err) ->
|
gs.close((err) ->
|
||||||
@@ -294,6 +360,11 @@ listener = (request, response) ->
|
|||||||
)
|
)
|
||||||
else if request.method == 'DELETE'
|
else if request.method == 'DELETE'
|
||||||
mongodb.GridStore.unlink(db.mongoDb, filename, (err) ->
|
mongodb.GridStore.unlink(db.mongoDb, filename, (err) ->
|
||||||
|
if err
|
||||||
|
response.writeHead(500)
|
||||||
|
response.end(errorToString(err))
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
)
|
)
|
||||||
@@ -303,9 +374,9 @@ listener = (request, response) ->
|
|||||||
else if PING_REGEX.test(urlParts.pathname)
|
else if PING_REGEX.test(urlParts.pathname)
|
||||||
host = querystring.unescape(PING_REGEX.exec(urlParts.pathname)[1])
|
host = querystring.unescape(PING_REGEX.exec(urlParts.pathname)[1])
|
||||||
require('child_process').exec("ping -w 1 -i 0.2 -c 3 #{host}", (err, stdout, stderr) ->
|
require('child_process').exec("ping -w 1 -i 0.2 -c 3 #{host}", (err, stdout, stderr) ->
|
||||||
if err?
|
if err
|
||||||
response.writeHead(404, {'Cache-Control' : 'no-cache'})
|
response.writeHead(404, {'Cache-Control' : 'no-cache'})
|
||||||
response.end()
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
response.writeHead(200, {'Content-Type' : 'text/plain', 'Cache-Control' : 'no-cache'})
|
response.writeHead(200, {'Content-Type' : 'text/plain', 'Cache-Control' : 'no-cache'})
|
||||||
response.end(stdout)
|
response.end(stdout)
|
||||||
@@ -320,7 +391,7 @@ listener = (request, response) ->
|
|||||||
apiFunctions.deleteDevice(deviceId, (err) ->
|
apiFunctions.deleteDevice(deviceId, (err) ->
|
||||||
if err
|
if err
|
||||||
response.writeHead(500)
|
response.writeHead(500)
|
||||||
response.end(err.message)
|
response.end(errorToString(err))
|
||||||
return
|
return
|
||||||
response.writeHead(200)
|
response.writeHead(200)
|
||||||
response.end()
|
response.end()
|
||||||
@@ -339,10 +410,16 @@ listener = (request, response) ->
|
|||||||
|
|
||||||
func = (aliases) ->
|
func = (aliases) ->
|
||||||
if urlParts.query.query?
|
if urlParts.query.query?
|
||||||
|
try
|
||||||
q = JSON.parse(urlParts.query.query)
|
q = JSON.parse(urlParts.query.query)
|
||||||
|
catch err
|
||||||
|
response.writeHead(400)
|
||||||
|
response.end(errorToString(err))
|
||||||
|
return
|
||||||
else
|
else
|
||||||
q = {}
|
q = {}
|
||||||
q = query.expand(q, aliases) if collectionName is 'devices'
|
q = query.expand(q, aliases) if collectionName is 'devices'
|
||||||
|
q = query.substituteObjectId(q) if collectionName is 'tasks'
|
||||||
|
|
||||||
if urlParts.query.projection?
|
if urlParts.query.projection?
|
||||||
projection = {}
|
projection = {}
|
||||||
@@ -360,7 +437,14 @@ listener = (request, response) ->
|
|||||||
sort = {}
|
sort = {}
|
||||||
for k,v of s
|
for k,v of s
|
||||||
if aliases[k]?
|
if aliases[k]?
|
||||||
sort[a] = v for a in aliases[k]
|
for a in aliases[k]
|
||||||
|
if a[a.lastIndexOf('.')+1] != '_' and collectionName is 'devices'
|
||||||
|
sort["#{a}._value"] = v
|
||||||
|
else
|
||||||
|
sort[a] = v
|
||||||
|
else
|
||||||
|
if k[k.lastIndexOf('.') + 1] != '_' and collectionName is 'devices'
|
||||||
|
sort["#{k}._value"] = v
|
||||||
else
|
else
|
||||||
sort[k] = v
|
sort[k] = v
|
||||||
cur.sort(sort)
|
cur.sort(sort)
|
||||||
@@ -368,6 +452,11 @@ listener = (request, response) ->
|
|||||||
cur.skip(parseInt(urlParts.query.skip)) if urlParts.query.skip?
|
cur.skip(parseInt(urlParts.query.skip)) if urlParts.query.skip?
|
||||||
cur.limit(parseInt(urlParts.query.limit)) if urlParts.query.limit?
|
cur.limit(parseInt(urlParts.query.limit)) if urlParts.query.limit?
|
||||||
cur.count((err, total) ->
|
cur.count((err, total) ->
|
||||||
|
if err
|
||||||
|
response.writeHead(500)
|
||||||
|
response.end(errorToString(err))
|
||||||
|
return
|
||||||
|
|
||||||
response.writeHead(200, {'Content-Type' : 'application/json', 'total' : total})
|
response.writeHead(200, {'Content-Type' : 'application/json', 'total' : total})
|
||||||
if request.method is 'HEAD'
|
if request.method is 'HEAD'
|
||||||
response.end()
|
response.end()
|
||||||
@@ -375,6 +464,8 @@ listener = (request, response) ->
|
|||||||
response.write("[\n")
|
response.write("[\n")
|
||||||
i = 0
|
i = 0
|
||||||
cur.each((err, item) ->
|
cur.each((err, item) ->
|
||||||
|
throw err if err
|
||||||
|
|
||||||
if item is null
|
if item is null
|
||||||
response.end("\n]")
|
response.end("\n]")
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ common = require './common'
|
|||||||
parameters = require './parameters'
|
parameters = require './parameters'
|
||||||
|
|
||||||
|
|
||||||
stringToRegexp = (input) ->
|
stringToRegexp = (input, flags) ->
|
||||||
if (input.indexOf('*') == -1)
|
if (input.indexOf('*') == -1)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ stringToRegexp = (input) ->
|
|||||||
|
|
||||||
output = output.replace(/[\*]/, '.*')
|
output = output.replace(/[\*]/, '.*')
|
||||||
|
|
||||||
return new RegExp(output)
|
return new RegExp(output, flags)
|
||||||
|
|
||||||
|
|
||||||
normalizers = {}
|
normalizers = {}
|
||||||
@@ -68,7 +68,7 @@ normalizers.default = (input, normType) ->
|
|||||||
|
|
||||||
r = stringToRegexp(input)
|
r = stringToRegexp(input)
|
||||||
if r isnt false
|
if r isnt false
|
||||||
vals.push({'$regex' : r})
|
vals.push(r)
|
||||||
|
|
||||||
return vals
|
return vals
|
||||||
return input
|
return input
|
||||||
@@ -90,7 +90,7 @@ normalizers.date = (input, normType) ->
|
|||||||
normalizers.string = (input, normType) ->
|
normalizers.string = (input, normType) ->
|
||||||
if normType is 'query'
|
if normType is 'query'
|
||||||
if (m = /^\/(.*?)\/(g?i?m?y?)$/.exec(input))
|
if (m = /^\/(.*?)\/(g?i?m?y?)$/.exec(input))
|
||||||
return [{'$regex' : new RegExp(m[1], m[2])}, input]
|
return [new RegExp(m[1], m[2]), input]
|
||||||
return input
|
return input
|
||||||
|
|
||||||
|
|
||||||
@@ -117,14 +117,14 @@ normalizers.mac = (input, normType) ->
|
|||||||
|
|
||||||
if input.indexOf('*') != -1
|
if input.indexOf('*') != -1
|
||||||
input = (colonizeMac(a) for a in input.split('*')).join('*')
|
input = (colonizeMac(a) for a in input.split('*')).join('*')
|
||||||
return stringToRegexp(input, false)
|
return stringToRegexp(input, 'i')
|
||||||
|
|
||||||
input = colonizeMac(input)
|
input = colonizeMac(input)
|
||||||
|
|
||||||
if input.length == 17
|
if input.length == 17
|
||||||
return input
|
return [input, input.toLowerCase()]
|
||||||
|
|
||||||
return {'$regex' : new RegExp(input)}
|
return new RegExp(input, 'i')
|
||||||
|
|
||||||
|
|
||||||
exports.normalize = (path, value, normType) ->
|
exports.normalize = (path, value, normType) ->
|
||||||
|
|||||||
+41
-36
@@ -54,12 +54,21 @@ exports.calculatePresetsHash = (presets, objects) ->
|
|||||||
|
|
||||||
|
|
||||||
matchObject = (object, param) ->
|
matchObject = (object, param) ->
|
||||||
return false if not object._keys? or object._keys.length == 0
|
flatObject = common.flattenObject(object)
|
||||||
for k in object._keys
|
if object._keys?.length
|
||||||
return false if not param[k]?
|
keys = object._keys
|
||||||
v = common.matchType(param[k]._value, object[k])
|
else
|
||||||
if param[k]._value != v
|
# Consider all parameters as keys if none are defined
|
||||||
|
keys = (k for k in Object.keys(flatObject) when k[0] != '_')
|
||||||
|
|
||||||
|
for k in keys
|
||||||
|
p = common.getParamValueFromPath(param, k)
|
||||||
|
return false if not p?
|
||||||
|
v = common.matchType(p._value, flatObject[k])
|
||||||
|
|
||||||
|
if p._value != common.matchType(p._value, flatObject[k])
|
||||||
return false
|
return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
|
||||||
@@ -146,15 +155,7 @@ exports.getDevicePreset = (deviceId, presets, objects, aliases, callback) ->
|
|||||||
devicePreset.objects[c.name][c.object].current ?= {}
|
devicePreset.objects[c.name][c.object].current ?= {}
|
||||||
for k,p of param
|
for k,p of param
|
||||||
continue if k[0] == '_'
|
continue if k[0] == '_'
|
||||||
if p._name?
|
if matchObject(objects[c.object], p)
|
||||||
if p._name == c.object
|
|
||||||
devicePreset.objects[c.name][c.object].current[k] = p
|
|
||||||
else if matchObject(objects[c.object], p)
|
|
||||||
u = {}
|
|
||||||
u["#{c.name}.#{k}._name"] = c.object
|
|
||||||
db.devicesCollection.update({'_id' : deviceId}, {'$set' : u}, {}, (err, count) ->
|
|
||||||
throw err if err
|
|
||||||
)
|
|
||||||
devicePreset.objects[c.name][c.object].current[k] = p
|
devicePreset.objects[c.name][c.object].current[k] = p
|
||||||
|
|
||||||
when 'delete_object'
|
when 'delete_object'
|
||||||
@@ -165,15 +166,7 @@ exports.getDevicePreset = (deviceId, presets, objects, aliases, callback) ->
|
|||||||
devicePreset.objects[c.name][c.object].current ?= {}
|
devicePreset.objects[c.name][c.object].current ?= {}
|
||||||
for k,p of param
|
for k,p of param
|
||||||
continue if k[0] == '_'
|
continue if k[0] == '_'
|
||||||
if p._name?
|
if matchObject(objects[c.object], p)
|
||||||
if p._name == c.object
|
|
||||||
devicePreset.objects[c.name][c.object].current[k] = p
|
|
||||||
else if matchObject(objects[c.object], p)
|
|
||||||
u = {}
|
|
||||||
u["#{c.name}.#{k}._name"] = c.object
|
|
||||||
db.devicesCollection.update({'_id' : deviceId}, {'$set' : u}, {}, (err, count) ->
|
|
||||||
throw err if err
|
|
||||||
)
|
|
||||||
devicePreset.objects[c.name][c.object].current[k] = p
|
devicePreset.objects[c.name][c.object].current[k] = p
|
||||||
|
|
||||||
when 'custom_command_value'
|
when 'custom_command_value'
|
||||||
@@ -250,20 +243,21 @@ exports.processDevicePreset = (deviceId, devicePreset, callback) ->
|
|||||||
for objectName, objectDetails of object
|
for objectName, objectDetails of object
|
||||||
continue if not objectDetails.current?
|
continue if not objectDetails.current?
|
||||||
if objectDetails.preset?
|
if objectDetails.preset?
|
||||||
|
flatObject = common.flattenObject(objectDetails.preset)
|
||||||
if Object.keys(objectDetails.current).length > 0
|
if Object.keys(objectDetails.current).length > 0
|
||||||
for i, obj of objectDetails.current
|
for i, obj of objectDetails.current
|
||||||
for paramName, paramValue of objectDetails.preset
|
for paramName, paramValue of flatObject
|
||||||
continue if paramName[0] == '_'
|
continue if paramName[0] == '_'
|
||||||
if obj[paramName]
|
currentValue = common.getParamValueFromPath(obj, paramName)
|
||||||
currentValue = obj[paramName]._value
|
if currentValue?
|
||||||
presetValue = common.matchType(currentValue, objectDetails.preset[paramName])
|
presetValue = common.matchType(currentValue._value, flatObject[paramName])
|
||||||
if currentValue != presetValue
|
if currentValue._value != presetValue
|
||||||
setParameterValues.push(["#{parameterPath}.#{i}.#{paramName}", presetValue, obj[paramName]._type])
|
setParameterValues.push(["#{parameterPath}.#{i}.#{paramName}", presetValue, currentValue._type])
|
||||||
else
|
else
|
||||||
vals = []
|
vals = []
|
||||||
for k,v of objectDetails.preset
|
for k,v of flatObject
|
||||||
vals.push([k, v]) if k[0] != '_'
|
vals.push([k, v]) if k[0] != '_'
|
||||||
taskList.push({device : deviceId, name : 'addObject', objectName : parameterPath, parameterValues : vals, instanceName : objectName})
|
taskList.push({device : deviceId, name : 'addObject', objectName : parameterPath, parameterValues : vals})
|
||||||
else if Object.keys(objectDetails.current).length > 0
|
else if Object.keys(objectDetails.current).length > 0
|
||||||
for i, obj of objectDetails.current
|
for i, obj of objectDetails.current
|
||||||
taskList.push({device : deviceId, name : 'deleteObject', objectName : "#{parameterPath}.#{i}"})
|
taskList.push({device : deviceId, name : 'deleteObject', objectName : "#{parameterPath}.#{i}"})
|
||||||
@@ -300,11 +294,19 @@ exports.processDevicePreset = (deviceId, devicePreset, callback) ->
|
|||||||
|
|
||||||
|
|
||||||
getObjectHash = (object) ->
|
getObjectHash = (object) ->
|
||||||
return object._id if not object._keys? or object._keys.length == 0
|
if object._keys?.length
|
||||||
hash = ''
|
keys = object._keys
|
||||||
for k in object._keys
|
else
|
||||||
hash += "#{k}=#{object[k]}"
|
keys = (k for k in Object.keys(object) when k[0] != '_')
|
||||||
return hash
|
|
||||||
|
keys.sort()
|
||||||
|
|
||||||
|
hash = []
|
||||||
|
for k in keys
|
||||||
|
hash.push(k)
|
||||||
|
hash.push(common.getParamValueFromPath(object, k))
|
||||||
|
|
||||||
|
return JSON.stringify(hash)
|
||||||
|
|
||||||
|
|
||||||
accumulateConfigurations = (presets, objects) ->
|
accumulateConfigurations = (presets, objects) ->
|
||||||
@@ -320,6 +322,9 @@ accumulateConfigurations = (presets, objects) ->
|
|||||||
"object_#{c.name}_#{objectHash}"
|
"object_#{c.name}_#{objectHash}"
|
||||||
when 'software_version'
|
when 'software_version'
|
||||||
'software_version'
|
'software_version'
|
||||||
|
when 'custom_command_age', 'custom_command_value'
|
||||||
|
[filename, commandName] = c.command.split(' ', 2)
|
||||||
|
"#{c.type}_#{filename}_#{commandName}"
|
||||||
else
|
else
|
||||||
"#{c.type}_#{c.name}"
|
"#{c.type}_#{c.name}"
|
||||||
|
|
||||||
|
|||||||
+41
-4
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
common = require './common'
|
common = require './common'
|
||||||
normalize = require './normalize'
|
normalize = require './normalize'
|
||||||
|
mongodb = require 'mongodb'
|
||||||
|
|
||||||
|
|
||||||
expandValue = (param, value) ->
|
expandValue = (param, value) ->
|
||||||
@@ -50,8 +51,17 @@ expandValue = (param, value) ->
|
|||||||
while i < indices.length
|
while i < indices.length
|
||||||
obj = {}
|
obj = {}
|
||||||
for i in [0...keys.length]
|
for i in [0...keys.length]
|
||||||
|
if common.typeOf(values[i][indices[i]]) is common.REGEXP_TYPE
|
||||||
|
if keys[i] == '$ne'
|
||||||
|
obj['$not'] = values[i][indices[i]]
|
||||||
|
continue
|
||||||
|
else if keys[i] == '$not' and common.typeOf(values[i][indices[i]]) isnt common.OBJECT_TYPE
|
||||||
|
# Only a regex or decoument (object) are allowed within a $not operator.
|
||||||
|
# This is needed in order to discard string from which a regex is generated.
|
||||||
|
continue
|
||||||
|
|
||||||
obj[keys[i]] = values[i][indices[i]]
|
obj[keys[i]] = values[i][indices[i]]
|
||||||
objs.push(obj)
|
objs.push(obj) if Object.keys(obj).length
|
||||||
|
|
||||||
for i in [0...indices.length]
|
for i in [0...indices.length]
|
||||||
indices[i] += 1
|
indices[i] += 1
|
||||||
@@ -94,14 +104,41 @@ expand = (query, aliases) ->
|
|||||||
else
|
else
|
||||||
conditions = permute(k, v, aliases)
|
conditions = permute(k, v, aliases)
|
||||||
if conditions.length > 1
|
if conditions.length > 1
|
||||||
if new_query['$and']?
|
new_query['$and'] ?= []
|
||||||
new_query['$and'].push({'$or' : conditions})
|
if v?['$ne']? or v?['$nin']? or v?['$not']?
|
||||||
|
for c in conditions
|
||||||
|
new_query['$and'].push(c)
|
||||||
else
|
else
|
||||||
new_query['$and'] = [{'$or' : conditions}]
|
new_query['$and'].push({'$or' : conditions})
|
||||||
else
|
else
|
||||||
common.extend(new_query, conditions[0])
|
common.extend(new_query, conditions[0])
|
||||||
|
|
||||||
return new_query
|
return new_query
|
||||||
|
|
||||||
|
# Replace _id string values with ObjectID type
|
||||||
|
substituteObjectId = (query) ->
|
||||||
|
for k, v of query
|
||||||
|
if k[0] == '$' # logical operator
|
||||||
|
for i in [0...v.length]
|
||||||
|
substituteObjectId(v[i])
|
||||||
|
else if k == '_id'
|
||||||
|
if common.typeOf(v) is common.STRING_TYPE
|
||||||
|
query[k] = mongodb.ObjectID(v) if v.length == 24
|
||||||
|
else if common.typeOf(v) is common.OBJECT_TYPE
|
||||||
|
for kk, vv of v
|
||||||
|
switch kk # operator
|
||||||
|
when '$in', '$nin'
|
||||||
|
for i in [0...vv.length]
|
||||||
|
vv[i] = mongodb.ObjectID(vv[i]) if vv[i].length == 24
|
||||||
|
when '$eq', '$gt', '$gte', '$lt', '$lte', '$ne'
|
||||||
|
v[kk] = mongodb.ObjectID(vv) if vv.length == 24
|
||||||
|
when '$exists', '$type' then
|
||||||
|
# ignore
|
||||||
|
else
|
||||||
|
throw new Error('Operator not supported')
|
||||||
|
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
exports.expand = expand
|
exports.expand = expand
|
||||||
|
exports.substituteObjectId = substituteObjectId
|
||||||
+1
-1
@@ -51,7 +51,7 @@ listener = (httpRequest, httpResponse) ->
|
|||||||
)
|
)
|
||||||
|
|
||||||
httpResponse.writeHead(500, {'Connection' : 'close'})
|
httpResponse.writeHead(500, {'Connection' : 'close'})
|
||||||
httpResponse.end()
|
httpResponse.end("#{err.name}: #{err.message}")
|
||||||
catch err2
|
catch err2
|
||||||
util.error("#{new Date().toISOString()} - #{err2.stack}\n")
|
util.error("#{new Date().toISOString()} - #{err2.stack}\n")
|
||||||
)
|
)
|
||||||
|
|||||||
+1
-1
@@ -232,7 +232,7 @@ acsInform = (xml) ->
|
|||||||
parameterList : parameterValueList(xml.get('ParameterList')),
|
parameterList : parameterValueList(xml.get('ParameterList')),
|
||||||
deviceId : traverseXml(xml.get('DeviceId')),
|
deviceId : traverseXml(xml.get('DeviceId')),
|
||||||
event : event(xml.get('Event')),
|
event : event(xml.get('Event')),
|
||||||
retryCount : JSON.parse(xml.get('RetryCount').text())
|
retryCount : parseInt(xml.get('RetryCount').text())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+26
-11
@@ -43,6 +43,7 @@ common = require './common'
|
|||||||
db = require './db'
|
db = require './db'
|
||||||
mongodb = require 'mongodb'
|
mongodb = require 'mongodb'
|
||||||
customCommands = require './custom-commands'
|
customCommands = require './custom-commands'
|
||||||
|
url = require 'url'
|
||||||
|
|
||||||
exports.STATUS_OK = STATUS_OK = 1
|
exports.STATUS_OK = STATUS_OK = 1
|
||||||
exports.STATUS_FAULT = STATUS_FAULT = 2
|
exports.STATUS_FAULT = STATUS_FAULT = 2
|
||||||
@@ -220,7 +221,6 @@ this.addObject = (task, methodResponse, callback) ->
|
|||||||
task.session.subtask = {device : task.device, name : 'getParameterNames', parameterPath : "#{task.objectName}.#{task.session.instanceNumber}.", nextLevel : false}
|
task.session.subtask = {device : task.device, name : 'getParameterNames', parameterPath : "#{task.objectName}.#{task.session.instanceNumber}.", nextLevel : false}
|
||||||
task.session.appliedParameterValues = []
|
task.session.appliedParameterValues = []
|
||||||
task.session.parameterNames = []
|
task.session.parameterNames = []
|
||||||
allDeviceUpdates.instanceName = [["#{task.objectName}.#{task.session.instanceNumber}", task.instanceName]] if task.instanceName?
|
|
||||||
else
|
else
|
||||||
callback(null, STATUS_OK, {type : 'AddObject', objectName : "#{task.objectName}."})
|
callback(null, STATUS_OK, {type : 'AddObject', objectName : "#{task.objectName}."})
|
||||||
return
|
return
|
||||||
@@ -251,7 +251,7 @@ this.addObject = (task, methodResponse, callback) ->
|
|||||||
if deviceUpdates and deviceUpdates.parameterValues?
|
if deviceUpdates and deviceUpdates.parameterValues?
|
||||||
for p1 in deviceUpdates.parameterValues
|
for p1 in deviceUpdates.parameterValues
|
||||||
for p2 in task.parameterValues
|
for p2 in task.parameterValues
|
||||||
if common.endsWith(p1[0], ".#{p2[0]}")
|
if p1[0] == "#{task.objectName}.#{task.session.instanceNumber}.#{p2[0]}"
|
||||||
t = if p2[2] then p2[2] else p1[2]
|
t = if p2[2] then p2[2] else p1[2]
|
||||||
v = common.matchType(p1[1], p2[1])
|
v = common.matchType(p1[1], p2[1])
|
||||||
# TODO only include if writable
|
# TODO only include if writable
|
||||||
@@ -322,19 +322,34 @@ this.download = (task, methodResponse, callback) ->
|
|||||||
return
|
return
|
||||||
|
|
||||||
if methodResponse.type isnt 'DownloadResponse'
|
if methodResponse.type isnt 'DownloadResponse'
|
||||||
|
if task.url?
|
||||||
|
methodRequest = {
|
||||||
|
type : 'Download',
|
||||||
|
fileType : task.fileType or '1 Firmware Upgrade Image',
|
||||||
|
url : task.url,
|
||||||
|
username: task.username,
|
||||||
|
password: task.password,
|
||||||
|
successUrl : task.successUrl,
|
||||||
|
failureUrl : task.failureUrl
|
||||||
|
}
|
||||||
|
callback(null, STATUS_OK, methodRequest)
|
||||||
|
else
|
||||||
db.filesCollection.findOne({_id : mongodb.ObjectID(String(task.file))}, (err, file) ->
|
db.filesCollection.findOne({_id : mongodb.ObjectID(String(task.file))}, (err, file) ->
|
||||||
if not file?
|
if err or not file?
|
||||||
callback('File not found')
|
return callback(err or new Error('File not found'))
|
||||||
return
|
|
||||||
else if err?
|
l = {
|
||||||
callback(err)
|
protocol : if config.get('FS_SSL') then 'https' else 'http',
|
||||||
return
|
hostname : config.get('FS_IP'),
|
||||||
|
port : config.get('FS_PORT'),
|
||||||
|
pathname : encodeURIComponent(file.filename)
|
||||||
|
}
|
||||||
|
|
||||||
methodRequest = {
|
methodRequest = {
|
||||||
type : 'Download',
|
type : 'Download',
|
||||||
fileType : file.metadata.fileType,
|
fileType : file.metadata.fileType,
|
||||||
fileSize : file.length,
|
fileSize : file.length,
|
||||||
url : "http://#{config.get('FS_IP')}:#{config.get('FS_PORT')}/#{encodeURIComponent(file.filename)}",
|
url : url.format(l),
|
||||||
successUrl : task.successUrl,
|
successUrl : task.successUrl,
|
||||||
failureUrl : task.failureUrl
|
failureUrl : task.failureUrl
|
||||||
}
|
}
|
||||||
@@ -347,8 +362,8 @@ this.download = (task, methodResponse, callback) ->
|
|||||||
this.customCommand = (task, methodResponse, callback) ->
|
this.customCommand = (task, methodResponse, callback) ->
|
||||||
# TODO implement timeout
|
# TODO implement timeout
|
||||||
customCommands.execute(task.device, task.command, (err, value) ->
|
customCommands.execute(task.device, task.command, (err, value) ->
|
||||||
if err?
|
if err
|
||||||
task.fault = err
|
task.fault = {name : err.name, message : err.message}
|
||||||
callback(null, STATUS_FAULT)
|
callback(null, STATUS_FAULT)
|
||||||
else
|
else
|
||||||
commandName = task.command.split(' ', 2)[0]
|
commandName = task.command.split(' ', 2)[0]
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ commitUpdates = (deviceId, deviceUpdates, commitQueue, callback) ->
|
|||||||
processBatch = (updatesBatch, cb) ->
|
processBatch = (updatesBatch, cb) ->
|
||||||
if updatesBatch.informEvents?
|
if updatesBatch.informEvents?
|
||||||
update['$set']['_lastInform'] = now
|
update['$set']['_lastInform'] = now
|
||||||
update['$set']['_lastBoot'] if '1 BOOT' in updatesBatch.informEvents
|
update['$set']['_lastBoot'] = now if '1 BOOT' in updatesBatch.informEvents
|
||||||
update['$set']['_lastBootstrap'] if '0 BOOTSTRAP' in updatesBatch.informEvents
|
update['$set']['_lastBootstrap'] = now if '0 BOOTSTRAP' in updatesBatch.informEvents
|
||||||
|
|
||||||
if updatesBatch.parameterValues?
|
if updatesBatch.parameterValues?
|
||||||
for p in updatesBatch.parameterValues
|
for p in updatesBatch.parameterValues
|
||||||
@@ -75,10 +75,6 @@ commitUpdates = (deviceId, deviceUpdates, commitQueue, callback) ->
|
|||||||
for p in updatesBatch.deletedObjects
|
for p in updatesBatch.deletedObjects
|
||||||
update['$unset'][p] = 1
|
update['$unset'][p] = 1
|
||||||
|
|
||||||
if updatesBatch.instanceName?
|
|
||||||
for i in updatesBatch.instanceName
|
|
||||||
update['$set']["#{i[0]}._name"] = i[1]
|
|
||||||
|
|
||||||
if updatesBatch.parameterNames?
|
if updatesBatch.parameterNames?
|
||||||
presentPaths ?= {}
|
presentPaths ?= {}
|
||||||
projection ?= {}
|
projection ?= {}
|
||||||
@@ -187,7 +183,7 @@ commitUpdates = (deviceId, deviceUpdates, commitQueue, callback) ->
|
|||||||
if presentPaths[p]
|
if presentPaths[p]
|
||||||
recursive(v, "#{p}.")
|
recursive(v, "#{p}.")
|
||||||
else
|
else
|
||||||
update['$unset'][p] = 1
|
update['$unset'][p] = 2
|
||||||
|
|
||||||
# Scan the DB object and remove parameters that no longer exists in device
|
# Scan the DB object and remove parameters that no longer exists in device
|
||||||
for path of projection
|
for path of projection
|
||||||
@@ -202,7 +198,7 @@ commitUpdates = (deviceId, deviceUpdates, commitQueue, callback) ->
|
|||||||
recursive(root, rootPath)
|
recursive(root, rootPath)
|
||||||
else
|
else
|
||||||
if not presentPaths[rootPath.slice(0, -1)]?
|
if not presentPaths[rootPath.slice(0, -1)]?
|
||||||
update['$unset'][rootPath.slice(0, -1)] = 1
|
update['$unset'][rootPath.slice(0, -1)] = 2
|
||||||
|
|
||||||
# Remove unnecessary unset updates
|
# Remove unnecessary unset updates
|
||||||
for k, v of update['$unset']
|
for k, v of update['$unset']
|
||||||
|
|||||||
+7
-7
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "genieacs",
|
"name": "genieacs",
|
||||||
"version": "1.0.0",
|
"version": "1.0.7",
|
||||||
"description": "A blazing fast TR-069 auto configuration server (ACS) built with Node.js, Redis, and MongoDB",
|
"description": "A blazing fast TR-069 auto configuration server (ACS) built with Node.js, Redis, and MongoDB",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
"ACS"
|
"ACS"
|
||||||
],
|
],
|
||||||
"author": "Zaid Abdulla",
|
"author": "Zaid Abdulla",
|
||||||
"license": "AGPL3",
|
"license": "AGPL-3.0",
|
||||||
"readmeFilename": "README.md",
|
"readmeFilename": "README.md",
|
||||||
"preferGlobal": true,
|
"preferGlobal": true,
|
||||||
"directories": {
|
"directories": {
|
||||||
@@ -20,13 +20,13 @@
|
|||||||
"bin": "bin"
|
"bin": "bin"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"libxmljs": "~0.11.0",
|
"libxmljs": "0.11.0 - 0.14.x",
|
||||||
"redis": "~0.12.1",
|
"redis": "^0.12.1",
|
||||||
"hiredis": "~0.1.17",
|
"hiredis": "0.1.17 - 0.4.x",
|
||||||
"mongodb": "~1.4.8"
|
"mongodb": "^1.4.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"coffee-script": "~1.7.1"
|
"coffee-script": "^1.7.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0 <0.12"
|
"node": ">=0.10.0 <0.12"
|
||||||
|
|||||||
Reference in new issue
Block a user