From ee9a35b9b33022ddd644fd2f01afc675319d936f Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Wed, 6 Aug 2014 00:45:24 +0300 Subject: [PATCH] Ability to specify per device, per product class, or per oui configuration. Reimplemented Libxmljs options on the new configuration system. --- lib/cluster.coffee | 11 ++- lib/config.coffee | 154 +++++++++++++++++++++++++++--------------- lib/cwmp.coffee | 32 +++++---- lib/db.coffee | 14 ++-- lib/nbi.coffee | 2 +- lib/parameters.coffee | 4 +- lib/presets.coffee | 7 +- lib/server.coffee | 10 +-- lib/soap.coffee | 12 +++- lib/tasks.coffee | 18 ++--- 10 files changed, 164 insertions(+), 100 deletions(-) diff --git a/lib/cluster.coffee b/lib/cluster.coffee index 9ea3d98..4550368 100644 --- a/lib/cluster.coffee +++ b/lib/cluster.coffee @@ -19,6 +19,11 @@ config = require './config' cluster = require 'cluster' 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) -> 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) -> util.log("Worker #{worker.process.pid} died (#{worker.process.exitCode})") - cluster.fork() + cluster.fork(ENVIRONMENT_VARIABLES) ) start = (service) -> - workerProcesses = config["#{service.toUpperCase()}_WORKER_PROCESSES"] + workerProcesses = config.get("#{service.toUpperCase()}_WORKER_PROCESSES") cluster.setupMaster({ exec : 'lib/server', @@ -39,7 +44,7 @@ start = (service) -> }) for [0 ... workerProcesses] - cluster.fork() + cluster.fork(ENVIRONMENT_VARIABLES) exports.start = start diff --git a/lib/config.coffee b/lib/config.coffee index 113578f..81559d8 100644 --- a/lib/config.coffee +++ b/lib/config.coffee @@ -18,64 +18,89 @@ path = require 'path' 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 = { - CONFIG_DIR : './config', + CWMP_WORKER_PROCESSES : {type : 'int', default : 4}, + 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', - REDIS_PORT : 6379, - REDIS_HOST : '127.0.0.1', - REDIS_DB : 0, + NBI_WORKER_PROCESSES : {type : 'int', default : 2}, + NBI_PORT : {type : 'int', default : 7557}, + NBI_INTERFACE : {type : 'string', default : '0.0.0.0'}, + NBI_SSL : {type : 'bool', default : false}, - CWMP_WORKER_PROCESSES : 4, - CWMP_PORT : 7547, # CWMP port as assigned by IANA - CWMP_INTERFACE : '0.0.0.0', - CWMP_SSL : false, - NBI_WORKER_PROCESSES : 2, - 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 + FS_WORKER_PROCESSES : {type : 'int', default : 2}, + FS_PORT : {type : 'int', default : 7567}, + FS_INTERFACE : {type : 'string', default : '0.0.0.0'}, + FS_SSL : {type : 'bool', default : false}, + FS_IP : {type : 'string', default : '192.168.0.1'}, - CACHE_DURATION : 60, # in seconds - PRESETS_CACHE_DURATION : 86400, - PRESETS_TIME_PADDING : 1, + PRESETS_CACHE_DURATION : {type : 'int', default : 86400}, + LOG_INFORMS : {type : 'bool', default : true}, + 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, - DEBUG : false, - DEVICE_ONLINE_THRESHOLD : 4000, - RETRY_DELAY : 300, - IGNORE_XML_NAMESPACES : false, # Traverse XML using element's local name only - SESSION_TIMEOUT : 30, - GET_PARAMETER_NAMES_DEPTH_THRESHOLD : 0, - TASK_PARAMETERS_BATCH_SIZE : 32 + # Libxml related configuration + XML_PARSE_RECOVER : {type : 'bool'}, + XML_PARSE_NOENT : {type : 'bool'}, + XML_PARSE_NOBLANKS : {type : 'bool'}, + XML_PARSE_NSCLEAN : {type : 'bool'}, + XML_PARSE_NOCDATA : {type : 'bool'}, + XML_PARSE_IGNORE_ENC : {type : 'bool'}, + + # 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) -> - return true if exports[name]? +setConfig = (name, value, commandLineArgument) -> + 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 - if defaults[name]? - _value = common.matchType(defaults[name], value) - else if common.startsWith(name, 'XML_PARSE_') - n = name[10..].toLowerCase() # libxmljs' options are lower case - _value = common.matchType(true, value) - exports.LIBXMLJS_OPTIONS[n] = _value + for optionName, optionDetails of options + n = optionName + if commandLineArgument + n = n.toLowerCase().replace(/_/g, '-') - if _value? - exports[name] = _value - # Save as environmnet variable to pass on to any child processes - process.env["GENIEACS_#{name}"] = _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..]}" - return _value? + if _value? + allConfig[n] = _value + # Save as environmnet variable to pass on to any child processes + process.env[n] = _value + return true + + return false # Command line arguments @@ -86,41 +111,60 @@ while argv.length if arg[0] == '-' v = argv.shift() exports.argv[arg] = v - n = arg[2..].toUpperCase().replace(/-/g, '_') - setConfig(n, v) + setConfig(arg[2..], v, true) else exports.argv.push(arg) # Environment variable for k, v of process.env + continue if k.lastIndexOf('GENIEACS_', 0) != 0 k = k[9..] # remove "GENIEACS_" prefix setConfig(k, v) # Find 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']? - exports.CONFIG_DIR = process.env['GENIEACS_CONFIG_DIR'] + allConfig.CONFIG_DIR = process.env['GENIEACS_CONFIG_DIR'] else - exports.CONFIG_DIR = defaults.CONFIG_DIR + allConfig.CONFIG_DIR = options.CONFIG_DIR.default # 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) # Defaults -for k, v of defaults - setConfig(k, v) +for k, v of options + 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 -exports.PARAMETERS = require(path.resolve(exports.CONFIG_DIR, 'parameters')) +exports.PARAMETERS = require(path.resolve(allConfig.CONFIG_DIR, 'parameters')) # 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 diff --git a/lib/cwmp.coffee b/lib/cwmp.coffee index 28705b9..67f956c 100644 --- a/lib/cwmp.coffee +++ b/lib/cwmp.coffee @@ -58,7 +58,7 @@ holdUntil = Date.now() 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" require('fs').appendFile("../debug/#{currentRequest.session.deviceId}.dump", dump, (err) -> throw err if err @@ -102,7 +102,8 @@ inform = (currentRequest, cwmpRequest) -> 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) @@ -138,7 +139,7 @@ inform = (currentRequest, cwmpRequest) -> if oldInformHash == informHash and not lastBootstrap? 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 ) @@ -234,7 +235,7 @@ runTask = (currentRequest, task, methodResponse) -> switch status & ~tasks.STATUS_SAVE when tasks.STATUS_OK 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 res = soap.response({ id : task._id, @@ -268,7 +269,7 @@ runTask = (currentRequest, task, methodResponse) -> ) ) 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.") taskUpdate = {fault : task.fault, timestamp : new Date(Date.now() + retryAfter * 1000)} if save @@ -297,16 +298,17 @@ assertPresets = (currentRequest) -> # no discrepancy, end the session endSession(currentRequest) else + PRESETS_CACHE_DURATION = config.get('PRESETS_CACHE_DURATION', currentRequest.session.deviceId) db.getPresetsObjectsAliases((allPresets, allObjects, allAliases) -> if not presetsHash? 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 ) presets.getDevicePreset(currentRequest.session.deviceId, allPresets, allObjects, allAliases, (devicePreset) -> 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 ) @@ -436,12 +438,16 @@ listener = (httpRequest, httpResponse) -> httpResponse.writeHead(400) httpResponse.end('Session is expired') return - session = { - deviceId : common.generateDeviceId(cwmpRequest.methodRequest.deviceId), - cwmpVersion : cwmpRequest.cwmpVersion, - sessionTimeout : cwmpRequest.sessionTimeout ? config.SESSION_TIMEOUT - } + + deviceId = common.generateDeviceId(cwmpRequest.methodRequest.deviceId) 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) currentRequest = { @@ -451,7 +457,7 @@ listener = (httpRequest, httpResponse) -> 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" require('fs').appendFile("../debug/#{currentRequest.session.deviceId}.dump", dump, (err) -> throw err if err diff --git a/lib/db.coffee b/lib/db.coffee index a9483b3..94092c8 100644 --- a/lib/db.coffee +++ b/lib/db.coffee @@ -52,7 +52,7 @@ flushRedis = (callback) -> connect = (callback) -> 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 exports.mongoDb = db db.collection('tasks', (err, collection) -> @@ -93,8 +93,8 @@ connect = (callback) -> return callback(err) ) - exports.redisClient = redisClient = redis.createClient(config.REDIS_PORT, config.REDIS_HOST) - redisClient.select(config.REDIS_DB, (err) -> + exports.redisClient = redisClient = redis.createClient(config.get('REDIS_PORT'), config.get('REDIS_HOST')) + redisClient.select(config.get('REDIS_DB'), (err) -> if err callbackCounter = 0 return callback(err) @@ -174,7 +174,7 @@ getCached = (name, valueCallback, valueExpiry, 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 callback(res) ) @@ -194,7 +194,7 @@ getPresetsObjectsAliases = (callback) -> presetsCollection.find().toArray((err, res) -> callback(err, res) ) - , config.PRESETS_CACHE_DURATION, (err, res) -> + , config.get('PRESETS_CACHE_DURATION'), (err, res) -> throw err if err presets = res callback(presets, objects, aliases) if objects and aliases @@ -208,14 +208,14 @@ getPresetsObjectsAliases = (callback) -> objs[r._id] = r for r in res callback(null, objs) ) - , config.PRESETS_CACHE_DURATION, (err, res) -> + , config.get('PRESETS_CACHE_DURATION'), (err, res) -> throw err if err objects = res callback(presets, objects, aliases) if presets and 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 aliases = res callback(presets, objects, aliases) if presets and objects diff --git a/lib/nbi.coffee b/lib/nbi.coffee index d7cb943..cb88dbf 100644 --- a/lib/nbi.coffee +++ b/lib/nbi.coffee @@ -198,7 +198,7 @@ listener = (request, response) -> response.writeHead(202) response.end() else - apiFunctions.watchTask(task._id, config.DEVICE_ONLINE_THRESHOLD, (err) -> + apiFunctions.watchTask(task._id, config.get('DEVICE_ONLINE_THRESHOLD', deviceId), (err) -> if err response.writeHead(202) response.end() diff --git a/lib/parameters.coffee b/lib/parameters.coffee index 9c87c4f..a5b7180 100644 --- a/lib/parameters.coffee +++ b/lib/parameters.coffee @@ -177,7 +177,7 @@ compileAliases = (callback) -> counter = 0 splitIds(4, (batches) -> if not batches? - return callback(null, aliases, config.ALIASES_CACHE) + return callback(null, aliases) for batch in batches options = { @@ -201,7 +201,7 @@ compileAliases = (callback) -> aliases[alias].push(id) if ++counter == batches.length - callback?(null, aliases, config.ALIASES_CACHE) + callback?(null, aliases) ) return ) diff --git a/lib/presets.coffee b/lib/presets.coffee index 52e0acc..da5324d 100644 --- a/lib/presets.coffee +++ b/lib/presets.coffee @@ -218,8 +218,9 @@ exports.getDevicePreset = (deviceId, presets, objects, aliases, callback) -> exports.processDevicePreset = (deviceId, devicePreset, callback) -> + PRESETS_TIME_PADDING = config.get('PRESETS_TIME_PADDING') now = new Date() - expiry = config.PRESETS_CACHE_DURATION + expiry = config.get('PRESETS_CACHE_DURATION', deviceId) getParameterValues = [] setParameterValues = [] addTags = [] @@ -236,7 +237,7 @@ exports.processDevicePreset = (deviceId, devicePreset, callback) -> setParameterValues.push([parameterPath, presetValue, parameterDetails.current._type]) else if parameterDetails.preset.expiry? 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? getParameterValues.push(parameterPath) else @@ -284,7 +285,7 @@ exports.processDevicePreset = (deviceId, devicePreset, callback) -> taskList.push({device : deviceId, name : 'customCommand', command : commandDetails.preset.valueCommand}) else if commandDetails.preset.expiry? 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}) else expiry = Math.min(expiry, diff) diff --git a/lib/server.coffee b/lib/server.coffee index 6ec1477..af58f72 100644 --- a/lib/server.coffee +++ b/lib/server.coffee @@ -25,9 +25,9 @@ service = config.argv[0] if not service? throw new Error('Missing argument cwmp, fs, or nbi') -networkInterface = config["#{service.toUpperCase()}_INTERFACE"] -port = config["#{service.toUpperCase()}_PORT"] -useHttps = config["#{service.toUpperCase()}_SSL"] +networkInterface = config.get("#{service.toUpperCase()}_INTERFACE") +port = config.get("#{service.toUpperCase()}_PORT") +useHttps = config.get("#{service.toUpperCase()}_SSL") serviceListener = require("./#{service}").listener @@ -67,8 +67,8 @@ listener = (httpRequest, httpResponse) -> if useHttps path = require 'path' fs = require 'fs' - httpsKey = path.resolve(config.CONFIG_DIR, "#{service}.key") - httpsCert = path.resolve(config.CONFIG_DIR, "#{service}.crt") + httpsKey = path.resolve(config.get('CONFIG_DIR'), "#{service}.key") + httpsCert = path.resolve(config.get('CONFIG_DIR'), "#{service}.crt") options = { key: fs.readFileSync(httpsKey), cert: fs.readFileSync(httpsCert) diff --git a/lib/soap.coffee b/lib/soap.coffee index a770434..9faaa1a 100644 --- a/lib/soap.coffee +++ b/lib/soap.coffee @@ -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 -if config.IGNORE_XML_NAMESPACES +if config.get('IGNORE_XML_NAMESPACES') libxmljs.Element.prototype.__find = libxmljs.Element.prototype.find libxmljs.Element.prototype.find = (xpath, namespaces) -> # Modify xpath queries to work regardless of element's namespace @@ -291,7 +297,7 @@ exports.request = (httpRequest, cwmpVersion) -> data = httpRequest.getBody() if data.length > 0 - xml = libxmljs.parseXml(data, config.LIBXMLJS_OPTIONS) + xml = libxmljs.parseXml(data, LIBXMLJS_OPTIONS) if not cwmpRequest.cwmpVersion? # 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 - 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() when 'Inform' cwmpRequest.methodRequest = acsInform(methodElement) diff --git a/lib/tasks.coffee b/lib/tasks.coffee index 27f356b..cfe2ddf 100644 --- a/lib/tasks.coffee +++ b/lib/tasks.coffee @@ -72,7 +72,7 @@ this.refreshObject = (task, methodResponse, callback) -> task.session.parameterNames.push(p[0]) 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 this.getParameterValues(task.session.subtask, {}, (err, status, methodRequest) -> @@ -102,6 +102,8 @@ this.getParameterNames = (task, methodResponse, callback) -> callback(null, STATUS_FAULT) return + GET_PARAMETER_NAMES_DEPTH_THRESHOLD = config.get('GET_PARAMETER_NAMES_DEPTH_THRESHOLD', task.device) + getParameterDepth = (param) -> return 0 if !param return (param[...-1] + '.').split('.').length - 1 @@ -110,7 +112,7 @@ this.getParameterNames = (task, methodResponse, callback) -> path = task.session.queue.pop() # 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 task.session.queue.push(p[0]) if p[0][-1..] == '.' @@ -138,7 +140,7 @@ this.getParameterNames = (task, methodResponse, callback) -> methodRequest = { type : 'GetParameterNames', 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) else @@ -158,7 +160,7 @@ this.getParameterValues = (task, methodResponse, callback) -> else if methodResponse.parameterList? 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) if methodResponse.type is 'GetParameterValuesResponse' @@ -188,7 +190,7 @@ this.setParameterValues = (task, methodResponse, callback) -> prevValues = task.parameterValues.slice(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) if prevValues? @@ -233,7 +235,7 @@ this.addObject = (task, methodResponse, callback) -> task.session.parameterNames.push(p[0]) if not common.endsWith(p[0], '.') 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() else if status & STATUS_OK # 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) 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() else callback(err, status, methodRequest, allDeviceUpdates) @@ -332,7 +334,7 @@ this.download = (task, methodResponse, callback) -> type : 'Download', fileType : file.metadata.fileType, 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, failureUrl : task.failureUrl }