Ability to specify per device, per product class, or per oui configuration. Reimplemented Libxmljs options on the new configuration system.

This commit is contained in:
Zaid Abdulla committed 2014-08-06 00:45:24 +03:00
1 parent 3d201981e2
commit ee9a35b9b3
10 files changed
+162 -98

No files matched your search

+8 -3
View File
@@ -19,6 +19,11 @@ config = require './config'
cluster = require 'cluster' cluster = require 'cluster'
util = require 'util' util = require 'util'
# Keep current configuration to pass that to workers as environment variables
ENVIRONMENT_VARIABLES = {}
for k, v of config.allConfig
ENVIRONMENT_VARIABLES["GENIEACS_#{k}"] = v
cluster.on('listening', (worker, address) -> cluster.on('listening', (worker, address) ->
util.log("Worker #{worker.process.pid} listening to #{address.address}:#{address.port}") util.log("Worker #{worker.process.pid} listening to #{address.address}:#{address.port}")
@@ -26,12 +31,12 @@ cluster.on('listening', (worker, address) ->
cluster.on('exit', (worker, code, signal) -> cluster.on('exit', (worker, code, signal) ->
util.log("Worker #{worker.process.pid} died (#{worker.process.exitCode})") util.log("Worker #{worker.process.pid} died (#{worker.process.exitCode})")
cluster.fork() cluster.fork(ENVIRONMENT_VARIABLES)
) )
start = (service) -> start = (service) ->
workerProcesses = config["#{service.toUpperCase()}_WORKER_PROCESSES"] workerProcesses = config.get("#{service.toUpperCase()}_WORKER_PROCESSES")
cluster.setupMaster({ cluster.setupMaster({
exec : 'lib/server', exec : 'lib/server',
@@ -39,7 +44,7 @@ start = (service) ->
}) })
for [0 ... workerProcesses] for [0 ... workerProcesses]
cluster.fork() cluster.fork(ENVIRONMENT_VARIABLES)
exports.start = start exports.start = start
+97 -53
View File
@@ -18,64 +18,89 @@
path = require 'path' path = require 'path'
common = require './common' common = require './common'
options = {
CONFIG_DIR : {type : 'string', default : 'config'},
MONGODB_CONNECTION_URL : {type : 'string', default : 'mongodb://127.0.0.1/genieacs'},
REDIS_PORT : {type : 'int', default : 6379},
REDIS_HOST : {type : 'string', default : '127.0.0.1'},
REDIS_DB : {type : 'int', default : 0},
defaults = { CWMP_WORKER_PROCESSES : {type : 'int', default : 4},
CONFIG_DIR : './config', CWMP_PORT : {type : 'int', default : 7547},
CWMP_INTERFACE : {type : 'string', default : '0.0.0.0'},
CWMP_SSL : {type : 'bool', default : false},
MONGODB_CONNECTION_URL : 'mongodb://127.0.0.1/genieacs', NBI_WORKER_PROCESSES : {type : 'int', default : 2},
REDIS_PORT : 6379, NBI_PORT : {type : 'int', default : 7557},
REDIS_HOST : '127.0.0.1', NBI_INTERFACE : {type : 'string', default : '0.0.0.0'},
REDIS_DB : 0, NBI_SSL : {type : 'bool', default : false},
CWMP_WORKER_PROCESSES : 4, FS_WORKER_PROCESSES : {type : 'int', default : 2},
CWMP_PORT : 7547, # CWMP port as assigned by IANA FS_PORT : {type : 'int', default : 7567},
CWMP_INTERFACE : '0.0.0.0', FS_INTERFACE : {type : 'string', default : '0.0.0.0'},
CWMP_SSL : false, FS_SSL : {type : 'bool', default : false},
NBI_WORKER_PROCESSES : 2, FS_IP : {type : 'string', default : '192.168.0.1'},
NBI_PORT : 7557,
NBI_INTERFACE : '0.0.0.0',
NBI_SSL : false,
FS_WORKER_PROCESSES : 2,
FS_PORT : 7567,
FS_INTERFACE : '0.0.0.0',
FS_SSL : false,
FS_IP : '192.168.0.1', # Used when sending download requests to devices
CACHE_DURATION : 60, # in seconds PRESETS_CACHE_DURATION : {type : 'int', default : 86400},
PRESETS_CACHE_DURATION : 86400, LOG_INFORMS : {type : 'bool', default : true},
PRESETS_TIME_PADDING : 1, DEBUG : {type : 'bool', default : false},
RETRY_DELAY : {type : 'int', default : 300},
IGNORE_XML_NAMESPACES : {type : 'bool', default : false},
SESSION_TIMEOUT : {type : 'int', default : 30},
GET_PARAMETER_NAMES_DEPTH_THRESHOLD : {type : 'int', default : 0},
TASK_PARAMETERS_BATCH_SIZE : {type : 'int', default : 32},
LOG_INFORMS : true, # Libxml related configuration
DEBUG : false, XML_PARSE_RECOVER : {type : 'bool'},
DEVICE_ONLINE_THRESHOLD : 4000, XML_PARSE_NOENT : {type : 'bool'},
RETRY_DELAY : 300, XML_PARSE_NOBLANKS : {type : 'bool'},
IGNORE_XML_NAMESPACES : false, # Traverse XML using element's local name only XML_PARSE_NSCLEAN : {type : 'bool'},
SESSION_TIMEOUT : 30, XML_PARSE_NOCDATA : {type : 'bool'},
GET_PARAMETER_NAMES_DEPTH_THRESHOLD : 0, XML_PARSE_IGNORE_ENC : {type : 'bool'},
TASK_PARAMETERS_BATCH_SIZE : 32
# Should probably never be changed
PRESETS_TIME_PADDING : {type : 'int', default : 1},
DEVICE_ONLINE_THRESHOLD : {type : 'int', default : 4000}
} }
exports.LIBXMLJS_OPTIONS = {} allConfig = {}
setConfig = (name, value) -> setConfig = (name, value, commandLineArgument) ->
return true if exports[name]? return true if allConfig[name]?
cast = (val, type) ->
switch type
when 'int'
Number(val)
when 'bool'
String(val).trim().toLowerCase() in ['true', 'on', 'yes', '1']
when 'string'
String(val)
else
null
_value = null _value = null
if defaults[name]? for optionName, optionDetails of options
_value = common.matchType(defaults[name], value) n = optionName
else if common.startsWith(name, 'XML_PARSE_') if commandLineArgument
n = name[10..].toLowerCase() # libxmljs' options are lower case n = n.toLowerCase().replace(/_/g, '-')
_value = common.matchType(true, value)
exports.LIBXMLJS_OPTIONS[n] = _value if name == n
_value = cast(value, optionDetails.type)
n = optionName
else if common.startsWith(name, "#{n}-")
_value = cast(value, optionDetails.type)
n = "#{optionName}-#{name[optionName.length+1..]}"
if _value? if _value?
exports[name] = _value allConfig[n] = _value
# Save as environmnet variable to pass on to any child processes # Save as environmnet variable to pass on to any child processes
process.env["GENIEACS_#{name}"] = _value process.env[n] = _value
return true
return _value? return false
# Command line arguments # Command line arguments
@@ -86,41 +111,60 @@ while argv.length
if arg[0] == '-' if arg[0] == '-'
v = argv.shift() v = argv.shift()
exports.argv[arg] = v exports.argv[arg] = v
n = arg[2..].toUpperCase().replace(/-/g, '_') setConfig(arg[2..], v, true)
setConfig(n, v)
else else
exports.argv.push(arg) exports.argv.push(arg)
# Environment variable # Environment variable
for k, v of process.env for k, v of process.env
continue if k.lastIndexOf('GENIEACS_', 0) != 0
k = k[9..] # remove "GENIEACS_" prefix k = k[9..] # remove "GENIEACS_" prefix
setConfig(k, v) setConfig(k, v)
# Find config dir # Find config dir
if exports.argv['--config-dir']? if exports.argv['--config-dir']?
exports.CONFIG_DIR = exports.argv['--config-dir'] allConfig.CONFIG_DIR = exports.argv['--config-dir']
else if process.env['GENIEACS_CONFIG_DIR']? else if process.env['GENIEACS_CONFIG_DIR']?
exports.CONFIG_DIR = process.env['GENIEACS_CONFIG_DIR'] allConfig.CONFIG_DIR = process.env['GENIEACS_CONFIG_DIR']
else else
exports.CONFIG_DIR = defaults.CONFIG_DIR allConfig.CONFIG_DIR = options.CONFIG_DIR.default
# Configuration file # Configuration file
for k, v of require(path.resolve(exports.CONFIG_DIR, 'config')) for k, v of require(path.resolve(allConfig.CONFIG_DIR, 'config'))
setConfig(k, v) setConfig(k, v)
# Defaults # Defaults
for k, v of defaults for k, v of options
setConfig(k, v) setConfig(k, v.default) if v.default?
get = (option, deviceId) ->
if deviceId?
name = "#{option}-#{deviceId}"
v = allConfig[name]
return v if v?
i = name.lastIndexOf('-')
v = allConfig[name[0...i]]
return v if v?
i = name.lastIndexOf('-', i-1)
v = allConfig[name[0...i]]
return v if v? or i == -1
return allConfig[option]
# load parameter configurations # load parameter configurations
exports.PARAMETERS = require(path.resolve(exports.CONFIG_DIR, 'parameters')) exports.PARAMETERS = require(path.resolve(allConfig.CONFIG_DIR, 'parameters'))
# load authentication scripts # load authentication scripts
exports.auth = require(path.resolve(exports.CONFIG_DIR, 'auth')) exports.auth = require(path.resolve(allConfig.CONFIG_DIR, 'auth'))
exports.CUSTOM_COMMANDS = require(path.resolve(exports.CONFIG_DIR, 'custom_commands')) exports.CUSTOM_COMMANDS = require(path.resolve(allConfig.CONFIG_DIR, 'custom_commands'))
exports.get = get
exports.allConfig = allConfig
+19 -13
View File
@@ -58,7 +58,7 @@ holdUntil = Date.now()
writeResponse = (currentRequest, res) -> writeResponse = (currentRequest, res) ->
if config.DEBUG if config.get('DEBUG', currentRequest.session.deviceId)
dump = "# RESPONSE #{new Date(Date.now())}\n" + JSON.stringify(res.headers) + "\n#{res.data}\n\n" dump = "# RESPONSE #{new Date(Date.now())}\n" + JSON.stringify(res.headers) + "\n#{res.data}\n\n"
require('fs').appendFile("../debug/#{currentRequest.session.deviceId}.dump", dump, (err) -> require('fs').appendFile("../debug/#{currentRequest.session.deviceId}.dump", dump, (err) ->
throw err if err throw err if err
@@ -102,7 +102,8 @@ inform = (currentRequest, cwmpRequest) ->
now = new Date(Date.now()) now = new Date(Date.now())
util.log("#{currentRequest.session.deviceId}: Inform (#{cwmpRequest.methodRequest.event}); retry count #{cwmpRequest.methodRequest.retryCount}") if config.LOG_INFORMS if config.get('LOG_INFORMS', currentRequest.session.deviceId)
util.log("#{currentRequest.session.deviceId}: Inform (#{cwmpRequest.methodRequest.event}); retry count #{cwmpRequest.methodRequest.retryCount}")
parameterNames = (p[0] for p in cwmpRequest.methodRequest.parameterList) parameterNames = (p[0] for p in cwmpRequest.methodRequest.parameterList)
@@ -138,7 +139,7 @@ inform = (currentRequest, cwmpRequest) ->
if oldInformHash == informHash and not lastBootstrap? if oldInformHash == informHash and not lastBootstrap?
return updateAndRespond() return updateAndRespond()
db.redisClient.setex("#{currentRequest.session.deviceId}_inform_hash", config.PRESETS_CACHE_DURATION, informHash, (err, res) -> db.redisClient.setex("#{currentRequest.session.deviceId}_inform_hash", config.get('PRESETS_CACHE_DURATION', currentRequest.session.deviceId), informHash, (err, res) ->
throw err if err throw err if err
) )
@@ -234,7 +235,7 @@ runTask = (currentRequest, task, methodResponse) ->
switch status & ~tasks.STATUS_SAVE switch status & ~tasks.STATUS_SAVE
when tasks.STATUS_OK when tasks.STATUS_OK
f = () -> f = () ->
db.redisClient.setex(String(task._id), config.CACHE_DURATION, JSON.stringify(task), (err) -> db.redisClient.setex(String(task._id), currentRequest.session.sessionTimeout, JSON.stringify(task), (err) ->
throw err if err throw err if err
res = soap.response({ res = soap.response({
id : task._id, id : task._id,
@@ -268,7 +269,7 @@ runTask = (currentRequest, task, methodResponse) ->
) )
) )
when tasks.STATUS_FAULT when tasks.STATUS_FAULT
retryAfter = config.RETRY_DELAY * Math.pow(2, task.retries ? 0) retryAfter = config.get('RETRY_DELAY', currentRequest.session.deviceId) * Math.pow(2, task.retries ? 0)
util.log("#{currentRequest.session.deviceId}: Fault response for task #{task._id}. Retrying after #{retryAfter} seconds.") util.log("#{currentRequest.session.deviceId}: Fault response for task #{task._id}. Retrying after #{retryAfter} seconds.")
taskUpdate = {fault : task.fault, timestamp : new Date(Date.now() + retryAfter * 1000)} taskUpdate = {fault : task.fault, timestamp : new Date(Date.now() + retryAfter * 1000)}
if save if save
@@ -297,16 +298,17 @@ assertPresets = (currentRequest) ->
# no discrepancy, end the session # no discrepancy, end the session
endSession(currentRequest) endSession(currentRequest)
else else
PRESETS_CACHE_DURATION = config.get('PRESETS_CACHE_DURATION', currentRequest.session.deviceId)
db.getPresetsObjectsAliases((allPresets, allObjects, allAliases) -> db.getPresetsObjectsAliases((allPresets, allObjects, allAliases) ->
if not presetsHash? if not presetsHash?
presetsHash = presets.calculatePresetsHash(allPresets, allObjects) presetsHash = presets.calculatePresetsHash(allPresets, allObjects)
db.redisClient.setex('presets_hash', config.PRESETS_CACHE_DURATION, presetsHash, (err, res) -> db.redisClient.setex('presets_hash', PRESETS_CACHE_DURATION, presetsHash, (err, res) ->
throw err if err throw err if err
) )
presets.getDevicePreset(currentRequest.session.deviceId, allPresets, allObjects, allAliases, (devicePreset) -> presets.getDevicePreset(currentRequest.session.deviceId, allPresets, allObjects, allAliases, (devicePreset) ->
presets.processDevicePreset(currentRequest.session.deviceId, devicePreset, (taskList, addTags, deleteTags, expiry) -> presets.processDevicePreset(currentRequest.session.deviceId, devicePreset, (taskList, addTags, deleteTags, expiry) ->
db.redisClient.setex("#{currentRequest.session.deviceId}_presets_hash", Math.floor(Math.max(1, expiry - config.PRESETS_TIME_PADDING)), presetsHash, (err, res) -> db.redisClient.setex("#{currentRequest.session.deviceId}_presets_hash", Math.floor(Math.max(1, expiry - config.get('PRESETS_TIME_PADDING'))), presetsHash, (err, res) ->
throw err if err throw err if err
) )
@@ -436,12 +438,16 @@ listener = (httpRequest, httpResponse) ->
httpResponse.writeHead(400) httpResponse.writeHead(400)
httpResponse.end('Session is expired') httpResponse.end('Session is expired')
return return
session = {
deviceId : common.generateDeviceId(cwmpRequest.methodRequest.deviceId), deviceId = common.generateDeviceId(cwmpRequest.methodRequest.deviceId)
cwmpVersion : cwmpRequest.cwmpVersion,
sessionTimeout : cwmpRequest.sessionTimeout ? config.SESSION_TIMEOUT
}
sessionId = crypto.randomBytes(8).toString('hex') sessionId = crypto.randomBytes(8).toString('hex')
session = {
deviceId : deviceId,
cwmpVersion : cwmpRequest.cwmpVersion,
sessionTimeout : cwmpRequest.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId)
}
httpRequest.connection.setTimeout(session.sessionTimeout * 1000) httpRequest.connection.setTimeout(session.sessionTimeout * 1000)
currentRequest = { currentRequest = {
@@ -451,7 +457,7 @@ listener = (httpRequest, httpResponse) ->
session : session session : session
} }
if config.DEBUG if config.get('DEBUG', currentRequest.session.deviceId)
dump = "# REQUEST #{new Date(Date.now())}\n" + JSON.stringify(httpRequest.headers) + "\n#{httpRequest.getBody()}\n\n" dump = "# REQUEST #{new Date(Date.now())}\n" + JSON.stringify(httpRequest.headers) + "\n#{httpRequest.getBody()}\n\n"
require('fs').appendFile("../debug/#{currentRequest.session.deviceId}.dump", dump, (err) -> require('fs').appendFile("../debug/#{currentRequest.session.deviceId}.dump", dump, (err) ->
throw err if err throw err if err
+7 -7
View File
@@ -52,7 +52,7 @@ flushRedis = (callback) ->
connect = (callback) -> connect = (callback) ->
callbackCounter = 6 callbackCounter = 6
mongodb.MongoClient.connect(config.MONGODB_CONNECTION_URL, {db:{w:1},server:{autoReconnect:true}}, (err, db) -> mongodb.MongoClient.connect(config.get('MONGODB_CONNECTION_URL'), {db:{w:1},server:{autoReconnect:true}}, (err, db) ->
return callback(err) if err return callback(err) if err
exports.mongoDb = db exports.mongoDb = db
db.collection('tasks', (err, collection) -> db.collection('tasks', (err, collection) ->
@@ -93,8 +93,8 @@ connect = (callback) ->
return callback(err) return callback(err)
) )
exports.redisClient = redisClient = redis.createClient(config.REDIS_PORT, config.REDIS_HOST) exports.redisClient = redisClient = redis.createClient(config.get('REDIS_PORT'), config.get('REDIS_HOST'))
redisClient.select(config.REDIS_DB, (err) -> redisClient.select(config.get('REDIS_DB'), (err) ->
if err if err
callbackCounter = 0 callbackCounter = 0
return callback(err) return callback(err)
@@ -174,7 +174,7 @@ getCached = (name, valueCallback, valueExpiry, callback) ->
getAliases = (callback) -> getAliases = (callback) ->
getCached('aliases', parameters.compileAliases, config.PRESETS_CACHE_DURATION, (err, res) -> getCached('aliases', parameters.compileAliases, config.get('PRESETS_CACHE_DURATION'), (err, res) ->
throw err if err throw err if err
callback(res) callback(res)
) )
@@ -194,7 +194,7 @@ getPresetsObjectsAliases = (callback) ->
presetsCollection.find().toArray((err, res) -> presetsCollection.find().toArray((err, res) ->
callback(err, res) callback(err, res)
) )
, config.PRESETS_CACHE_DURATION, (err, res) -> , config.get('PRESETS_CACHE_DURATION'), (err, res) ->
throw err if err throw err if err
presets = res presets = res
callback(presets, objects, aliases) if objects and aliases callback(presets, objects, aliases) if objects and aliases
@@ -208,14 +208,14 @@ getPresetsObjectsAliases = (callback) ->
objs[r._id] = r for r in res objs[r._id] = r for r in res
callback(null, objs) callback(null, objs)
) )
, config.PRESETS_CACHE_DURATION, (err, res) -> , config.get('PRESETS_CACHE_DURATION'), (err, res) ->
throw err if err throw err if err
objects = res objects = res
callback(presets, objects, aliases) if presets and aliases callback(presets, objects, aliases) if presets and aliases
) )
if not aliases if not aliases
getCached('aliases', parameters.compileAliases, config.PRESETS_CACHE_DURATION, (err, res) -> getCached('aliases', parameters.compileAliases, config.get('PRESETS_CACHE_DURATION'), (err, res) ->
throw err if err throw err if err
aliases = res aliases = res
callback(presets, objects, aliases) if presets and objects callback(presets, objects, aliases) if presets and objects
+1 -1
View File
@@ -198,7 +198,7 @@ listener = (request, response) ->
response.writeHead(202) response.writeHead(202)
response.end() response.end()
else else
apiFunctions.watchTask(task._id, config.DEVICE_ONLINE_THRESHOLD, (err) -> apiFunctions.watchTask(task._id, config.get('DEVICE_ONLINE_THRESHOLD', deviceId), (err) ->
if err if err
response.writeHead(202) response.writeHead(202)
response.end() response.end()
+2 -2
View File
@@ -177,7 +177,7 @@ compileAliases = (callback) ->
counter = 0 counter = 0
splitIds(4, (batches) -> splitIds(4, (batches) ->
if not batches? if not batches?
return callback(null, aliases, config.ALIASES_CACHE) return callback(null, aliases)
for batch in batches for batch in batches
options = { options = {
@@ -201,7 +201,7 @@ compileAliases = (callback) ->
aliases[alias].push(id) aliases[alias].push(id)
if ++counter == batches.length if ++counter == batches.length
callback?(null, aliases, config.ALIASES_CACHE) callback?(null, aliases)
) )
return return
) )
+4 -3
View File
@@ -218,8 +218,9 @@ exports.getDevicePreset = (deviceId, presets, objects, aliases, callback) ->
exports.processDevicePreset = (deviceId, devicePreset, callback) -> exports.processDevicePreset = (deviceId, devicePreset, callback) ->
PRESETS_TIME_PADDING = config.get('PRESETS_TIME_PADDING')
now = new Date() now = new Date()
expiry = config.PRESETS_CACHE_DURATION expiry = config.get('PRESETS_CACHE_DURATION', deviceId)
getParameterValues = [] getParameterValues = []
setParameterValues = [] setParameterValues = []
addTags = [] addTags = []
@@ -236,7 +237,7 @@ exports.processDevicePreset = (deviceId, devicePreset, callback) ->
setParameterValues.push([parameterPath, presetValue, parameterDetails.current._type]) setParameterValues.push([parameterPath, presetValue, parameterDetails.current._type])
else if parameterDetails.preset.expiry? else if parameterDetails.preset.expiry?
diff = parameterDetails.preset.expiry - (now - (parameterDetails.current._timestamp ? 0)) / 1000 diff = parameterDetails.preset.expiry - (now - (parameterDetails.current._timestamp ? 0)) / 1000
if diff <= config.PRESETS_TIME_PADDING if diff <= PRESETS_TIME_PADDING
if parameterDetails.current._value? if parameterDetails.current._value?
getParameterValues.push(parameterPath) getParameterValues.push(parameterPath)
else else
@@ -284,7 +285,7 @@ exports.processDevicePreset = (deviceId, devicePreset, callback) ->
taskList.push({device : deviceId, name : 'customCommand', command : commandDetails.preset.valueCommand}) taskList.push({device : deviceId, name : 'customCommand', command : commandDetails.preset.valueCommand})
else if commandDetails.preset.expiry? else if commandDetails.preset.expiry?
diff = commandDetails.preset.expiry - (now - (commandDetails.current._timestamp ? 0)) / 1000 diff = commandDetails.preset.expiry - (now - (commandDetails.current._timestamp ? 0)) / 1000
if diff <= config.PRESETS_TIME_PADDING if diff <= PRESETS_TIME_PADDING
taskList.push({device : deviceId, name : 'customCommand', command : commandDetails.preset.expiryCommand}) taskList.push({device : deviceId, name : 'customCommand', command : commandDetails.preset.expiryCommand})
else else
expiry = Math.min(expiry, diff) expiry = Math.min(expiry, diff)
+5 -5
View File
@@ -25,9 +25,9 @@ service = config.argv[0]
if not service? if not service?
throw new Error('Missing argument cwmp, fs, or nbi') throw new Error('Missing argument cwmp, fs, or nbi')
networkInterface = config["#{service.toUpperCase()}_INTERFACE"] networkInterface = config.get("#{service.toUpperCase()}_INTERFACE")
port = config["#{service.toUpperCase()}_PORT"] port = config.get("#{service.toUpperCase()}_PORT")
useHttps = config["#{service.toUpperCase()}_SSL"] useHttps = config.get("#{service.toUpperCase()}_SSL")
serviceListener = require("./#{service}").listener serviceListener = require("./#{service}").listener
@@ -67,8 +67,8 @@ listener = (httpRequest, httpResponse) ->
if useHttps if useHttps
path = require 'path' path = require 'path'
fs = require 'fs' fs = require 'fs'
httpsKey = path.resolve(config.CONFIG_DIR, "#{service}.key") httpsKey = path.resolve(config.get('CONFIG_DIR'), "#{service}.key")
httpsCert = path.resolve(config.CONFIG_DIR, "#{service}.crt") httpsCert = path.resolve(config.get('CONFIG_DIR'), "#{service}.crt")
options = { options = {
key: fs.readFileSync(httpsKey), key: fs.readFileSync(httpsKey),
cert: fs.readFileSync(httpsCert) cert: fs.readFileSync(httpsCert)
+9 -3
View File
@@ -81,9 +81,15 @@ NAMESPACES = {
} }
} }
# Generate Libxmljs options
LIBXMLJS_OPTIONS = {}
for k, v of config.allConfig
if k.lastIndexOf('XML_PARSE_', 0) == 0
LIBXMLJS_OPTIONS[k] = v
# Workaround for devices that don't use correct namespace declarations or prefixes # Workaround for devices that don't use correct namespace declarations or prefixes
if config.IGNORE_XML_NAMESPACES if config.get('IGNORE_XML_NAMESPACES')
libxmljs.Element.prototype.__find = libxmljs.Element.prototype.find libxmljs.Element.prototype.__find = libxmljs.Element.prototype.find
libxmljs.Element.prototype.find = (xpath, namespaces) -> libxmljs.Element.prototype.find = (xpath, namespaces) ->
# Modify xpath queries to work regardless of element's namespace # Modify xpath queries to work regardless of element's namespace
@@ -291,7 +297,7 @@ exports.request = (httpRequest, cwmpVersion) ->
data = httpRequest.getBody() data = httpRequest.getBody()
if data.length > 0 if data.length > 0
xml = libxmljs.parseXml(data, config.LIBXMLJS_OPTIONS) xml = libxmljs.parseXml(data, LIBXMLJS_OPTIONS)
if not cwmpRequest.cwmpVersion? if not cwmpRequest.cwmpVersion?
# cwmpVersion not passed, thus it's an inform request # cwmpVersion not passed, thus it's an inform request
@@ -318,7 +324,7 @@ exports.request = (httpRequest, cwmpVersion) ->
cwmpRequest.id = try xml.get('/soap-env:Envelope/soap-env:Header/cwmp:ID', NAMESPACES[cwmpRequest.cwmpVersion]).text() catch then null cwmpRequest.id = try xml.get('/soap-env:Envelope/soap-env:Header/cwmp:ID', NAMESPACES[cwmpRequest.cwmpVersion]).text() catch then null
if methodElement? and not (config.IGNORE_XML_NAMESPACES and methodElement.name() is 'Fault') if methodElement? and not (config.get('IGNORE_XML_NAMESPACES') and methodElement.name() is 'Fault')
switch methodElement.name() switch methodElement.name()
when 'Inform' when 'Inform'
cwmpRequest.methodRequest = acsInform(methodElement) cwmpRequest.methodRequest = acsInform(methodElement)
+10 -8
View File
@@ -72,7 +72,7 @@ this.refreshObject = (task, methodResponse, callback) ->
task.session.parameterNames.push(p[0]) task.session.parameterNames.push(p[0])
if status & STATUS_COMPLETED if status & STATUS_COMPLETED
task.session.subtask = {name : 'getParameterValues', parameterNames : task.session.parameterNames} task.session.subtask = {device : task.device, name : 'getParameterValues', parameterNames : task.session.parameterNames}
delete task.session.parameterNames delete task.session.parameterNames
this.getParameterValues(task.session.subtask, {}, (err, status, methodRequest) -> this.getParameterValues(task.session.subtask, {}, (err, status, methodRequest) ->
@@ -102,6 +102,8 @@ this.getParameterNames = (task, methodResponse, callback) ->
callback(null, STATUS_FAULT) callback(null, STATUS_FAULT)
return return
GET_PARAMETER_NAMES_DEPTH_THRESHOLD = config.get('GET_PARAMETER_NAMES_DEPTH_THRESHOLD', task.device)
getParameterDepth = (param) -> getParameterDepth = (param) ->
return 0 if !param return 0 if !param
return (param[...-1] + '.').split('.').length - 1 return (param[...-1] + '.').split('.').length - 1
@@ -110,7 +112,7 @@ this.getParameterNames = (task, methodResponse, callback) ->
path = task.session.queue.pop() path = task.session.queue.pop()
# If parameter depth higher than the threshold, nextLevel was set to false # If parameter depth higher than the threshold, nextLevel was set to false
if not task.nextLevel? and getParameterDepth(path) < config.GET_PARAMETER_NAMES_DEPTH_THRESHOLD if not task.nextLevel? and getParameterDepth(path) < GET_PARAMETER_NAMES_DEPTH_THRESHOLD
for p in methodResponse.parameterList for p in methodResponse.parameterList
task.session.queue.push(p[0]) if p[0][-1..] == '.' task.session.queue.push(p[0]) if p[0][-1..] == '.'
@@ -138,7 +140,7 @@ this.getParameterNames = (task, methodResponse, callback) ->
methodRequest = { methodRequest = {
type : 'GetParameterNames', type : 'GetParameterNames',
parameterPath : path, parameterPath : path,
nextLevel : task.nextLevel ? getParameterDepth(path) < config.GET_PARAMETER_NAMES_DEPTH_THRESHOLD nextLevel : task.nextLevel ? getParameterDepth(path) < GET_PARAMETER_NAMES_DEPTH_THRESHOLD
} }
return callback(null, STATUS_OK, methodRequest, deviceUpdates) return callback(null, STATUS_OK, methodRequest, deviceUpdates)
else else
@@ -158,7 +160,7 @@ this.getParameterValues = (task, methodResponse, callback) ->
else if methodResponse.parameterList? else if methodResponse.parameterList?
task.session.currentIndex = task.session.nextIndex task.session.currentIndex = task.session.nextIndex
task.session.nextIndex = Math.min(task.session.currentIndex + config.TASK_PARAMETERS_BATCH_SIZE, task.parameterNames.length) task.session.nextIndex = Math.min(task.session.currentIndex + config.get('TASK_PARAMETERS_BATCH_SIZE', task.device), task.parameterNames.length)
names = task.parameterNames.slice(task.session.currentIndex, task.session.nextIndex) names = task.parameterNames.slice(task.session.currentIndex, task.session.nextIndex)
if methodResponse.type is 'GetParameterValuesResponse' if methodResponse.type is 'GetParameterValuesResponse'
@@ -188,7 +190,7 @@ this.setParameterValues = (task, methodResponse, callback) ->
prevValues = task.parameterValues.slice(task.session.currentIndex, task.session.nextIndex) prevValues = task.parameterValues.slice(task.session.currentIndex, task.session.nextIndex)
task.session.currentIndex = task.session.nextIndex task.session.currentIndex = task.session.nextIndex
task.session.nextIndex = Math.min(task.session.currentIndex + config.TASK_PARAMETERS_BATCH_SIZE, task.parameterValues.length) task.session.nextIndex = Math.min(task.session.currentIndex + config.get('TASK_PARAMETERS_BATCH_SIZE', task.device), task.parameterValues.length)
values = task.parameterValues.slice(task.session.currentIndex, task.session.nextIndex) values = task.parameterValues.slice(task.session.currentIndex, task.session.nextIndex)
if prevValues? if prevValues?
@@ -233,7 +235,7 @@ this.addObject = (task, methodResponse, callback) ->
task.session.parameterNames.push(p[0]) if not common.endsWith(p[0], '.') task.session.parameterNames.push(p[0]) if not common.endsWith(p[0], '.')
if status & STATUS_COMPLETED if status & STATUS_COMPLETED
task.session.subtask = {name : 'getParameterValues', parameterNames : task.session.parameterNames} task.session.subtask = {device : task.device, name : 'getParameterValues', parameterNames : task.session.parameterNames}
subtask() subtask()
else if status & STATUS_OK else if status & STATUS_OK
# Use STATUS_SAVE to avoid adding duplicate object in case of error # Use STATUS_SAVE to avoid adding duplicate object in case of error
@@ -260,7 +262,7 @@ this.addObject = (task, methodResponse, callback) ->
return callback(null, STATUS_FAULT) return callback(null, STATUS_FAULT)
if status & STATUS_COMPLETED and task.session.appliedParameterValues.length > 0 if status & STATUS_COMPLETED and task.session.appliedParameterValues.length > 0
task.session.subtask = {name : 'setParameterValues', parameterValues : task.session.appliedParameterValues} task.session.subtask = {device : task.device, name : 'setParameterValues', parameterValues : task.session.appliedParameterValues}
subtask() subtask()
else else
callback(err, status, methodRequest, allDeviceUpdates) callback(err, status, methodRequest, allDeviceUpdates)
@@ -332,7 +334,7 @@ this.download = (task, methodResponse, callback) ->
type : 'Download', type : 'Download',
fileType : file.metadata.fileType, fileType : file.metadata.fileType,
fileSize : file.length, fileSize : file.length,
url : "http://#{config.FS_IP}:#{config.FS_PORT}/#{encodeURIComponent(file.filename)}", url : "http://#{config.get('FS_IP')}:#{config.get('FS_PORT')}/#{encodeURIComponent(file.filename)}",
successUrl : task.successUrl, successUrl : task.successUrl,
failureUrl : task.failureUrl failureUrl : task.failureUrl
} }