Simplify declare function in scripts
Using declare function is made easier by accept a single path and returning a promise to read parameter attributes.
This commit is contained in:
1 parent
044734b567
commit
b4bbd8f58c
4 files changed
+347
-219
No files matched your search
+2
-2
@@ -167,7 +167,7 @@ refresh = (callback) ->
|
|||||||
for r in res
|
for r in res
|
||||||
provisions[r._id] = {}
|
provisions[r._id] = {}
|
||||||
provisions[r._id].md5 = crypto.createHash('md5').update(r.script).digest('hex')
|
provisions[r._id].md5 = crypto.createHash('md5').update(r.script).digest('hex')
|
||||||
provisions[r._id].script = new vm.Script(r.script, {filename: r._id, timeout: 50})
|
provisions[r._id].script = new vm.Script("\"use strict\";(function(){\n#{r.script}\n})();", {filename: r._id, lineOffset: 1, timeout: 50})
|
||||||
|
|
||||||
if -- counter == 0
|
if -- counter == 0
|
||||||
computeHash()
|
computeHash()
|
||||||
@@ -188,7 +188,7 @@ refresh = (callback) ->
|
|||||||
for r in res
|
for r in res
|
||||||
virtualParameters[r._id] = {}
|
virtualParameters[r._id] = {}
|
||||||
virtualParameters[r._id].md5 = crypto.createHash('md5').update(r.script).digest('hex')
|
virtualParameters[r._id].md5 = crypto.createHash('md5').update(r.script).digest('hex')
|
||||||
virtualParameters[r._id].script = new vm.Script(r.script, {filename: r._id, timeout: 50})
|
virtualParameters[r._id].script = new vm.Script("\"use strict\";(function(){\n#{r.script}\n})();", {filename: r._id, lineOffset: 1, timeout: 50})
|
||||||
|
|
||||||
if -- counter == 0
|
if -- counter == 0
|
||||||
computeHash()
|
computeHash()
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
###
|
|
||||||
# Copyright 2013-2016 Zaid Abdulla
|
|
||||||
#
|
|
||||||
# GenieACS is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU Affero General Public License as
|
|
||||||
# published by the Free Software Foundation, either version 3 of the
|
|
||||||
# License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# GenieACS is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU Affero General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
|
||||||
# along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
###
|
|
||||||
|
|
||||||
vm = require 'vm'
|
|
||||||
|
|
||||||
common = require './common'
|
|
||||||
device = require './device'
|
|
||||||
|
|
||||||
|
|
||||||
# Used for throwing to exit user script
|
|
||||||
class Exit;
|
|
||||||
|
|
||||||
|
|
||||||
sandbox = {
|
|
||||||
timestamp: null
|
|
||||||
deviceData: null
|
|
||||||
revision: null
|
|
||||||
maxRevision: null
|
|
||||||
declarations: null
|
|
||||||
extensionsCache: null
|
|
||||||
extensions: null
|
|
||||||
context: vm.createContext()
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.defineProperty(sandbox.context, 'Date', {value: class
|
|
||||||
constructor: (arg) ->
|
|
||||||
if arguments.length
|
|
||||||
return new (Function.prototype.bind.apply(Date, arguments))
|
|
||||||
|
|
||||||
return new Date(sandbox.timestamp)
|
|
||||||
|
|
||||||
@now: () ->
|
|
||||||
return sandbox.timestamp
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
extCall = (String(a) for a in arguments)
|
|
||||||
key = JSON.stringify(extCall)
|
|
||||||
if not sandbox.extensionsCache[sandbox.revision]? or key not of sandbox.extensionsCache[sandbox.revision]
|
|
||||||
sandbox.extensions = [extCall]
|
|
||||||
throw new Exit()
|
|
||||||
|
|
||||||
return sandbox.extensionsCache[sandbox.revision][key]
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
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')
|
|
||||||
|
|
||||||
if sandbox.revision == sandbox.maxRevision + 1
|
|
||||||
for k, v of decs
|
|
||||||
timestamp = 1
|
|
||||||
exist = null
|
|
||||||
attributeTimestamps = {}
|
|
||||||
attributeValues = {}
|
|
||||||
for attrName, dec of v
|
|
||||||
if attrName is 'exist'
|
|
||||||
if Array.isArray(dec)
|
|
||||||
timestamp = dec[0]
|
|
||||||
exist = dec[1] if 1 of dec
|
|
||||||
else
|
|
||||||
timestamp = dec
|
|
||||||
continue
|
|
||||||
|
|
||||||
if Array.isArray(dec)
|
|
||||||
attributeTimestamps[attrName] = dec[0]
|
|
||||||
attributeValues[attrName] = dec[1] if 1 of dec
|
|
||||||
else
|
|
||||||
attributeTimestamps[attrName] = dec
|
|
||||||
|
|
||||||
sandbox.declarations.push([common.parsePath(k), timestamp, attributeTimestamps, exist, attributeValues])
|
|
||||||
|
|
||||||
throw new Exit()
|
|
||||||
|
|
||||||
res = {}
|
|
||||||
for k, v of decs
|
|
||||||
path = common.parsePath(k)
|
|
||||||
single = true
|
|
||||||
for p in path
|
|
||||||
if p == '*' or common.typeOf(p) isnt common.STRING_TYPE
|
|
||||||
single = false
|
|
||||||
break
|
|
||||||
|
|
||||||
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision)
|
|
||||||
for param in unpacked
|
|
||||||
r = {}
|
|
||||||
attrs = sandbox.deviceData.attributes.get(param, sandbox.revision)
|
|
||||||
for attrName, dec of v
|
|
||||||
if attrName of attrs
|
|
||||||
r[attrName] = attrs[attrName]
|
|
||||||
|
|
||||||
if single
|
|
||||||
res[k] = r
|
|
||||||
else
|
|
||||||
res[k] ?= {}
|
|
||||||
res[k][param.join('.')] = r
|
|
||||||
|
|
||||||
return res
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
Object.defineProperty(sandbox.context, 'clear', {value: (pattern, timestamp) ->
|
|
||||||
if sandbox.revision == sandbox.maxRevision
|
|
||||||
sandbox.clear ?= []
|
|
||||||
sandbox.clear.push([common.parsePath(pattern), timestamp])
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
run = (script, globals, timestamp, deviceData, extensionsCache, startRevision, maxRevision) ->
|
|
||||||
sandbox.timestamp = timestamp
|
|
||||||
sandbox.deviceData = deviceData
|
|
||||||
sandbox.extensionsCache = extensionsCache
|
|
||||||
sandbox.revision = startRevision
|
|
||||||
sandbox.maxRevision = maxRevision
|
|
||||||
sandbox.declarations = []
|
|
||||||
sandbox.extensions = null
|
|
||||||
sandbox.clear = 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, extensions: sandbox.extensions, clear: sandbox.clear, 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, clear: sandbox.clear}
|
|
||||||
|
|
||||||
|
|
||||||
exports.run = run
|
|
||||||
+281
@@ -0,0 +1,281 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2013-2016 Zaid Abdulla
|
||||||
|
*
|
||||||
|
* GenieACS is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GenieACS is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const vm = require("vm");
|
||||||
|
|
||||||
|
const common = require("./common");
|
||||||
|
const device = require("./device");
|
||||||
|
const extensions = require("./extensions");
|
||||||
|
|
||||||
|
|
||||||
|
// Used for throwing to exit user script and commit
|
||||||
|
const COMMIT = Symbol();
|
||||||
|
|
||||||
|
// Used to execute extensions and restart
|
||||||
|
const EXT = Symbol();
|
||||||
|
|
||||||
|
const sandbox = {
|
||||||
|
timestamp: null,
|
||||||
|
deviceData: null,
|
||||||
|
revision: null,
|
||||||
|
maxRevision: null,
|
||||||
|
uncommitted: false,
|
||||||
|
declarations: null,
|
||||||
|
extensionsCache: null,
|
||||||
|
extensions: null,
|
||||||
|
context: vm.createContext()
|
||||||
|
}
|
||||||
|
|
||||||
|
class SandboxDate {
|
||||||
|
constructor(arg) {
|
||||||
|
if (arguments.length)
|
||||||
|
return new (Function.prototype.bind.apply(Date, arguments));
|
||||||
|
|
||||||
|
return new Date(sandbox.timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static now() {
|
||||||
|
return sandbox.timestamp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterWrapper {
|
||||||
|
constructor(path, attributes, unpacked, unpackedRevision) {
|
||||||
|
for (let attrName of attributes) {
|
||||||
|
Object.defineProperty(this, attrName, {get: function() {
|
||||||
|
if (sandbox.uncommitted)
|
||||||
|
commit();
|
||||||
|
|
||||||
|
if (sandbox.revision !== unpackedRevision) {
|
||||||
|
unpackedRevision = sandbox.revision;
|
||||||
|
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unpacked.length)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
let attr = sandbox.deviceData.attributes.get(unpacked[0], sandbox.revision + 1)[attrName];
|
||||||
|
|
||||||
|
if (!attr)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
return attr[1];
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(this, "path", {get: function() {
|
||||||
|
if (sandbox.uncommitted)
|
||||||
|
commit();
|
||||||
|
|
||||||
|
if (sandbox.revision !== unpackedRevision) {
|
||||||
|
unpackedRevision = sandbox.revision;
|
||||||
|
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unpacked.length)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
return unpacked[0].join('.');
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(this, "size", {get: function() {
|
||||||
|
if (sandbox.uncommitted)
|
||||||
|
commit();
|
||||||
|
|
||||||
|
if (sandbox.revision !== unpackedRevision) {
|
||||||
|
unpackedRevision = sandbox.revision;
|
||||||
|
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unpacked.length)
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
return unpacked.length;
|
||||||
|
}});
|
||||||
|
|
||||||
|
this[Symbol.iterator] = function*() {
|
||||||
|
if (sandbox.uncommitted)
|
||||||
|
commit();
|
||||||
|
|
||||||
|
if (sandbox.revision !== unpackedRevision) {
|
||||||
|
unpackedRevision = sandbox.revision;
|
||||||
|
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let p of unpacked)
|
||||||
|
yield new ParameterWrapper(p, attributes, [p], sandbox.revision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function declare(path, timestamps, values) {
|
||||||
|
sandbox.uncommitted = true;
|
||||||
|
if (!timestamps)
|
||||||
|
timestamps = {};
|
||||||
|
|
||||||
|
let parsedPath = common.parsePath(path);
|
||||||
|
|
||||||
|
sandbox.declarations[path] = sandbox.declarations[path] || [parsedPath, 1, {}, null, {}];
|
||||||
|
|
||||||
|
let attrs = {};
|
||||||
|
for (let attrName in timestamps) {
|
||||||
|
if (attrName === "path") {
|
||||||
|
if (timestamps.path > sandbox.declarations[path][1])
|
||||||
|
sandbox.declarations[path][1] = timestamps.path;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
attrs[attrName] = 1;
|
||||||
|
if (!(timestamps[attrName] <= sandbox.declarations[path][2][attrName]))
|
||||||
|
sandbox.declarations[path][2][attrName] = timestamps[attrName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values) {
|
||||||
|
for (let attrName in values) {
|
||||||
|
if (attrName === "path")
|
||||||
|
sandbox.declarations[path][3] = values.path;
|
||||||
|
else {
|
||||||
|
attrs[attrName] = 1;
|
||||||
|
if (attrName === 'value' && !Array.isArray(values[attrName]))
|
||||||
|
sandbox.declarations[path][4].value = [values[attrName]];
|
||||||
|
else
|
||||||
|
sandbox.declarations[path][4].value = values[attrName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ParameterWrapper(parsedPath, Object.keys(attrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function clear(path, timestamp, attributes) {
|
||||||
|
sandbox.uncommitted = true;
|
||||||
|
|
||||||
|
if (sandbox.revision === sandbox.maxRevision) {
|
||||||
|
sandbox.clear = sandbox.clear || [];
|
||||||
|
sandbox.clear.push([common.parsePath(path), timestamp, attributes]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function commit() {
|
||||||
|
++ sandbox.revision;
|
||||||
|
sandbox.uncommitted = false;
|
||||||
|
|
||||||
|
if (sandbox.revision === sandbox.maxRevision + 1)
|
||||||
|
throw COMMIT;
|
||||||
|
else if (sandbox.revision > sandbox.maxRevision + 1)
|
||||||
|
throw new Error("Declare function should not be called from within a try/catch block");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ext() {
|
||||||
|
let extCall = Array.from(arguments).map(String);
|
||||||
|
let key = `${sandbox.revision}: ${JSON.stringify(extCall)}`;
|
||||||
|
|
||||||
|
if (key in sandbox.extensionsCache)
|
||||||
|
return sandbox.extensionsCache[key];
|
||||||
|
|
||||||
|
sandbox.extensions[key] = extCall;
|
||||||
|
throw EXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Object.defineProperty(sandbox.context, 'Date', {value: SandboxDate});
|
||||||
|
Object.defineProperty(sandbox.context, 'declare', {value: declare});
|
||||||
|
Object.defineProperty(sandbox.context, 'clear', {value: clear});
|
||||||
|
Object.defineProperty(sandbox.context, 'commit', {value: commit});
|
||||||
|
Object.defineProperty(sandbox.context, 'ext', {value: ext});
|
||||||
|
|
||||||
|
|
||||||
|
function run(script, globals, timestamp, deviceData, extensionsCache, startRevision, maxRevision, callback) {
|
||||||
|
sandbox.timestamp = timestamp;
|
||||||
|
sandbox.deviceData = deviceData;
|
||||||
|
sandbox.extensionsCache = extensionsCache;
|
||||||
|
sandbox.revision = startRevision;
|
||||||
|
sandbox.maxRevision = maxRevision;
|
||||||
|
sandbox.uncommitted = false;
|
||||||
|
sandbox.declarations = {};
|
||||||
|
sandbox.extensions = {};
|
||||||
|
sandbox.clear = null;
|
||||||
|
|
||||||
|
for (let n in sandbox.context)
|
||||||
|
delete sandbox.context[n];
|
||||||
|
|
||||||
|
for (let n in globals)
|
||||||
|
sandbox.context[n] = globals[n];
|
||||||
|
|
||||||
|
try {
|
||||||
|
let ret = script.runInContext(sandbox.context, {displayErrors: false});
|
||||||
|
|
||||||
|
let declarations = [];
|
||||||
|
for (let p in sandbox.declarations)
|
||||||
|
declarations.push(sandbox.declarations[p]);
|
||||||
|
|
||||||
|
let counter = 1;
|
||||||
|
for (let key in sandbox.extensions) {
|
||||||
|
++ counter;
|
||||||
|
extensions.run(sandbox.extensions[key], function(err, res) {
|
||||||
|
sandbox.extensionsCache[key] = res;
|
||||||
|
if (-- counter === 0)
|
||||||
|
return callback(null, sandbox.clear, declarations, true, ret);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (-- counter === 0)
|
||||||
|
return callback(null, sandbox.clear, declarations, true, ret);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err === COMMIT) {
|
||||||
|
let declarations = [];
|
||||||
|
for (let p in sandbox.declarations)
|
||||||
|
declarations.push(sandbox.declarations[p]);
|
||||||
|
|
||||||
|
let counter = 1;
|
||||||
|
for (let key in sandbox.extensions) {
|
||||||
|
++ counter;
|
||||||
|
extensions.run(sandbox.extensions[key], function(err, res) {
|
||||||
|
sandbox.extensionsCache[key] = res;
|
||||||
|
if (-- counter === 0)
|
||||||
|
return callback(null, sandbox.clear, declarations, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (-- counter === 0)
|
||||||
|
return callback(null, sandbox.clear, declarations, false);
|
||||||
|
}
|
||||||
|
else if (err === EXT) {
|
||||||
|
let counter = 1;
|
||||||
|
for (let key in sandbox.extensions) {
|
||||||
|
++ counter;
|
||||||
|
extensions.run(sandbox.extensions[key], function(err, res) {
|
||||||
|
sandbox.extensionsCache[key] = res;
|
||||||
|
if (-- counter === 0)
|
||||||
|
return run(script, globals, timestamp, deviceData, extensionsCache, startRevision, maxRevision, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (-- counter === 0)
|
||||||
|
return run(script, globals, timestamp, deviceData, extensionsCache, startRevision, maxRevision, callback);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.run = run;
|
||||||
+64
-65
@@ -52,7 +52,7 @@ init = (deviceId, cwmpVersion, timeout, callback) ->
|
|||||||
revisions: []
|
revisions: []
|
||||||
rpcCount: 0
|
rpcCount: 0
|
||||||
iteration: 0
|
iteration: 0
|
||||||
extensionsCache: []
|
extensionsCache: {}
|
||||||
declarations: []
|
declarations: []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ addProvisions = (sessionData, channel, provisions) ->
|
|||||||
v.collapse(1) for k, v of sessionData.deviceData.attributes
|
v.collapse(1) for k, v of sessionData.deviceData.attributes
|
||||||
sessionData.rpcCount = 0
|
sessionData.rpcCount = 0
|
||||||
sessionData.revisions = [0]
|
sessionData.revisions = [0]
|
||||||
sessionData.extensionsCache.length = 0
|
sessionData.extensionsCache = {}
|
||||||
|
|
||||||
|
|
||||||
clearProvisions = (sessionData) ->
|
clearProvisions = (sessionData) ->
|
||||||
@@ -195,7 +195,7 @@ clearProvisions = (sessionData) ->
|
|||||||
sessionData.deviceData.attributes.collapse(1)
|
sessionData.deviceData.attributes.collapse(1)
|
||||||
sessionData.rpcCount = 0
|
sessionData.rpcCount = 0
|
||||||
sessionData.revisions = [0]
|
sessionData.revisions = [0]
|
||||||
sessionData.extensionsCache.length = 0
|
sessionData.extensionsCache = {}
|
||||||
|
|
||||||
|
|
||||||
runProvisions = (sessionData, provisions, startRevision, endRevision, callback) ->
|
runProvisions = (sessionData, provisions, startRevision, endRevision, callback) ->
|
||||||
@@ -203,6 +203,7 @@ runProvisions = (sessionData, provisions, startRevision, endRevision, callback)
|
|||||||
_extensions = []
|
_extensions = []
|
||||||
_clear = []
|
_clear = []
|
||||||
allDeclarations = []
|
allDeclarations = []
|
||||||
|
counter = 1
|
||||||
for provision in 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]
|
||||||
@@ -245,22 +246,27 @@ runProvisions = (sessionData, provisions, startRevision, endRevision, callback)
|
|||||||
allDeclarations.push([['FactoryReset'], 1, {value: 1}, null, {value: [sessionData.timestamp]}])
|
allDeclarations.push([['FactoryReset'], 1, {value: 1}, null, {value: [sessionData.timestamp]}])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
ret = sandbox.run(sessionData.cache.provisions[provision[0]].script, {args: provision[1]}, sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, startRevision, endRevision)
|
++ counter
|
||||||
|
sandbox.run(sessionData.cache.provisions[provision[0]].script,
|
||||||
|
{args: provision[1]}, sessionData.timestamp, sessionData.deviceData,
|
||||||
|
sessionData.extensionsCache, startRevision, endRevision,
|
||||||
|
(err, _clear, _declarations, _done) ->
|
||||||
|
-- counter
|
||||||
|
if err
|
||||||
|
if counter >= 0
|
||||||
|
counter = 0
|
||||||
|
return callback(err)
|
||||||
|
return
|
||||||
|
|
||||||
if ret.extensions?.length
|
done &&= _done
|
||||||
_extensions = _extensions.concat(ret.extensions)
|
allDeclarations = allDeclarations.concat(_declarations)
|
||||||
if ret.clear?.length
|
|
||||||
_clear = _clear.concat(ret.clear)
|
|
||||||
done &&= ret.done
|
|
||||||
allDeclarations = allDeclarations.concat(ret.declarations)
|
|
||||||
|
|
||||||
if _extensions.length
|
if counter == 0
|
||||||
return runExtensions(sessionData, endRevision, _extensions, (err) ->
|
return callback(null, done, allDeclarations, _clear)
|
||||||
return callback(err) if err
|
)
|
||||||
return runProvisions(sessionData, provisions, startRevision, endRevision, callback)
|
|
||||||
)
|
|
||||||
|
|
||||||
return callback(null, done, allDeclarations, _clear)
|
if -- counter == 0
|
||||||
|
return callback(null, done, allDeclarations, _clear)
|
||||||
|
|
||||||
|
|
||||||
runVirtualParameters = (sessionData, provisions, startRevision, endRevision, callback) ->
|
runVirtualParameters = (sessionData, provisions, startRevision, endRevision, callback) ->
|
||||||
@@ -269,36 +275,48 @@ runVirtualParameters = (sessionData, provisions, startRevision, endRevision, cal
|
|||||||
virtualParameterUpdates = []
|
virtualParameterUpdates = []
|
||||||
_extensions = []
|
_extensions = []
|
||||||
_clear = []
|
_clear = []
|
||||||
|
counter = 1
|
||||||
for provision in provisions
|
for provision in provisions
|
||||||
|
++ counter
|
||||||
globals = {TIMESTAMPS: provision[1], VALUES: provision[2]}
|
globals = {TIMESTAMPS: provision[1], VALUES: provision[2]}
|
||||||
ret = sandbox.run(sessionData.cache.virtualParameters[provision[0]].script, globals, sessionData.timestamp, sessionData.deviceData, sessionData.extensionsCache, startRevision, endRevision)
|
sandbox.run(sessionData.cache.virtualParameters[provision[0]].script, globals,
|
||||||
if ret.extensions?.length
|
sessionData.timestamp, sessionData.deviceData,
|
||||||
_extensions = _extensions.concat(ret.extensions)
|
sessionData.extensionsCache, startRevision, endRevision,
|
||||||
if ret.clear?.length
|
(err, _clear, _declarations, _done, _returnValue) ->
|
||||||
_clear = _clear.concat(ret.clear)
|
-- counter
|
||||||
|
if err
|
||||||
|
if counter >= 0
|
||||||
|
counter = 0
|
||||||
|
return callback(err)
|
||||||
|
return
|
||||||
|
|
||||||
done &&= ret.done
|
done &&= _done
|
||||||
decs = decs.concat(ret.declarations)
|
decs = decs.concat(_declarations)
|
||||||
|
|
||||||
if ret.done
|
if _done
|
||||||
virtualParameterUpdates.push(ret.returnValue)
|
virtualParameterUpdates.push(_returnValue)
|
||||||
|
|
||||||
if _extensions.length
|
if counter == 0
|
||||||
return runExtensions(sessionData, endRevision, _extensions, (err) ->
|
toClear = null
|
||||||
return callback(err) if err
|
if virtualParameterUpdates.length == provisions.length
|
||||||
return runVirtualParameters(sessionData, provisions, startRevision, endRevision, callback)
|
for vpu, i in virtualParameterUpdates
|
||||||
|
toClear = commitVirtualParameter(sessionData, provisions[i], vpu, toClear)
|
||||||
|
|
||||||
|
clear(sessionData, toClear, (err) ->
|
||||||
|
return callback(err, done, decs, _clear)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if -- counter == 0
|
||||||
|
toClear = null
|
||||||
|
if virtualParameterUpdates.length == provisions.length
|
||||||
|
for vpu, i in virtualParameterUpdates
|
||||||
|
toClear = commitVirtualParameter(sessionData, provisions[i], vpu, toClear)
|
||||||
|
|
||||||
|
clear(sessionData, toClear, (err) ->
|
||||||
|
return callback(err, done, decs, _clear)
|
||||||
)
|
)
|
||||||
|
|
||||||
toClear = null
|
|
||||||
if virtualParameterUpdates.length == provisions.length
|
|
||||||
for vpu, i in virtualParameterUpdates
|
|
||||||
toClear = commitVirtualParameter(sessionData, provisions[i], vpu, toClear)
|
|
||||||
|
|
||||||
clear(sessionData, toClear, (err) ->
|
|
||||||
return callback(err, done, decs, _clear)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
runDeclarations = (sessionData, declarations) ->
|
runDeclarations = (sessionData, declarations) ->
|
||||||
sessionData.iteration += 2
|
sessionData.iteration += 2
|
||||||
@@ -388,8 +406,8 @@ runDeclarations = (sessionData, declarations) ->
|
|||||||
|
|
||||||
if declaration[3]?
|
if declaration[3]?
|
||||||
if Array.isArray(declaration[3])
|
if Array.isArray(declaration[3])
|
||||||
minInstances = declaration[3].exist[0]
|
minInstances = declaration[3][0]
|
||||||
maxInstances = declaration[3].exist[1]
|
maxInstances = declaration[3][1]
|
||||||
else
|
else
|
||||||
minInstances = maxInstances = declaration[3]
|
minInstances = maxInstances = declaration[3]
|
||||||
|
|
||||||
@@ -557,13 +575,16 @@ rpcRequest = (sessionData, _declarations, callback) ->
|
|||||||
delete sessionData.syncState
|
delete sessionData.syncState
|
||||||
sessionData.deviceData.timestamps.collapse(1)
|
sessionData.deviceData.timestamps.collapse(1)
|
||||||
sessionData.deviceData.attributes.collapse(1)
|
sessionData.deviceData.attributes.collapse(1)
|
||||||
sessionData.extensionsCache.splice(0)
|
sessionData.extensionsCache = {}
|
||||||
return callback(null, null, null, doneProvisions)
|
return callback(null, null, null, doneProvisions)
|
||||||
|
|
||||||
rev = sessionData.revisions[sessionData.revisions.length - 1]
|
rev = sessionData.revisions[sessionData.revisions.length - 1]
|
||||||
sessionData.deviceData.timestamps.collapse(rev + 1)
|
sessionData.deviceData.timestamps.collapse(rev + 1)
|
||||||
sessionData.deviceData.attributes.collapse(rev + 1)
|
sessionData.deviceData.attributes.collapse(rev + 1)
|
||||||
sessionData.extensionsCache.splice(rev)
|
for k of sessionData.extensionsCache
|
||||||
|
n = Number(k.split(':', 1)[0])
|
||||||
|
if n > rev
|
||||||
|
delete sessionData.extensionsCache[k]
|
||||||
|
|
||||||
sessionData.syncState.virtualParameterDeclarations.length = sessionData.declarations.length
|
sessionData.syncState.virtualParameterDeclarations.length = sessionData.declarations.length
|
||||||
|
|
||||||
@@ -1039,28 +1060,6 @@ commitVirtualParameter = (sessionData, provision, update, toClear) ->
|
|||||||
return device.set(sessionData.deviceData, ['VirtualParameters', provision[0]], timestamp, attributes, toClear)
|
return device.set(sessionData.deviceData, ['VirtualParameters', provision[0]], timestamp, attributes, toClear)
|
||||||
|
|
||||||
|
|
||||||
runExtensions = (sessionData, revision, _extensions, callback) ->
|
|
||||||
sessionData.extensionsCache[revision] ?= {}
|
|
||||||
obj = {}
|
|
||||||
for e in _extensions
|
|
||||||
obj[JSON.stringify(e)] = e
|
|
||||||
|
|
||||||
counter = 1
|
|
||||||
for k, v of obj
|
|
||||||
++ counter
|
|
||||||
do (k, v) ->
|
|
||||||
extensions.run(v, (err, res) ->
|
|
||||||
sessionData.extensionsCache[revision][k] = res
|
|
||||||
|
|
||||||
if -- counter == 0 or err
|
|
||||||
counter = 0
|
|
||||||
return callback(err)
|
|
||||||
)
|
|
||||||
|
|
||||||
if -- counter == 0
|
|
||||||
return callback()
|
|
||||||
|
|
||||||
|
|
||||||
rpcResponse = (sessionData, id, rpcRes, callback) ->
|
rpcResponse = (sessionData, id, rpcRes, callback) ->
|
||||||
if id != generateRpcId(sessionData)
|
if id != generateRpcId(sessionData)
|
||||||
return callback(new Error('Request ID not recognized'))
|
return callback(new Error('Request ID not recognized'))
|
||||||
|
|||||||
Reference in new issue
Block a user