Pass sessionContext to sandbox
This commit is contained in:
1 parent
59d412155b
commit
d92ca4c2bf
2 files changed
+77
-94
No files matched your search
+70
-85
@@ -31,38 +31,29 @@ const COMMIT = Symbol();
|
|||||||
// Used to execute extensions and restart
|
// Used to execute extensions and restart
|
||||||
const EXT = Symbol();
|
const EXT = Symbol();
|
||||||
|
|
||||||
const sandbox = {
|
const context = vm.createContext();
|
||||||
timestamp: null,
|
|
||||||
deviceData: null,
|
let state;
|
||||||
revision: null,
|
|
||||||
maxRevision: null,
|
|
||||||
uncommitted: false,
|
|
||||||
declarations: null,
|
|
||||||
extensionsCache: null,
|
|
||||||
extensions: null,
|
|
||||||
clear: null,
|
|
||||||
rng: null,
|
|
||||||
context: vm.createContext()
|
|
||||||
}
|
|
||||||
|
|
||||||
class SandboxDate {
|
class SandboxDate {
|
||||||
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));
|
||||||
|
|
||||||
return new Date(sandbox.timestamp);
|
return new Date(state.sessionContext.timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static now() {
|
static now() {
|
||||||
return sandbox.timestamp;
|
return state.sessionContext.timestamp;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function random() {
|
function random() {
|
||||||
if (!sandbox.rng)
|
if (!state.rng)
|
||||||
sandbox.rng = seedrandom(sandbox.timestamp);
|
state.rng = seedrandom(sessionContext.timestamp);
|
||||||
|
|
||||||
return sandbox.rng();
|
return state.rng();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -70,18 +61,18 @@ class ParameterWrapper {
|
|||||||
constructor(path, attributes, unpacked, unpackedRevision) {
|
constructor(path, attributes, unpacked, unpackedRevision) {
|
||||||
for (let attrName of attributes) {
|
for (let attrName of attributes) {
|
||||||
Object.defineProperty(this, attrName, {get: function() {
|
Object.defineProperty(this, attrName, {get: function() {
|
||||||
if (sandbox.uncommitted)
|
if (state.uncommitted)
|
||||||
commit();
|
commit();
|
||||||
|
|
||||||
if (sandbox.revision !== unpackedRevision) {
|
if (state.revision !== unpackedRevision) {
|
||||||
unpackedRevision = sandbox.revision;
|
unpackedRevision = state.revision;
|
||||||
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
unpacked = device.unpack(state.sessionContext.deviceData, path, state.revision + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unpacked.length)
|
if (!unpacked.length)
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
let attr = sandbox.deviceData.attributes.get(unpacked[0], sandbox.revision + 1)[attrName];
|
let attr = state.sessionContext.deviceData.attributes.get(unpacked[0], state.revision + 1)[attrName];
|
||||||
|
|
||||||
if (!attr)
|
if (!attr)
|
||||||
return undefined;
|
return undefined;
|
||||||
@@ -91,27 +82,27 @@ class ParameterWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(this, "path", {get: function() {
|
Object.defineProperty(this, "path", {get: function() {
|
||||||
if (sandbox.uncommitted)
|
if (state.uncommitted)
|
||||||
commit();
|
commit();
|
||||||
|
|
||||||
if (sandbox.revision !== unpackedRevision) {
|
if (state.revision !== unpackedRevision) {
|
||||||
unpackedRevision = sandbox.revision;
|
unpackedRevision = state.revision;
|
||||||
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
unpacked = device.unpack(state.sessionContext.deviceData, path, state.revision + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unpacked.length)
|
if (!unpacked.length)
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
||||||
return unpacked[0].join('.');
|
return unpacked[0].join(".");
|
||||||
}});
|
}});
|
||||||
|
|
||||||
Object.defineProperty(this, "size", {get: function() {
|
Object.defineProperty(this, "size", {get: function() {
|
||||||
if (sandbox.uncommitted)
|
if (state.uncommitted)
|
||||||
commit();
|
commit();
|
||||||
|
|
||||||
if (sandbox.revision !== unpackedRevision) {
|
if (state.revision !== unpackedRevision) {
|
||||||
unpackedRevision = sandbox.revision;
|
unpackedRevision = state.revision;
|
||||||
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
unpacked = device.unpack(state.sessionContext.deviceData, path, state.revision + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unpacked.length)
|
if (!unpacked.length)
|
||||||
@@ -121,23 +112,23 @@ class ParameterWrapper {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
this[Symbol.iterator] = function*() {
|
this[Symbol.iterator] = function*() {
|
||||||
if (sandbox.uncommitted)
|
if (state.uncommitted)
|
||||||
commit();
|
commit();
|
||||||
|
|
||||||
if (sandbox.revision !== unpackedRevision) {
|
if (state.revision !== unpackedRevision) {
|
||||||
unpackedRevision = sandbox.revision;
|
unpackedRevision = state.revision;
|
||||||
unpacked = device.unpack(sandbox.deviceData, path, sandbox.revision + 1);
|
unpacked = device.unpack(state.sessionContext.deviceData, path, state.revision + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let p of unpacked)
|
for (let p of unpacked)
|
||||||
yield new ParameterWrapper(p, attributes, [p], sandbox.revision);
|
yield new ParameterWrapper(p, attributes, [p], state.revision);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function declare(path, timestamps, values) {
|
function declare(path, timestamps, values) {
|
||||||
sandbox.uncommitted = true;
|
state.uncommitted = true;
|
||||||
if (!timestamps)
|
if (!timestamps)
|
||||||
timestamps = {};
|
timestamps = {};
|
||||||
|
|
||||||
@@ -175,55 +166,53 @@ function declare(path, timestamps, values) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sandbox.declarations.push(declaration);
|
state.declarations.push(declaration);
|
||||||
|
|
||||||
return new ParameterWrapper(parsedPath, Object.keys(attrs));
|
return new ParameterWrapper(parsedPath, Object.keys(attrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function clear(path, timestamp, attributes) {
|
function clear(path, timestamp, attributes) {
|
||||||
sandbox.uncommitted = true;
|
state.uncommitted = true;
|
||||||
|
|
||||||
if (sandbox.revision === sandbox.maxRevision) {
|
if (state.revision === maxRevision)
|
||||||
sandbox.clear = sandbox.clear || [];
|
state.clear.push([common.parsePath(path), timestamp, attributes]);
|
||||||
sandbox.clear.push([common.parsePath(path), timestamp, attributes]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function commit() {
|
function commit() {
|
||||||
++ sandbox.revision;
|
++ state.revision;
|
||||||
sandbox.uncommitted = false;
|
state.uncommitted = false;
|
||||||
|
|
||||||
if (sandbox.revision === sandbox.maxRevision + 1)
|
if (state.revision === state.maxRevision + 1)
|
||||||
throw COMMIT;
|
throw COMMIT;
|
||||||
else if (sandbox.revision > sandbox.maxRevision + 1)
|
else if (state.revision > state.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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ext() {
|
function ext() {
|
||||||
let extCall = Array.from(arguments).map(String);
|
let extCall = Array.from(arguments).map(String);
|
||||||
let key = `${sandbox.revision}: ${JSON.stringify(extCall)}`;
|
let key = `${state.revision}: ${JSON.stringify(extCall)}`;
|
||||||
|
|
||||||
if (key in sandbox.extensionsCache)
|
if (key in state.sessionContext.extensionsCache)
|
||||||
return sandbox.extensionsCache[key];
|
return state.sessionContext.extensionsCache[key];
|
||||||
|
|
||||||
sandbox.extensions[key] = extCall;
|
state.extensions[key] = extCall;
|
||||||
throw EXT;
|
throw EXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object.defineProperty(sandbox.context, 'Date', {value: SandboxDate});
|
Object.defineProperty(context, "Date", {value: SandboxDate});
|
||||||
Object.defineProperty(sandbox.context, 'declare', {value: declare});
|
Object.defineProperty(context, "declare", {value: declare});
|
||||||
Object.defineProperty(sandbox.context, 'clear', {value: clear});
|
Object.defineProperty(context, "clear", {value: clear});
|
||||||
Object.defineProperty(sandbox.context, 'commit', {value: commit});
|
Object.defineProperty(context, "commit", {value: commit});
|
||||||
Object.defineProperty(sandbox.context, 'ext', {value: ext});
|
Object.defineProperty(context, "ext", {value: ext});
|
||||||
|
|
||||||
// Monkey-patch Math.random() to make it deterministic
|
// Monkey-patch Math.random() to make it deterministic
|
||||||
sandbox.context.random = random;
|
context.random = random;
|
||||||
vm.runInContext("Math.random = random;", sandbox.context);
|
vm.runInContext("Math.random = random;", context);
|
||||||
delete sandbox.random;
|
delete context.random;
|
||||||
|
|
||||||
|
|
||||||
function errorToFault(err) {
|
function errorToFault(err) {
|
||||||
@@ -245,28 +234,27 @@ function errorToFault(err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function run(script, globals, timestamp, deviceData, extensionsCache, startRevision, maxRevision, callback) {
|
function run(script, globals, sessionContext, startRevision, maxRevision, callback) {
|
||||||
sandbox.timestamp = timestamp;
|
state = {
|
||||||
sandbox.deviceData = deviceData;
|
sessionContext: sessionContext,
|
||||||
sandbox.extensionsCache = extensionsCache;
|
revision: startRevision,
|
||||||
sandbox.revision = startRevision;
|
maxRevision: maxRevision,
|
||||||
sandbox.maxRevision = maxRevision;
|
uncommitted: false,
|
||||||
sandbox.uncommitted = false;
|
declarations: [],
|
||||||
sandbox.declarations = [];
|
extensions: {},
|
||||||
sandbox.extensions = {};
|
clear: [],
|
||||||
sandbox.clear = null;
|
rng: null
|
||||||
sandbox.rng = null;
|
};
|
||||||
|
|
||||||
for (let n in sandbox.context)
|
for (let n of Object.keys(context))
|
||||||
delete sandbox.context[n];
|
delete context[n];
|
||||||
|
|
||||||
for (let n in globals)
|
Object.assign(context, globals);
|
||||||
sandbox.context[n] = globals[n];
|
|
||||||
|
|
||||||
let ret, status;
|
let ret, status;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ret = script.runInContext(sandbox.context, {displayErrors: false});
|
ret = script.runInContext(context, {displayErrors: false});
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
@@ -278,27 +266,24 @@ function run(script, globals, timestamp, deviceData, extensionsCache, startRevis
|
|||||||
return callback(null, errorToFault(err));
|
return callback(null, errorToFault(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ext = sandbox.extensions;
|
let _state = state;
|
||||||
let decs = sandbox.declarations;
|
|
||||||
let clr = sandbox.clear;
|
|
||||||
let extCache = sandbox.extensionsCache;
|
|
||||||
let args = arguments;
|
let args = arguments;
|
||||||
|
|
||||||
let counter = 3;
|
let counter = 3;
|
||||||
for (let key in sandbox.extensions) {
|
for (let key of Object.keys(_state.extensions)) {
|
||||||
counter += 2;
|
counter += 2;
|
||||||
extensions.run(sandbox.extensions[key], function(err, fault, res) {
|
extensions.run(_state.extensions[key], function(err, fault, res) {
|
||||||
if (err || fault) {
|
if (err || fault) {
|
||||||
if (counter & 1)
|
if (counter & 1)
|
||||||
callback(err, fault);
|
callback(err, fault);
|
||||||
return counter = 0;
|
return counter = 0;
|
||||||
}
|
}
|
||||||
extCache[key] = res;
|
_state.sessionContext.extensionsCache[key] = res;
|
||||||
if ((counter -= 2) === 1)
|
if ((counter -= 2) === 1)
|
||||||
if (status === 2)
|
if (status === 2)
|
||||||
return run.apply(null, args);
|
return run.apply(null, args);
|
||||||
else
|
else
|
||||||
return callback(null, null, clr, decs, status === 0, ret);
|
return callback(null, null, _state.clear, _state.declarations, status === 0, ret);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +291,7 @@ function run(script, globals, timestamp, deviceData, extensionsCache, startRevis
|
|||||||
if (status === 2)
|
if (status === 2)
|
||||||
return run.apply(null, args);
|
return run.apply(null, args);
|
||||||
else
|
else
|
||||||
return callback(null, null, clr, decs, status === 0, ret);
|
return callback(null, null, _state.clear, _state.declarations, status === 0, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-9
@@ -348,8 +348,7 @@ runProvisions = (sessionContext, provisions, startRevision, endRevision, callbac
|
|||||||
|
|
||||||
counter += 2
|
counter += 2
|
||||||
sandbox.run(allProvisions[provision[0]].script,
|
sandbox.run(allProvisions[provision[0]].script,
|
||||||
{args: provision.slice(1)}, sessionContext.timestamp, sessionContext.deviceData,
|
{args: provision.slice(1)}, sessionContext, startRevision, endRevision,
|
||||||
sessionContext.extensionsCache, startRevision, endRevision,
|
|
||||||
(err, _fault, _clear, _declarations, _done) ->
|
(err, _fault, _clear, _declarations, _done) ->
|
||||||
if err or _fault
|
if err or _fault
|
||||||
callback(err, _fault) if counter & 1
|
callback(err, _fault) if counter & 1
|
||||||
@@ -357,10 +356,10 @@ runProvisions = (sessionContext, provisions, startRevision, endRevision, callbac
|
|||||||
|
|
||||||
done &&= _done
|
done &&= _done
|
||||||
|
|
||||||
if _declarations
|
if _declarations.length
|
||||||
allDeclarations = allDeclarations.concat(_declarations)
|
allDeclarations = allDeclarations.concat(_declarations)
|
||||||
|
|
||||||
if _clear
|
if _clear.length
|
||||||
allClear = allClear.concat(_clear)
|
allClear = allClear.concat(_clear)
|
||||||
|
|
||||||
if (counter -= 2) == 1
|
if (counter -= 2) == 1
|
||||||
@@ -382,8 +381,7 @@ runVirtualParameters = (sessionContext, provisions, startRevision, endRevision,
|
|||||||
counter += 2
|
counter += 2
|
||||||
globals = {TIMESTAMPS: provision[1], VALUES: provision[2]}
|
globals = {TIMESTAMPS: provision[1], VALUES: provision[2]}
|
||||||
sandbox.run(allVirtualParameters[provision[0]].script, globals,
|
sandbox.run(allVirtualParameters[provision[0]].script, globals,
|
||||||
sessionContext.timestamp, sessionContext.deviceData,
|
sessionContext, startRevision, endRevision,
|
||||||
sessionContext.extensionsCache, startRevision, endRevision,
|
|
||||||
(err, _fault, _clear, _declarations, _done, _returnValue) ->
|
(err, _fault, _clear, _declarations, _done, _returnValue) ->
|
||||||
if err or _fault
|
if err or _fault
|
||||||
callback(err, _fault) if counter & 1
|
callback(err, _fault) if counter & 1
|
||||||
@@ -391,10 +389,10 @@ runVirtualParameters = (sessionContext, provisions, startRevision, endRevision,
|
|||||||
|
|
||||||
done &&= _done
|
done &&= _done
|
||||||
|
|
||||||
if _declarations
|
if _declarations.length
|
||||||
allDeclarations = allDeclarations.concat(_declarations)
|
allDeclarations = allDeclarations.concat(_declarations)
|
||||||
|
|
||||||
if _clear
|
if _clear.length
|
||||||
allClear = allClear.concat(_clear)
|
allClear = allClear.concat(_clear)
|
||||||
|
|
||||||
if _done
|
if _done
|
||||||
@@ -575,7 +573,7 @@ rpcRequest = (sessionContext, _declarations, callback) ->
|
|||||||
return callback(null, fault)
|
return callback(null, fault)
|
||||||
|
|
||||||
sessionContext.declarations.push(decs)
|
sessionContext.declarations.push(decs)
|
||||||
sessionContext.doneProvisions |= 1 << inception if done or not decs.length
|
sessionContext.doneProvisions |= 1 << inception if done
|
||||||
|
|
||||||
for d in decs
|
for d in decs
|
||||||
for ad in device.getAliasDeclarations(d[0], 1)
|
for ad in device.getAliasDeclarations(d[0], 1)
|
||||||
|
|||||||
Reference in new issue
Block a user