Files
genieacs/tasks.coffee
T

251 lines
8.7 KiB
CoffeeScript

config = require './config'
common = require './common'
db = require './db'
mongodb = require 'mongodb'
BATCH_SIZE = 16
exports.STATUS_QUEUED = STATUS_QUEUED = 0
exports.STATUS_STARTED = STATUS_STARTED = 1
exports.STATUS_PENDING = STATUS_PENDING = 2
exports.STATUS_FAULT = STATUS_FAULT = 3
exports.STATUS_FINISHED = STATUS_FINISHED = 4
this.init = (task, methodResponse, callback) ->
if not task.subtask?
task.subtask = {name : 'getParameterNames', parameterPath : '', nextLevel : false}
if task.subtask.name == 'getParameterNames'
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
this.getParameterNames(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) =>
if status is STATUS_FINISHED
parameterNames = []
for p in deviceUpdates.parameterNames
if not common.endsWith(p[0], '.')
parameterNames.push(p[0])
task.subtask = {name : 'getParameterValues', parameterNames : parameterNames}
this.getParameterValues(task.subtask, {}, (err, status, cwmpResponse) ->
# ignore deviceUpdates returned by firt call to getParameterValues
callback(err, status, cwmpResponse, deviceUpdates)
)
else if status is STATUS_STARTED
callback(err, STATUS_STARTED, cwmpResponse, deviceUpdates)
else
throw Error('Unexpected subtask status')
)
else if task.subtask.name == 'getParameterValues'
if methodResponse.faultcode?
# Ignore GetParameterValues errors. A workaround for the crappy Seewon devices.
methodResponse = {parameterList : {}}
this.getParameterValues(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) ->
callback(err, status, cwmpResponse, deviceUpdates)
)
else
throw Error('Unexpected subtask name')
this.getParameterNames = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if methodResponse.type is 'GetParameterNamesResponse'
callback(null, STATUS_FINISHED, null, {parameterNames : methodResponse.parameterList})
else
methodRequest = {
type : 'GetParameterNames',
parameterPath : task.parameterPath,
nextLevel : if task.nextLevel? then task.nextLevel else false
}
callback(null, STATUS_STARTED, {methodRequest : methodRequest})
this.getParameterValues = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if not task.currentIndex?
task.currentIndex = 0
else if methodResponse.parameterList?
task.currentIndex = task.nextIndex
task.nextIndex = Math.min(task.currentIndex + BATCH_SIZE, task.parameterNames.length)
names = task.parameterNames.slice(task.currentIndex, task.nextIndex)
if methodResponse.type is 'GetParameterValuesResponse'
deviceUpdates = {parameterValues : methodResponse.parameterList}
if names.length == 0
callback(null, STATUS_FINISHED, null, deviceUpdates)
else
methodRequest = {
type : 'GetParameterValues',
parameterNames : names
}
callback(null, STATUS_STARTED, {methodRequest : methodRequest}, deviceUpdates)
this.setParameterValues = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if not task.currentIndex?
task.currentIndex = 0
else if methodResponse.type is 'SetParameterValuesResponse'
prevValues = task.parameterValues.slice(task.currentIndex, task.nextIndex)
task.currentIndex = task.nextIndex
task.nextIndex = Math.min(task.currentIndex + BATCH_SIZE, task.parameterValues.length)
values = task.parameterValues.slice(task.currentIndex, task.nextIndex)
if prevValues?
deviceUpdates = {parameterValues : prevValues}
if values.length == 0
callback(null, STATUS_FINISHED, null, deviceUpdates)
else
callback(null, STATUS_STARTED, {methodRequest : {type : 'SetParameterValues', parameterList : values}}, deviceUpdates)
this.addObject = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
allDeviceUpdates = {}
if not task.instanceNumber?
if methodResponse.type is 'AddObjectResponse'
task.instanceNumber = methodResponse.instanceNumber
task.subtask = {name : 'getParameterNames', parameterPath : "#{task.objectName}#{task.instanceNumber}.", nextLevel : false}
task.appliedParameterValues = []
task.parameterNames = []
allDeviceUpdates.instanceName = [["#{task.objectName}#{task.instanceNumber}", task.instanceName]] if task.instanceName?
else
callback(null, STATUS_STARTED, {methodRequest : {type : 'AddObject', objectName : task.objectName}})
return
if task.subtask.name is 'getParameterNames'
this.getParameterNames(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) =>
common.extend(allDeviceUpdates, deviceUpdates)
if deviceUpdates and deviceUpdates.parameterNames
for p in deviceUpdates.parameterNames
task.parameterNames.push(p[0]) if not common.endsWith(p[0], '.')
if status is STATUS_FINISHED
task.subtask = {name : 'getParameterValues', parameterNames : task.parameterNames}
else if status is STATUS_STARTED
callback(err, STATUS_STARTED, cwmpResponse, allDeviceUpdates)
else
throw Error('Unexpected subtask status')
)
if task.subtask.name is 'getParameterValues'
this.getParameterValues(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) =>
common.extend(allDeviceUpdates, deviceUpdates)
if deviceUpdates and deviceUpdates.parameterValues
for p1 in deviceUpdates.parameterValues
for p2 in task.parameterValues
if common.endsWith(p1[0], ".#{p2[0]}")
t = if p2[2] then p2[2] else p1[2]
v = common.matchType(p1[1], p2[1])
# TODO only include if writable
task.appliedParameterValues.push([p1[0], v, t])
if methodResponse.faultcode?
# Ignore GetParameterValues errors. A workaround for the crappy Seewon devices.
methodResponse = {parameterList : {}}
if status is STATUS_FINISHED and task.appliedParameterValues.length > 0
task.subtask = {name : 'setParameterValues', parameterValues : task.appliedParameterValues}
else
callback(err, status, cwmpResponse, allDeviceUpdates)
)
if task.subtask.name is 'setParameterValues'
this.setParameterValues(task.subtask, methodResponse, (err, status, cwmpResponse, deviceUpdates) =>
common.extend(allDeviceUpdates, deviceUpdates)
callback(err, status, cwmpResponse, allDeviceUpdates)
)
this.deleteObject = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if methodResponse.type is 'DeleteObjectResponse'
# trim the last dot (.)
callback(null, STATUS_FINISHED, null, {deletedObjects : [task.objectName.slice(0, -1)]})
else
methodRequest = {
type : 'DeleteObject',
objectName : task.objectName
}
callback(null, STATUS_STARTED, {methodRequest : methodRequest})
this.reboot = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if methodResponse.type isnt 'RebootResponse'
callback(null, STATUS_STARTED, {methodRequest : {type : 'Reboot'}})
else
callback(null, STATUS_FINISHED)
this.factoryReset = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if methodResponse.type isnt 'FactoryResetResponse'
callback(null, STATUS_STARTED, {methodRequest : {type : 'FactoryReset'}})
else
callback(null, STATUS_FINISHED)
this.download = (task, methodResponse, callback) ->
if methodResponse.faultcode?
task.fault = methodResponse
callback(null, STATUS_FAULT)
return
if methodResponse.type isnt 'DownloadResponse'
db.filesCollection.findOne({_id : mongodb.ObjectID(task.file)}, (err, file) ->
if not file?
callback('File not found')
return
else if err?
callback(err)
return
methodRequest = {
type : 'Download',
fileType : '1 Firmware Upgrade Image',
fileSize : file.length,
url : "http://#{config.FILES_IP}:#{config.FILES_PORT}/#{file.filename}"
}
callback(null, STATUS_STARTED, {methodRequest : methodRequest})
)
else
callback(null, STATUS_FINISHED)
exports.task = (task, methodResponse, callback) ->
this[task.name](task, methodResponse, callback)