Restructuring and optimization in provision processing

This commit is contained in:
Zaid Abdulla committed 2016-09-06 02:38:08 -07:00
1 parent 8e450f6ad0
commit ad38a7ccb1
3 files changed
+302 -273

No files matched your search

+1 -1
View File
@@ -220,7 +220,7 @@ nextRpc = (currentRequest) ->
if rpcRequest? if rpcRequest?
return sendRpcRequest(currentRequest, id, rpcRequest) return sendRpcRequest(currentRequest, id, rpcRequest)
for p, i in currentRequest.sessionData.provisions for p, i in currentRequest.sessionData.provisions[0]
if currentRequest.sessionData.faults? if currentRequest.sessionData.faults?
delete currentRequest.sessionData.faults[currentRequest.sessionData.channels[i]] delete currentRequest.sessionData.faults[currentRequest.sessionData.channels[i]]
+12 -9
View File
@@ -28,7 +28,6 @@ class Exit;
sandbox = { sandbox = {
timestamp: null timestamp: null
deviceData: null deviceData: null
args: null
revision: null revision: null
maxRevision: null maxRevision: null
declarations: null declarations: null
@@ -37,7 +36,7 @@ sandbox = {
context: vm.createContext() context: vm.createContext()
} }
sandbox.context.Date = class Object.defineProperty(sandbox.context, 'Date', {value: class
constructor: (arg) -> constructor: (arg) ->
if arguments.length if arguments.length
return new (Function.prototype.bind.apply(Date, arguments)) return new (Function.prototype.bind.apply(Date, arguments))
@@ -46,9 +45,10 @@ sandbox.context.Date = class
@now: () -> @now: () ->
return sandbox.timestamp return sandbox.timestamp
})
sandbox.context.ext = () -> Object.defineProperty(sandbox.context, 'ext', {value: () ->
if sandbox.extensions?.length if sandbox.extensions?.length
throw new Error('Ext function should not be called from within a try/catch block') throw new Error('Ext function should not be called from within a try/catch block')
@@ -59,9 +59,10 @@ sandbox.context.ext = () ->
throw new Exit() throw new Exit()
return sandbox.extensionsCache[sandbox.revision][key] return sandbox.extensionsCache[sandbox.revision][key]
})
sandbox.context.declare = (decs) -> Object.defineProperty(sandbox.context, 'declare', {value: (decs) ->
if ++ sandbox.revision > sandbox.maxRevision + 1 if ++ sandbox.revision > sandbox.maxRevision + 1
throw new Error('Declare function should not be called from within a try/catch block') throw new Error('Declare function should not be called from within a try/catch block')
@@ -103,26 +104,28 @@ sandbox.context.declare = (decs) ->
res[k][param.join('.')] = r res[k][param.join('.')] = r
return res return res
})
Object.freeze(sandbox.context)
run = (script, args, timestamp, deviceData, extensionsCache, startRevision, maxRevision) -> run = (script, globals, timestamp, deviceData, extensionsCache, startRevision, maxRevision) ->
sandbox.timestamp = timestamp sandbox.timestamp = timestamp
sandbox.deviceData = deviceData sandbox.deviceData = deviceData
sandbox.extensionsCache = extensionsCache sandbox.extensionsCache = extensionsCache
sandbox.args = args
sandbox.revision = startRevision sandbox.revision = startRevision
sandbox.maxRevision = maxRevision sandbox.maxRevision = maxRevision
sandbox.declarations = [] sandbox.declarations = []
sandbox.extensions = null sandbox.extensions = null
for k, v of globals
sandbox.context[k] = v
try try
ret = script.runInNewContext(sandbox.context, {displayErrors: false}) ret = script.runInNewContext(sandbox.context, {displayErrors: false})
delete sandbox.context[k] for k of sandbox.context
return {done: true, declarations: sandbox.declarations, returnValue: ret} return {done: true, declarations: sandbox.declarations, returnValue: ret}
catch err catch err
delete sandbox.context[k] for k of sandbox.context
throw err if err not instanceof Exit throw err if err not instanceof Exit
return {done: false, declarations: sandbox.declarations, extensions: sandbox.extensions} return {done: false, declarations: sandbox.declarations, extensions: sandbox.extensions}
+289 -263
View File
@@ -45,7 +45,7 @@ init = (deviceId, cwmpVersion, timeout, callback) ->
deviceData : initDeviceData() deviceData : initDeviceData()
cwmpVersion : cwmpVersion cwmpVersion : cwmpVersion
timeout : timeout timeout : timeout
provisions: [] provisions: [[]]
channels: [] channels: []
revisions: [0] revisions: [0]
rpcCount: 0 rpcCount: 0
@@ -77,10 +77,10 @@ loadParameters = (sessionData, callback) ->
if not parameters? if not parameters?
# Device not available in database, mark as new # Device not available in database, mark as new
sessionData.new = true sessionData.new = true
path = sessionData.deviceData.paths.add(['*']) loaded = [[[], 99]]
sessionData.deviceData.loaded.set(path, 99) parameters = []
delete sessionData.toLoad
return callback() vparams = {}
for p in loaded for p in loaded
path = sessionData.deviceData.paths.add(p[0]) path = sessionData.deviceData.paths.add(p[0])
@@ -89,6 +89,17 @@ loadParameters = (sessionData, callback) ->
l = sessionData.deviceData.loaded.get(path) || 0 l = sessionData.deviceData.loaded.get(path) || 0
sessionData.deviceData.loaded.set(path, Math.max(l, p[1])) sessionData.deviceData.loaded.set(path, Math.max(l, p[1]))
if path.length <= 2 and path.length + p[1] > 2
if path.length < 1 or path[0] == '*' or path[0] == 'VirtualParameters'
if path.length < 2 or path[1] == '*'
vparams['*'] = 1
else
vparams[path[1]] = 1
if path.length <= 1 and path.length + p[1] > 1
if path.length < 1 or path[0] == '*' or path[0] == 'VirtualParameters'
vparams[''] = 1
for p in parameters for p in parameters
path = sessionData.deviceData.paths.add(p[0]) path = sessionData.deviceData.paths.add(p[0])
@@ -99,31 +110,28 @@ loadParameters = (sessionData, callback) ->
sessionData.deviceData.values[k].set(path, v, 0) sessionData.deviceData.values[k].set(path, v, 0)
# Virtual parameters # Virtual parameters
for p in sessionData.toLoad if vparams['']
p = sessionData.deviceData.paths.add(p) device.set(sessionData.deviceData, ['VirtualParameters'],
if p[0] == '*' or p[0] == 'VirtualParameters' {exist: sessionData.timestamp, object: sessionData.timestamp, writable: sessionData.timestamp},
if p.length == 1 {exist: 1, object: 1, writable: 0})
sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0) delete vparams['']
sessionData.deviceData.timestamps.object.set(p, sessionData.timestamp, 0)
sessionData.deviceData.timestamps.writable.set(p, sessionData.timestamp, 0)
sessionData.deviceData.values.exist.set(p, 1, 0)
sessionData.deviceData.values.object.set(p, 1, 0)
sessionData.deviceData.values.writable.set(p, 0, 0)
else if p.length == 2
if not p[1]?
sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0)
for k, v of sessionData.cache.virtualParameters if vparams['*']
p = sessionData.deviceData.paths.add(p) for k, v of sessionData.cache.virtualParameters
sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0) device.set(sessionData.deviceData, ['VirtualParameters', k],
sessionData.deviceData.timestamps.object.set(p, sessionData.timestamp, 0) {exist: sessionData.timestamp, object: sessionData.timestamp},
sessionData.deviceData.values.exist.set(p, 1, 0) {exist: 1, object: 0})
sessionData.deviceData.values.object.set(p, 0, 0)
else if sessionData.cache.virtualParameters[p[1]]? device.set(sessionData.deviceData, ['VirtualParameters', '*'],
sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0) {exist: sessionData.timestamp})
sessionData.deviceData.timestamps.object.set(p, sessionData.timestamp, 0) else
sessionData.deviceData.values.exist.set(p, 1, 0) for k of vparams
sessionData.deviceData.values.object.set(p, 0, 0) if k of sessionData.cache.virtualParameters
device.set(sessionData.deviceData, ['VirtualParameters', k]
{exist: sessionData.timestamp, object: sessionData.timestamp},
{exist: 1, object: 0})
else
device.set(sessionData.deviceData, ['VirtualParameters', k], {exist: sessionData.timestamp})
delete sessionData.toLoad delete sessionData.toLoad
return callback() return callback()
@@ -189,14 +197,19 @@ inform = (sessionData, rpcReq, callback) ->
addProvisions = (sessionData, channel, provisions) -> addProvisions = (sessionData, channel, provisions) ->
sessionData.declarations = []
sessionData.provisions.length = 1
sessionData.doneProvisions = 0
sessionData.doneDeclarations = 0
for provision, i in provisions for provision, i in provisions
# Remove duplicate provisions # Remove duplicate provisions
for p, j in sessionData.provisions for p, j in sessionData.provisions[0]
if channel == sessionData.channels[j] and JSON.stringify(p) == JSON.stringify(provision) if channel == sessionData.channels[j] and JSON.stringify(p) == JSON.stringify(provision)
sessionData.provisions.splice(j, 1) sessionData.provisions.splice(j, 1)
sessionData.channels.splice(j, 1) sessionData.channels.splice(j, 1)
sessionData.provisions.push(provision) sessionData.provisions[0].push(provision)
sessionData.channels.push(channel) sessionData.channels.push(channel)
if sessionData.revisions.length > 1 or sessionData.revisions[0] > 0 if sessionData.revisions.length > 1 or sessionData.revisions[0] > 0
@@ -210,9 +223,11 @@ addProvisions = (sessionData, channel, provisions) ->
clearProvisions = (sessionData) -> clearProvisions = (sessionData) ->
delete sessionData.syncState delete sessionData.syncState
sessionData.provisions = [] sessionData.provisions = [[]]
sessionData.channels = [] sessionData.channels = []
sessionData.declarations = [] sessionData.declarations = []
sessionData.doneProvisions = 0
sessionData.doneDeclarations = 0
if sessionData.revisions.length > 1 or sessionData.revisions[0] > 0 if sessionData.revisions.length > 1 or sessionData.revisions[0] > 0
v.collapse(1) for k, v of sessionData.deviceData.timestamps v.collapse(1) for k, v of sessionData.deviceData.timestamps
v.collapse(1) for k, v of sessionData.deviceData.values v.collapse(1) for k, v of sessionData.deviceData.values
@@ -222,11 +237,11 @@ clearProvisions = (sessionData) ->
sessionData.extensionsCache.length = 0 sessionData.extensionsCache.length = 0
runProvisions = (sessionData, callback) -> runProvisions = (sessionData, provisions, startRevision, endRevision, callback) ->
done = true done = true
_extensions = [] _extensions = []
allDeclarations = [] allDeclarations = []
for provision in sessionData.provisions for provision in provisions
if not sessionData.cache.provisions[provision[0]]? if not sessionData.cache.provisions[provision[0]]?
switch provision[0] switch provision[0]
when 'refresh' when 'refresh'
@@ -264,81 +279,71 @@ runProvisions = (sessionData, callback) ->
allDeclarations.push([p, {exist: sessionData.timestamp, object: 1, writable: 1, value: sessionData.timestamp}]) allDeclarations.push([p, {exist: sessionData.timestamp, object: 1, writable: 1, value: sessionData.timestamp}])
continue continue
ret = sandbox.run(sessionData.cache.provisions[provision[0]].script, provision.slice(1), sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, 0, sessionData.revisions[0] >> 1) ret = sandbox.run(sessionData.cache.provisions[provision[0]].script, {args: provision[1]}, sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, startRevision, endRevision)
if ret.extensions?.length if ret.extensions?.length
_extensions = _extensions.concat(ret.extensions) _extensions = _extensions.concat(ret.extensions)
done &&= ret.done done &&= ret.done
allDeclarations = allDeclarations.concat(ret.declarations) allDeclarations = allDeclarations.concat(ret.declarations)
if _extensions.length if _extensions.length
return runExtensions(sessionData, (sessionData.revisions[0] >> 1), _extensions, (err) -> return runExtensions(sessionData, endRevision, _extensions, (err) ->
return callback(err) if err return callback(err) if err
return runProvisions(sessionData, callback) return runProvisions(sessionData, provisions, startRevision, endRevision, callback)
) )
for d in allDeclarations return callback(null, done, allDeclarations)
state = applyDeclaration(sessionData, d[0], 0, d[1], d[2])
sessionData.declarations.push([d[0], state, d[1], d[2]])
return callback(null, done)
runVirtualParameters = (sessionData, inception, callback) -> runVirtualParameters = (sessionData, provisions, startRevision, endRevision, callback) ->
if not sessionData.syncState? or Object.keys(sessionData.syncState.virtualParameters).length == 0 done = true
return callback()
virtualParameterDeclarations = sessionData.syncState.virtualParameters
sessionData.syncState.virtualParameters = {}
revision = sessionData.revisions.reduce(((a, b) -> a + (b >> 1)), 0) + 1
sessionData.revisions[inception] ?= 0
decs = [] decs = []
virtualParameterUpdates = {} virtualParameterUpdates = []
_extensions = [] _extensions = []
firstRevision = revision - (sessionData.revisions[sessionData.revisions.length - 1] >> 1) for provision in provisions
for vpName, vpDeclarations of virtualParameterDeclarations ret = sandbox.run(sessionData.cache.virtualParameters[provision[0]].script, provision[1], sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, startRevision, endRevision)
ret = sandbox.run(sessionData.cache.virtualParameters[vpName].script, [vpDeclarations.timestamps, vpDeclarations.values], sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, firstRevision, revision)
if ret.extensions?.length if ret.extensions?.length
_extensions = _extensions.concat(ret.extensions) _extensions = _extensions.concat(ret.extensions)
done &&= ret.done
decs = decs.concat(ret.declarations) decs = decs.concat(ret.declarations)
if ret.done if ret.done
virtualParameterUpdates[vpName] = ret.returnValue virtualParameterUpdates.push([provision[0], ret.returnValue])
if _extensions.length if _extensions.length
return runExtensions(sessionData, revision, _extensions, (err) -> return runExtensions(sessionData, endRevision, _extensions, (err) ->
return callback(err) if err return callback(err) if err
return runVirtualParameters(sessionData, inception, callback) return runVirtualParameters(sessionData, provisions, startRevision, endRevision, callback)
) )
for d in decs if virtualParameterUpdates.length == provisions.length
state = applyDeclaration(sessionData, d[0], 0, d[1], d[2]) for vpu, i in virtualParameterUpdates
sessionData.declarations.push([d[0], state, d[1], d[2]]) commitVirtualParameter(sessionData, vpu[0], provisions[i][1], vpu[1])
return callback(null, done, decs)
if Object.keys(virtualParameterUpdates).length == Object.keys(virtualParameterDeclarations).length runDeclarations = (sessionData, declarations, callback) ->
done = true
if sessionData.toLoad?.length
return loadParameters(sessionData, (err) ->
return callback(err) if err
runDeclarations(sessionData, declarations, callback)
)
rev = sessionData.revisions.reduce(((a, b) -> a + (b >> 1)), 0) + 1 for d in declarations
v.revision = rev for k, v of sessionData.deviceData.timestamps done &= applyDeclaration(sessionData, d[0], d[1], d[2])
v.revision = rev for k, v of sessionData.deviceData.values
for vpName, vpDeclarations of virtualParameterDeclarations
commitVirtualParameter(sessionData, vpName, vpDeclarations, virtualParameterUpdates[vpName])
if sessionData.revisions[inception] > 0 if sessionData.syncState? and sessionData.syncState.virtualParameters?
sessionData.revisions.length = inception provisions = []
rev = sessionData.revisions.reduce(((a, b) -> a + (b >> 1)), 0) + 1 for k, v of sessionData.syncState.virtualParameters
m.collapse(rev) for k, m of sessionData.deviceData.timestamps provisions.push([k, v])
m.collapse(rev) for k, m of sessionData.deviceData.values sessionData.syncState.virtualParameters = {}
if sessionData.extensionsCache.length > rev
sessionData.extensionsCache.length = rev
return runVirtualParameters(sessionData, inception + 1, callback) return callback(null, done, provisions)
rpcRequest = (sessionData, declarations, callback) -> rpcRequest = (sessionData, _declarations, callback) ->
if sessionData.rpcRequest? if sessionData.rpcRequest?
return callback(null, generateRpcId(sessionData), sessionData.rpcRequest) return callback(null, generateRpcId(sessionData), sessionData.rpcRequest)
@@ -346,77 +351,119 @@ rpcRequest = (sessionData, declarations, callback) ->
sessionData.rpcRequest = rpcReq sessionData.rpcRequest = rpcReq
return callback(null, generateRpcId(sessionData), rpcReq) return callback(null, generateRpcId(sessionData), rpcReq)
revision = sessionData.revisions.reduce(((a, b) -> a + (b >> 1)), 0) + 1 revision = sessionData.revisions[sessionData.revisions.length - 1] + 1
v.revision = revision for k, v of sessionData.deviceData.timestamps v.revision = revision for k, v of sessionData.deviceData.timestamps
v.revision = revision for k, v of sessionData.deviceData.values v.revision = revision for k, v of sessionData.deviceData.values
f = (cb) -> if _declarations?.length
return cb() if not sessionData.declarations.length sessionData.declarations = []
sessionData.provisions[0] ?= []
sessionData.revisions[0] ?= 0
sessionData.doneDeclarations = 0
sessionData.doneProvisions = 0
for d, i in sessionData.declarations if sessionData.declarations.length != sessionData.provisions.length
state = applyDeclaration(sessionData, d[0], d[1], d[2], d[3]) inception = sessionData.declarations.length
d[1] = state run = if inception == 0 then runProvisions else runVirtualParameters
if sessionData.toLoad?.length return run(sessionData, sessionData.provisions[inception], sessionData.revisions[inception - 1] ? 0, sessionData.revisions[inception], f = (err, done, decs) ->
return loadParameters(sessionData, (err) -> return callback(err) if err
return cb(err) if err
return f(cb) if _declarations?.length
decs = decs.concat(_declarations)
sessionData.declarations.push(decs)
sessionData.doneProvisions |= 1 << inception if done
if ++ inception < sessionData.provisions.length
if inception == 1 and _declarations?.length
for d in _declarations
sessionData.declarations[0].push(d)
for ad in device.getAliasDeclarations(d[0], 1)
loadPath(sessionData, ad[0])
else
if not decs.length
while sessionData.doneDeclarations & (1 << (sessionData.declarations.length - 1))
sessionData.declarations.pop()
while sessionData.provisions.length > (sessionData.declarations.length or 1) and
sessionData.doneProvisions & (1 << (sessionData.provisions.length - 1))
sessionData.provisions.pop()
sessionData.revisions.pop()
rev = sessionData.revisions[sessionData.revisions.length - 1]
m.collapse(rev + 1) for k, m of sessionData.deviceData.timestamps
m.collapse(rev + 1) for k, m of sessionData.deviceData.values
sessionData.extensionsCache.splice(rev)
sessionData.doneDeclarations &= (1 << sessionData.declarations.length) - 1
sessionData.doneProvisions &= (1 << sessionData.provisions.length) - 1
if sessionData.provisions.length == 1 and sessionData.doneProvisions
return callback()
for d in decs
for ad in device.getAliasDeclarations(d[0], 1)
loadPath(sessionData, ad[0])
return rpcRequest(sessionData, null, callback)
return runVirtualParameters(sessionData, sessionData.provisions[inception], sessionData.revisions[inception - 1], sessionData.revisions[inception], f)
)
return callback() if not sessionData.declarations.length
inception = 0
runDeclarations(sessionData, sessionData.declarations[inception], f = (err, done, provisions) ->
return callback(err) if err
sessionData.doneDeclarations |= 1 << (sessionData.revisions.length - 1)
if ++ inception < sessionData.revisions.length
return runDeclarations(sessionData, sessionData.declarations[inception], f)
if provisions?.length
rev = sessionData.revisions[sessionData.revisions.length - 1]
sessionData.revisions.push(rev)
sessionData.provisions.push(provisions)
return runVirtualParameters(sessionData, provisions, rev, rev, (err, done, declarations) ->
return callback(err) if err
sessionData.doneProvisions |= 1 << (sessionData.revisions.length - 1) if done
for d in declarations
for ad in device.getAliasDeclarations(d[0], 1)
loadPath(sessionData, ad[0])
sessionData.declarations.push(declarations)
runDeclarations(sessionData, declarations, f)
) )
runVirtualParameters(sessionData, 1, (err) -> rpcReq = generateRpcRequest(sessionData)
return cb(err) if err if not rpcReq?
while sessionData.doneDeclarations & (1 << (sessionData.declarations.length - 1))
sessionData.declarations.pop()
if sessionData.toLoad?.length while sessionData.provisions.length > (sessionData.declarations.length or 1) and
return loadParameters(sessionData, (err) -> sessionData.doneProvisions & (1 << (sessionData.provisions.length - 1))
return cb(err) if err sessionData.provisions.pop()
return f(cb) sessionData.revisions.pop()
) rev = sessionData.revisions[sessionData.revisions.length - 1]
m.collapse(rev + 1) for k, m of sessionData.deviceData.timestamps
m.collapse(rev + 1) for k, m of sessionData.deviceData.values
sessionData.extensionsCache.splice(rev)
return cb(null, generateRpcRequest(sessionData)) sessionData.doneDeclarations &= (1 << sessionData.declarations.length) - 1
) sessionData.doneProvisions &= (1 << sessionData.provisions.length) - 1
if declarations? if sessionData.provisions.length == 1 and sessionData.doneProvisions
for d in declarations
sessionData.declarations.push([d[0], 0, d[1], d[2]])
if sessionData.declarations.length
return f((err, rpcReq) ->
return callback(err) if err
if rpcReq?
sessionData.declarations = [] if rpcReq.done
sessionData.rpcRequest = rpcReq
return callback(null, generateRpcId(sessionData), rpcReq)
sessionData.declarations = []
++ sessionData.revisions[sessionData.revisions.length - 1]
return rpcRequest(sessionData, null, callback)
)
if not sessionData.provisions.length
return callback()
runProvisions(sessionData, (err, done) ->
return callback(err) if err
return f((err, rpcReq) ->
return callback(err) if err
if rpcReq?
sessionData.declarations = [] if rpcReq.done
sessionData.rpcRequest = rpcReq
return callback(null, generateRpcId(sessionData), rpcReq)
sessionData.declarations = []
if done
return callback() return callback()
++ sessionData.revisions[sessionData.revisions.length - 1] ++ sessionData.revisions[sessionData.revisions.length - 1]
return rpcRequest(sessionData, null, callback) return rpcRequest(sessionData, _declarations, callback)
)
sessionData.rpcRequest = rpcReq
return callback(null, generateRpcId(sessionData), rpcReq)
) )
generateRpcRequest = (sessionData) -> generateRpcRequest = (sessionData) ->
syncState = sessionData.syncState if not (syncState = sessionData.syncState)?
return
iter = syncState.refreshAttributes.exist.values() iter = syncState.refreshAttributes.exist.values()
while (path = iter.next().value) while (path = iter.next().value)
@@ -434,7 +481,6 @@ generateRpcRequest = (sessionData) ->
syncState.refreshGpn.set(path, syncState.refreshGpn.get(path) or 1) syncState.refreshGpn.set(path, syncState.refreshGpn.get(path) or 1)
syncState.refreshAttributes.exist.clear() syncState.refreshAttributes.exist.clear()
iter = syncState.refreshAttributes.object.values() iter = syncState.refreshAttributes.object.values()
while (path = iter.next().value) while (path = iter.next().value)
descendantIter = syncState.paths.subset(path, 99) descendantIter = syncState.paths.subset(path, 99)
@@ -471,36 +517,6 @@ generateRpcRequest = (sessionData) ->
rpcReq = null rpcReq = null
completed = true completed = true
# Delete instance
syncState.instancesToDelete.forEach((instances, parent) ->
instances.forEach((instance, index, thisArray) ->
if rpcReq?
completed = false
else
rpcReq = {
type: 'DeleteObject'
objectName: instance.join('.') + '.'
}
thisArray.splice(index, 1)
)
)
# Create instance
syncState.instancesToCreate.forEach((instances, parent) ->
instances.forEach((instance, index, thisArray) ->
if rpcReq?
completed = false
else
rpcReq = {
type: 'AddObject'
objectName: parent.join('.') + '.'
next: 'getInstanceKeys'
instanceValues: instance
}
thisArray.splice(index, 1)
)
)
if syncState.refreshGpn.size if syncState.refreshGpn.size
if rpcReq? if rpcReq?
completed = false completed = false
@@ -548,6 +564,47 @@ generateRpcRequest = (sessionData) ->
parameterNames: (p.join('.') for p in parameterNames) parameterNames: (p.join('.') for p in parameterNames)
} }
refreshDone = not rpcReq?
# Skip write if read isn't finished
sessionData.syncState.setValues.clear()
sessionData.syncState.instancesToDelete.clear()
sessionData.syncState.instancesToCreate.clear()
# Delete instance
syncState.instancesToDelete.forEach((instances, parent) ->
instances.forEach((instance, index, thisArray) ->
if rpcReq?
completed = false
else
rpcReq = {
type: 'DeleteObject'
objectName: instance.join('.') + '.'
}
thisArray.splice(index, 1)
)
)
syncState.instancesToDelete.clear() if not refreshDone
# Create instance
syncState.instancesToCreate.forEach((instances, parent) ->
instances.forEach((instance, index, thisArray) ->
if rpcReq?
completed = false
else
rpcReq = {
type: 'AddObject'
objectName: parent.join('.') + '.'
next: 'getInstanceKeys'
instanceValues: instance
}
thisArray.splice(index, 1)
)
)
syncState.instancesToCreate.clear() if not refreshDone
# Set values
TASK_PARAMETERS_BATCH_SIZE = TASK_PARAMETERS_BATCH_SIZE =
config.get('TASK_PARAMETERS_BATCH_SIZE', sessionData.deviceId) config.get('TASK_PARAMETERS_BATCH_SIZE', sessionData.deviceId)
@@ -555,22 +612,22 @@ generateRpcRequest = (sessionData) ->
syncState.setValues.forEach((v, k) -> syncState.setValues.forEach((v, k) ->
return if completed == false return if completed == false
if rpcReq? if (curVal = sessionData.deviceData.values.value.get(k))? and sessionData.deviceData.values.writable.get(k)
completed = false val = v.slice()
return val[1] = curVal[1] if not val[1]?
device.sanitizeParameterValue(val)
val = v[1].slice() if val[0] != curVal[0] or val[1] != curVal[1]
if not val[1]? if rpcReq? or parameterValues.length >= TASK_PARAMETERS_BATCH_SIZE
val[1] = v[0][1] completed = false
device.sanitizeParameterValue(val) return
if val[0] != v[0][0] or val[1] != v[0][1]
if parameterValues.length >= TASK_PARAMETERS_BATCH_SIZE parameterValues.push([k, val[0], val[1]])
completed = false syncState.setValues.delete(k)
return
parameterValues.push([k, val[0], val[1]])
syncState.setValues.delete(k)
) )
syncState.setValues.clear() if not refreshDone
if parameterValues.length and not rpcReq? if parameterValues.length and not rpcReq?
rpcReq = { rpcReq = {
type: 'SetParameterValues' type: 'SetParameterValues'
@@ -589,6 +646,7 @@ processVirtualparameterDeclaration = (sessionData, path, timestamps, values) ->
deviceData = sessionData.deviceData deviceData = sessionData.deviceData
subIter = sessionData.deviceData.paths.subset(path) subIter = sessionData.deviceData.paths.subset(path)
while sub = subIter.next().value while sub = subIter.next().value
continue if sub[0] isnt 'VirtualParameters'
continue if not deviceData.values.exist.get(sub) continue if not deviceData.values.exist.get(sub)
isWritable = deviceData.values.writable.get(sub) isWritable = deviceData.values.writable.get(sub)
@@ -624,11 +682,12 @@ processDeclaration = (sessionData, path, _timestamps, values) ->
timestamps = {} timestamps = {}
timestamps[k] = v for k, v of _timestamps timestamps[k] = v for k, v of _timestamps
timestamps.exist ?= 1
ret = true ret = true
if path[0] == '*' or path[0] == 'VirtualParameters' if path[0] == '*' or path[0] == 'VirtualParameters'
ret &&= processVirtualparameterDeclaration(sessionData, path, _timestamps, values) ret = processVirtualparameterDeclaration(sessionData, path, _timestamps, values) && ret
return ret if path[0] != '*' return ret if path[0] != '*'
iter = sessionData.deviceData.paths.superset(path) iter = sessionData.deviceData.paths.superset(path)
@@ -660,20 +719,13 @@ processDeclaration = (sessionData, path, _timestamps, values) ->
ret = false ret = false
if values?.value? if values?.value?
if isObject == 0 and isWritable == 1 syncState.setValues.set(param, values.value)
cur = syncState.setValues.get(param) if not isObject?
if not cur? syncState.refreshAttributes.object.add(param)
cur = [deviceData.values.value.get(param), values.value] ret = false
syncState.setValues.set(param, cur) if not isWritable?
else syncState.refreshAttributes.writable.add(param)
cur[1] = values.value ret = false
else
if not isObject?
syncState.refreshAttributes.object.add(param)
ret = false
if not isWritable?
syncState.refreshAttributes.writable.add(param)
ret = false
return ret return ret
else if existTimestamp >= (timestamps.exist or 1) else if existTimestamp >= (timestamps.exist or 1)
return ret return ret
@@ -697,23 +749,16 @@ processDeclaration = (sessionData, path, _timestamps, values) ->
ret = false ret = false
if values?.value? if values?.value?
if isObject == 0 and isWritable == 1 syncState.setValues.set(sub, values.value)
cur = syncState.setValues.get(sub) if not isObject?
if not cur? syncState.refreshAttributes.object.add(sub)
cur = [deviceData.values.value.get(sub), values.value] ret = false
syncState.setValues.set(sub, cur) if not isWritable?
else syncState.refreshAttributes.writable.add(sub)
cur[1] = values.value ret = false
else
if not isObject?
syncState.refreshAttributes.object.add(sub)
ret = false
if not isWritable?
syncState.refreshAttributes.writable.add(sub)
ret = false
if existTimestamp >= (timestamps.exist or 1) if existTimestamp >= (timestamps.exist or 1)
return return ret
childrenTimestamp = existTimestamp childrenTimestamp = existTimestamp
@@ -755,7 +800,7 @@ processDeclaration = (sessionData, path, _timestamps, values) ->
pp = sub.concat(path.slice(sub.length)) pp = sub.concat(path.slice(sub.length))
ts = {} ts = {}
ts[k] = v for k, v of timestamps ts[k] = v for k, v of timestamps
ret &&= processDeclaration(sessionData, pp, ts) ret = processDeclaration(sessionData, pp, ts) && ret
if existTimestamp >= (timestamps.exist or 1) if existTimestamp >= (timestamps.exist or 1)
return ret return ret
@@ -833,12 +878,7 @@ processInstances = (sessionData, parent, parameters, keys, minInstances, maxInst
return return
applyDeclaration = (sessionData, path, state, timestamps, values) -> applyDeclaration = (sessionData, path, timestamps, values) ->
if state == 100
if not values? or Object.keys(values).length == 0
return state
timestamps = {}
sessionData.syncState ?= { sessionData.syncState ?= {
paths: new PathSet() paths: new PathSet()
refreshAttributes: { refreshAttributes: {
@@ -856,60 +896,46 @@ applyDeclaration = (sessionData, path, state, timestamps, values) ->
decs = device.getAliasDeclarations(path, timestamps.exist ? 1) decs = device.getAliasDeclarations(path, timestamps.exist ? 1)
if state <= 1
loaded = true
for d in decs
loaded &&= loadPath(sessionData, d[0])
return 1 if not loaded
if decs.length == 1 if decs.length == 1
satisfied = processDeclaration(sessionData, decs[0][0], timestamps, values) processDeclaration(sessionData, decs[0][0], timestamps, values)
if satisfied return true
return 100
satisfied = true
for d in decs
satisfied = processDeclaration(sessionData, d[0], d[1]) && satisfied
return false if not satisfied
unpacked = device.unpack(sessionData.deviceData, path)
if values.exist?
if Array.isArray(values.exist)
minInstances = values.exist[0]
maxInstances = values.exist[1]
else else
return 2 minInstances = maxInstances = values.exist
else
if state <= 2
satisfied = true
for d in decs parent = path.slice(0, -1)
satisfied &&= processDeclaration(sessionData, d[0], d[1], d[2])
return 2 if not satisfied if Array.isArray(path[path.length - 1])
keys = {}
for p, i in path[path.length - 1] by 2
keys[p] = path[path.length - 1][i + 1]
else if path[path.length - 1] == '*'
keys = {}
unpacked = device.unpack(sessionData.deviceData, path) if (path.wildcard | path.alias) & ((1 << (path.length - 1)) - 1) == 0
processInstances(sessionData, parent, unpacked, keys, minInstances, maxInstances)
if values.exist?
if Array.isArray(values.exist)
minInstances = values.exist[0]
maxInstances = values.exist[1]
else
minInstances = maxInstances = values.exist
parent = path.slice(0, -1)
if Array.isArray(path[path.length - 1])
keys = {}
for p, i in path[path.length - 1] by 2
keys[p] = path[path.length - 1][i + 1]
else if path[path.length - 1] == '*'
keys = {}
if (path.wildcard | path.alias) & ((1 << (path.length - 1)) - 1) == 0
processInstances(sessionData, parent, unpacked, keys, minInstances, maxInstances)
else
parentsUnpacked = device.unpack(sessionData.deviceData, parent)
for parent in parentsUnpacked
processInstances(sessionData, parent, device.unpack(sessionData.deviceData, parent.concat([path[parent.length]])), keys, minInstances, maxInstances)
satisfied = true
for up in unpacked
satisfied &&= processDeclaration(sessionData, path, timestamps, values)
if satisfied
return 100
else else
return 4 parentsUnpacked = device.unpack(sessionData.deviceData, parent)
for parent in parentsUnpacked
processInstances(sessionData, parent, device.unpack(sessionData.deviceData, parent.concat([path[parent.length]])), keys, minInstances, maxInstances)
for up in unpacked
processDeclaration(sessionData, path, timestamps, values)
return true
commitVirtualParameter = (sessionData, name, declaration, update) -> commitVirtualParameter = (sessionData, name, declaration, update) ->
@@ -938,7 +964,7 @@ commitVirtualParameter = (sessionData, name, declaration, update) ->
t.value = Math.max(declaration.timestamps.value, t.value) t.value = Math.max(declaration.timestamps.value, t.value)
v.value = device.sanitizeParameterValue(update.value[1]) v.value = device.sanitizeParameterValue(update.value[1])
else if declaration.timestmaps.value? else if declaration.timestamps.value?
throw new Error('Virtual parameter must provide declared attributes') throw new Error('Virtual parameter must provide declared attributes')
device.set(sessionData.deviceData, ['VirtualParameters', name], t, v) device.set(sessionData.deviceData, ['VirtualParameters', name], t, v)