From ad38a7ccb15bf06cd6b5bc09720137238c9be245 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Tue, 6 Sep 2016 02:38:08 -0700 Subject: [PATCH] Restructuring and optimization in provision processing --- lib/cwmp.coffee | 2 +- lib/sandbox.coffee | 21 +- lib/session.coffee | 552 ++++++++++++++++++++++++--------------------- 3 files changed, 302 insertions(+), 273 deletions(-) diff --git a/lib/cwmp.coffee b/lib/cwmp.coffee index a839e6c..dd4fd40 100644 --- a/lib/cwmp.coffee +++ b/lib/cwmp.coffee @@ -220,7 +220,7 @@ nextRpc = (currentRequest) -> if 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? delete currentRequest.sessionData.faults[currentRequest.sessionData.channels[i]] diff --git a/lib/sandbox.coffee b/lib/sandbox.coffee index 3621a52..c2ecf63 100644 --- a/lib/sandbox.coffee +++ b/lib/sandbox.coffee @@ -28,7 +28,6 @@ class Exit; sandbox = { timestamp: null deviceData: null - args: null revision: null maxRevision: null declarations: null @@ -37,7 +36,7 @@ sandbox = { context: vm.createContext() } -sandbox.context.Date = class +Object.defineProperty(sandbox.context, 'Date', {value: class constructor: (arg) -> if arguments.length return new (Function.prototype.bind.apply(Date, arguments)) @@ -46,9 +45,10 @@ sandbox.context.Date = class @now: () -> return sandbox.timestamp +}) -sandbox.context.ext = () -> +Object.defineProperty(sandbox.context, 'ext', {value: () -> if sandbox.extensions?.length 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() return sandbox.extensionsCache[sandbox.revision][key] +}) -sandbox.context.declare = (decs) -> +Object.defineProperty(sandbox.context, 'declare', {value: (decs) -> if ++ sandbox.revision > sandbox.maxRevision + 1 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 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.deviceData = deviceData sandbox.extensionsCache = extensionsCache - sandbox.args = args sandbox.revision = startRevision sandbox.maxRevision = maxRevision sandbox.declarations = [] sandbox.extensions = null + for k, v of globals + sandbox.context[k] = v + try ret = script.runInNewContext(sandbox.context, {displayErrors: false}) + delete sandbox.context[k] for k of sandbox.context return {done: true, declarations: sandbox.declarations, returnValue: ret} catch err + delete sandbox.context[k] for k of sandbox.context throw err if err not instanceof Exit - return {done: false, declarations: sandbox.declarations, extensions: sandbox.extensions} diff --git a/lib/session.coffee b/lib/session.coffee index 8e30e75..9fb8001 100644 --- a/lib/session.coffee +++ b/lib/session.coffee @@ -45,7 +45,7 @@ init = (deviceId, cwmpVersion, timeout, callback) -> deviceData : initDeviceData() cwmpVersion : cwmpVersion timeout : timeout - provisions: [] + provisions: [[]] channels: [] revisions: [0] rpcCount: 0 @@ -77,10 +77,10 @@ loadParameters = (sessionData, callback) -> if not parameters? # Device not available in database, mark as new sessionData.new = true - path = sessionData.deviceData.paths.add(['*']) - sessionData.deviceData.loaded.set(path, 99) - delete sessionData.toLoad - return callback() + loaded = [[[], 99]] + parameters = [] + + vparams = {} for p in loaded path = sessionData.deviceData.paths.add(p[0]) @@ -89,6 +89,17 @@ loadParameters = (sessionData, callback) -> l = sessionData.deviceData.loaded.get(path) || 0 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 path = sessionData.deviceData.paths.add(p[0]) @@ -99,31 +110,28 @@ loadParameters = (sessionData, callback) -> sessionData.deviceData.values[k].set(path, v, 0) # Virtual parameters - for p in sessionData.toLoad - p = sessionData.deviceData.paths.add(p) - if p[0] == '*' or p[0] == 'VirtualParameters' - if p.length == 1 - sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0) - 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) + if vparams[''] + device.set(sessionData.deviceData, ['VirtualParameters'], + {exist: sessionData.timestamp, object: sessionData.timestamp, writable: sessionData.timestamp}, + {exist: 1, object: 1, writable: 0}) + delete vparams[''] - for k, v of sessionData.cache.virtualParameters - p = sessionData.deviceData.paths.add(p) - sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0) - sessionData.deviceData.timestamps.object.set(p, sessionData.timestamp, 0) - sessionData.deviceData.values.exist.set(p, 1, 0) - sessionData.deviceData.values.object.set(p, 0, 0) - else if sessionData.cache.virtualParameters[p[1]]? - sessionData.deviceData.timestamps.exist.set(p, sessionData.timestamp, 0) - sessionData.deviceData.timestamps.object.set(p, sessionData.timestamp, 0) - sessionData.deviceData.values.exist.set(p, 1, 0) - sessionData.deviceData.values.object.set(p, 0, 0) + if vparams['*'] + for k, v of sessionData.cache.virtualParameters + device.set(sessionData.deviceData, ['VirtualParameters', k], + {exist: sessionData.timestamp, object: sessionData.timestamp}, + {exist: 1, object: 0}) + + device.set(sessionData.deviceData, ['VirtualParameters', '*'], + {exist: sessionData.timestamp}) + else + for k of vparams + 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 return callback() @@ -189,14 +197,19 @@ inform = (sessionData, rpcReq, callback) -> addProvisions = (sessionData, channel, provisions) -> + sessionData.declarations = [] + sessionData.provisions.length = 1 + sessionData.doneProvisions = 0 + sessionData.doneDeclarations = 0 + for provision, i in 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) sessionData.provisions.splice(j, 1) sessionData.channels.splice(j, 1) - sessionData.provisions.push(provision) + sessionData.provisions[0].push(provision) sessionData.channels.push(channel) if sessionData.revisions.length > 1 or sessionData.revisions[0] > 0 @@ -210,9 +223,11 @@ addProvisions = (sessionData, channel, provisions) -> clearProvisions = (sessionData) -> delete sessionData.syncState - sessionData.provisions = [] + sessionData.provisions = [[]] sessionData.channels = [] sessionData.declarations = [] + sessionData.doneProvisions = 0 + sessionData.doneDeclarations = 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.values @@ -222,11 +237,11 @@ clearProvisions = (sessionData) -> sessionData.extensionsCache.length = 0 -runProvisions = (sessionData, callback) -> +runProvisions = (sessionData, provisions, startRevision, endRevision, callback) -> done = true _extensions = [] allDeclarations = [] - for provision in sessionData.provisions + for provision in provisions if not sessionData.cache.provisions[provision[0]]? switch provision[0] when 'refresh' @@ -264,81 +279,71 @@ runProvisions = (sessionData, callback) -> allDeclarations.push([p, {exist: sessionData.timestamp, object: 1, writable: 1, value: sessionData.timestamp}]) 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 _extensions = _extensions.concat(ret.extensions) done &&= ret.done allDeclarations = allDeclarations.concat(ret.declarations) if _extensions.length - return runExtensions(sessionData, (sessionData.revisions[0] >> 1), _extensions, (err) -> + return runExtensions(sessionData, endRevision, _extensions, (err) -> return callback(err) if err - return runProvisions(sessionData, callback) + return runProvisions(sessionData, provisions, startRevision, endRevision, callback) ) - for d in 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) + return callback(null, done, allDeclarations) -runVirtualParameters = (sessionData, inception, callback) -> - if not sessionData.syncState? or Object.keys(sessionData.syncState.virtualParameters).length == 0 - return callback() - - - virtualParameterDeclarations = sessionData.syncState.virtualParameters - sessionData.syncState.virtualParameters = {} - - revision = sessionData.revisions.reduce(((a, b) -> a + (b >> 1)), 0) + 1 - sessionData.revisions[inception] ?= 0 +runVirtualParameters = (sessionData, provisions, startRevision, endRevision, callback) -> + done = true decs = [] - virtualParameterUpdates = {} + virtualParameterUpdates = [] _extensions = [] - firstRevision = revision - (sessionData.revisions[sessionData.revisions.length - 1] >> 1) - for vpName, vpDeclarations of virtualParameterDeclarations - ret = sandbox.run(sessionData.cache.virtualParameters[vpName].script, [vpDeclarations.timestamps, vpDeclarations.values], sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, firstRevision, revision) + for provision in provisions + ret = sandbox.run(sessionData.cache.virtualParameters[provision[0]].script, provision[1], sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, startRevision, endRevision) if ret.extensions?.length _extensions = _extensions.concat(ret.extensions) - + done &&= ret.done decs = decs.concat(ret.declarations) if ret.done - virtualParameterUpdates[vpName] = ret.returnValue + virtualParameterUpdates.push([provision[0], ret.returnValue]) if _extensions.length - return runExtensions(sessionData, revision, _extensions, (err) -> + return runExtensions(sessionData, endRevision, _extensions, (err) -> return callback(err) if err - return runVirtualParameters(sessionData, inception, callback) + return runVirtualParameters(sessionData, provisions, startRevision, endRevision, callback) ) - for d in decs - state = applyDeclaration(sessionData, d[0], 0, d[1], d[2]) - sessionData.declarations.push([d[0], state, d[1], d[2]]) + if virtualParameterUpdates.length == provisions.length + for vpu, i in virtualParameterUpdates + 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 - v.revision = rev for k, v of sessionData.deviceData.timestamps - v.revision = rev for k, v of sessionData.deviceData.values - for vpName, vpDeclarations of virtualParameterDeclarations - commitVirtualParameter(sessionData, vpName, vpDeclarations, virtualParameterUpdates[vpName]) + for d in declarations + done &= applyDeclaration(sessionData, d[0], d[1], d[2]) - if sessionData.revisions[inception] > 0 - sessionData.revisions.length = inception - rev = sessionData.revisions.reduce(((a, b) -> a + (b >> 1)), 0) + 1 - m.collapse(rev) for k, m of sessionData.deviceData.timestamps - m.collapse(rev) for k, m of sessionData.deviceData.values - if sessionData.extensionsCache.length > rev - sessionData.extensionsCache.length = rev + if sessionData.syncState? and sessionData.syncState.virtualParameters? + provisions = [] + for k, v of sessionData.syncState.virtualParameters + provisions.push([k, v]) + sessionData.syncState.virtualParameters = {} - return runVirtualParameters(sessionData, inception + 1, callback) + return callback(null, done, provisions) -rpcRequest = (sessionData, declarations, callback) -> +rpcRequest = (sessionData, _declarations, callback) -> if sessionData.rpcRequest? return callback(null, generateRpcId(sessionData), sessionData.rpcRequest) @@ -346,77 +351,119 @@ rpcRequest = (sessionData, declarations, callback) -> sessionData.rpcRequest = 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.values - f = (cb) -> - return cb() if not sessionData.declarations.length + if _declarations?.length + sessionData.declarations = [] + sessionData.provisions[0] ?= [] + sessionData.revisions[0] ?= 0 + sessionData.doneDeclarations = 0 + sessionData.doneProvisions = 0 - for d, i in sessionData.declarations - state = applyDeclaration(sessionData, d[0], d[1], d[2], d[3]) - d[1] = state + if sessionData.declarations.length != sessionData.provisions.length + inception = sessionData.declarations.length + run = if inception == 0 then runProvisions else runVirtualParameters - if sessionData.toLoad?.length - return loadParameters(sessionData, (err) -> - return cb(err) if err - return f(cb) + return run(sessionData, sessionData.provisions[inception], sessionData.revisions[inception - 1] ? 0, sessionData.revisions[inception], f = (err, done, decs) -> + return callback(err) if err + + 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) -> - return cb(err) if err + rpcReq = generateRpcRequest(sessionData) + if not rpcReq? + while sessionData.doneDeclarations & (1 << (sessionData.declarations.length - 1)) + sessionData.declarations.pop() - if sessionData.toLoad?.length - return loadParameters(sessionData, (err) -> - return cb(err) if err - return f(cb) - ) + 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) - return cb(null, generateRpcRequest(sessionData)) - ) + sessionData.doneDeclarations &= (1 << sessionData.declarations.length) - 1 + sessionData.doneProvisions &= (1 << sessionData.provisions.length) - 1 - if declarations? - 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 + if sessionData.provisions.length == 1 and sessionData.doneProvisions return callback() + ++ 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) -> - syncState = sessionData.syncState + if not (syncState = sessionData.syncState)? + return iter = syncState.refreshAttributes.exist.values() while (path = iter.next().value) @@ -434,7 +481,6 @@ generateRpcRequest = (sessionData) -> syncState.refreshGpn.set(path, syncState.refreshGpn.get(path) or 1) syncState.refreshAttributes.exist.clear() - iter = syncState.refreshAttributes.object.values() while (path = iter.next().value) descendantIter = syncState.paths.subset(path, 99) @@ -471,36 +517,6 @@ generateRpcRequest = (sessionData) -> rpcReq = null 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 rpcReq? completed = false @@ -548,6 +564,47 @@ generateRpcRequest = (sessionData) -> 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 = config.get('TASK_PARAMETERS_BATCH_SIZE', sessionData.deviceId) @@ -555,22 +612,22 @@ generateRpcRequest = (sessionData) -> syncState.setValues.forEach((v, k) -> return if completed == false - if rpcReq? - completed = false - return + if (curVal = sessionData.deviceData.values.value.get(k))? and sessionData.deviceData.values.writable.get(k) + val = v.slice() + val[1] = curVal[1] if not val[1]? + device.sanitizeParameterValue(val) - val = v[1].slice() - if not val[1]? - val[1] = v[0][1] - device.sanitizeParameterValue(val) - if val[0] != v[0][0] or val[1] != v[0][1] - if parameterValues.length >= TASK_PARAMETERS_BATCH_SIZE - completed = false - return - parameterValues.push([k, val[0], val[1]]) - syncState.setValues.delete(k) + if val[0] != curVal[0] or val[1] != curVal[1] + if rpcReq? or parameterValues.length >= TASK_PARAMETERS_BATCH_SIZE + completed = false + return + + parameterValues.push([k, val[0], val[1]]) + syncState.setValues.delete(k) ) + syncState.setValues.clear() if not refreshDone + if parameterValues.length and not rpcReq? rpcReq = { type: 'SetParameterValues' @@ -589,6 +646,7 @@ processVirtualparameterDeclaration = (sessionData, path, timestamps, values) -> deviceData = sessionData.deviceData subIter = sessionData.deviceData.paths.subset(path) while sub = subIter.next().value + continue if sub[0] isnt 'VirtualParameters' continue if not deviceData.values.exist.get(sub) isWritable = deviceData.values.writable.get(sub) @@ -624,11 +682,12 @@ processDeclaration = (sessionData, path, _timestamps, values) -> timestamps = {} timestamps[k] = v for k, v of _timestamps + timestamps.exist ?= 1 ret = true 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] != '*' iter = sessionData.deviceData.paths.superset(path) @@ -660,20 +719,13 @@ processDeclaration = (sessionData, path, _timestamps, values) -> ret = false if values?.value? - if isObject == 0 and isWritable == 1 - cur = syncState.setValues.get(param) - if not cur? - cur = [deviceData.values.value.get(param), values.value] - syncState.setValues.set(param, cur) - else - cur[1] = values.value - else - if not isObject? - syncState.refreshAttributes.object.add(param) - ret = false - if not isWritable? - syncState.refreshAttributes.writable.add(param) - ret = false + syncState.setValues.set(param, values.value) + if not isObject? + syncState.refreshAttributes.object.add(param) + ret = false + if not isWritable? + syncState.refreshAttributes.writable.add(param) + ret = false return ret else if existTimestamp >= (timestamps.exist or 1) return ret @@ -697,23 +749,16 @@ processDeclaration = (sessionData, path, _timestamps, values) -> ret = false if values?.value? - if isObject == 0 and isWritable == 1 - cur = syncState.setValues.get(sub) - if not cur? - cur = [deviceData.values.value.get(sub), values.value] - syncState.setValues.set(sub, cur) - else - cur[1] = values.value - else - if not isObject? - syncState.refreshAttributes.object.add(sub) - ret = false - if not isWritable? - syncState.refreshAttributes.writable.add(sub) - ret = false + syncState.setValues.set(sub, values.value) + 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) - return + return ret childrenTimestamp = existTimestamp @@ -755,7 +800,7 @@ processDeclaration = (sessionData, path, _timestamps, values) -> pp = sub.concat(path.slice(sub.length)) ts = {} 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) return ret @@ -833,12 +878,7 @@ processInstances = (sessionData, parent, parameters, keys, minInstances, maxInst return -applyDeclaration = (sessionData, path, state, timestamps, values) -> - if state == 100 - if not values? or Object.keys(values).length == 0 - return state - timestamps = {} - +applyDeclaration = (sessionData, path, timestamps, values) -> sessionData.syncState ?= { paths: new PathSet() refreshAttributes: { @@ -856,60 +896,46 @@ applyDeclaration = (sessionData, path, state, timestamps, values) -> 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 - satisfied = processDeclaration(sessionData, decs[0][0], timestamps, values) - if satisfied - return 100 + processDeclaration(sessionData, decs[0][0], timestamps, values) + return true + + 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 - return 2 - else - if state <= 2 - satisfied = true + minInstances = maxInstances = values.exist - for d in decs - satisfied &&= processDeclaration(sessionData, d[0], d[1], d[2]) + parent = path.slice(0, -1) - 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 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 + if (path.wildcard | path.alias) & ((1 << (path.length - 1)) - 1) == 0 + processInstances(sessionData, parent, unpacked, keys, minInstances, maxInstances) 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) -> @@ -938,7 +964,7 @@ commitVirtualParameter = (sessionData, name, declaration, update) -> t.value = Math.max(declaration.timestamps.value, t.value) 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') device.set(sessionData.deviceData, ['VirtualParameters', name], t, v)