mirror of https://github.com/Budibase/budibase.git
77 changed files with 2892 additions and 560 deletions
@ -0,0 +1,650 @@ |
|||
const util = require("util") |
|||
const assert = require("assert") |
|||
const wrapEmitter = require("emitter-listener") |
|||
const async_hooks = require("async_hooks") |
|||
|
|||
const CONTEXTS_SYMBOL = "cls@contexts" |
|||
const ERROR_SYMBOL = "error@context" |
|||
|
|||
const DEBUG_CLS_HOOKED = process.env.DEBUG_CLS_HOOKED |
|||
|
|||
let currentUid = -1 |
|||
|
|||
module.exports = { |
|||
getNamespace: getNamespace, |
|||
createNamespace: createNamespace, |
|||
destroyNamespace: destroyNamespace, |
|||
reset: reset, |
|||
ERROR_SYMBOL: ERROR_SYMBOL, |
|||
} |
|||
|
|||
function Namespace(name) { |
|||
this.name = name |
|||
// changed in 2.7: no default context
|
|||
this.active = null |
|||
this._set = [] |
|||
this.id = null |
|||
this._contexts = new Map() |
|||
this._indent = 0 |
|||
this._hook = null |
|||
} |
|||
|
|||
Namespace.prototype.set = function set(key, value) { |
|||
if (!this.active) { |
|||
throw new Error( |
|||
"No context available. ns.run() or ns.bind() must be called first." |
|||
) |
|||
} |
|||
|
|||
this.active[key] = value |
|||
|
|||
if (DEBUG_CLS_HOOKED) { |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
indentStr + |
|||
"CONTEXT-SET KEY:" + |
|||
key + |
|||
"=" + |
|||
value + |
|||
" in ns:" + |
|||
this.name + |
|||
" currentUid:" + |
|||
currentUid + |
|||
" active:" + |
|||
util.inspect(this.active, { showHidden: true, depth: 2, colors: true }) |
|||
) |
|||
} |
|||
|
|||
return value |
|||
} |
|||
|
|||
Namespace.prototype.get = function get(key) { |
|||
if (!this.active) { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const asyncHooksCurrentId = async_hooks.currentId() |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
`${indentStr}CONTEXT-GETTING KEY NO ACTIVE NS: (${this.name}) ${key}=undefined currentUid:${currentUid} asyncHooksCurrentId:${asyncHooksCurrentId} triggerId:${triggerId} len:${this._set.length}` |
|||
) |
|||
} |
|||
return undefined |
|||
} |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const asyncHooksCurrentId = async_hooks.executionAsyncId() |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
indentStr + |
|||
"CONTEXT-GETTING KEY:" + |
|||
key + |
|||
"=" + |
|||
this.active[key] + |
|||
" (" + |
|||
this.name + |
|||
") currentUid:" + |
|||
currentUid + |
|||
" active:" + |
|||
util.inspect(this.active, { showHidden: true, depth: 2, colors: true }) |
|||
) |
|||
debug2( |
|||
`${indentStr}CONTEXT-GETTING KEY: (${this.name}) ${key}=${ |
|||
this.active[key] |
|||
} currentUid:${currentUid} asyncHooksCurrentId:${asyncHooksCurrentId} triggerId:${triggerId} len:${ |
|||
this._set.length |
|||
} active:${util.inspect(this.active)}` |
|||
) |
|||
} |
|||
return this.active[key] |
|||
} |
|||
|
|||
Namespace.prototype.createContext = function createContext() { |
|||
// Prototype inherit existing context if created a new child context within existing context.
|
|||
let context = Object.create(this.active ? this.active : Object.prototype) |
|||
context._ns_name = this.name |
|||
context.id = currentUid |
|||
|
|||
if (DEBUG_CLS_HOOKED) { |
|||
const asyncHooksCurrentId = async_hooks.executionAsyncId() |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
`${indentStr}CONTEXT-CREATED Context: (${ |
|||
this.name |
|||
}) currentUid:${currentUid} asyncHooksCurrentId:${asyncHooksCurrentId} triggerId:${triggerId} len:${ |
|||
this._set.length |
|||
} context:${util.inspect(context, { |
|||
showHidden: true, |
|||
depth: 2, |
|||
colors: true, |
|||
})}` |
|||
) |
|||
} |
|||
|
|||
return context |
|||
} |
|||
|
|||
Namespace.prototype.run = function run(fn) { |
|||
let context = this.createContext() |
|||
this.enter(context) |
|||
|
|||
try { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const asyncHooksCurrentId = async_hooks.executionAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
`${indentStr}CONTEXT-RUN BEGIN: (${ |
|||
this.name |
|||
}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${ |
|||
this._set.length |
|||
} context:${util.inspect(context)}` |
|||
) |
|||
} |
|||
fn(context) |
|||
return context |
|||
} catch (exception) { |
|||
if (exception) { |
|||
exception[ERROR_SYMBOL] = context |
|||
} |
|||
throw exception |
|||
} finally { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const asyncHooksCurrentId = async_hooks.executionAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
`${indentStr}CONTEXT-RUN END: (${ |
|||
this.name |
|||
}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${ |
|||
this._set.length |
|||
} ${util.inspect(context)}` |
|||
) |
|||
} |
|||
this.exit(context) |
|||
} |
|||
} |
|||
|
|||
Namespace.prototype.runAndReturn = function runAndReturn(fn) { |
|||
let value |
|||
this.run(function (context) { |
|||
value = fn(context) |
|||
}) |
|||
return value |
|||
} |
|||
|
|||
/** |
|||
* Uses global Promise and assumes Promise is cls friendly or wrapped already. |
|||
* @param {function} fn |
|||
* @returns {*} |
|||
*/ |
|||
Namespace.prototype.runPromise = function runPromise(fn) { |
|||
let context = this.createContext() |
|||
this.enter(context) |
|||
|
|||
let promise = fn(context) |
|||
if (!promise || !promise.then || !promise.catch) { |
|||
throw new Error("fn must return a promise.") |
|||
} |
|||
|
|||
if (DEBUG_CLS_HOOKED) { |
|||
debug2( |
|||
"CONTEXT-runPromise BEFORE: (" + |
|||
this.name + |
|||
") currentUid:" + |
|||
currentUid + |
|||
" len:" + |
|||
this._set.length + |
|||
" " + |
|||
util.inspect(context) |
|||
) |
|||
} |
|||
|
|||
return promise |
|||
.then(result => { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
debug2( |
|||
"CONTEXT-runPromise AFTER then: (" + |
|||
this.name + |
|||
") currentUid:" + |
|||
currentUid + |
|||
" len:" + |
|||
this._set.length + |
|||
" " + |
|||
util.inspect(context) |
|||
) |
|||
} |
|||
this.exit(context) |
|||
return result |
|||
}) |
|||
.catch(err => { |
|||
err[ERROR_SYMBOL] = context |
|||
if (DEBUG_CLS_HOOKED) { |
|||
debug2( |
|||
"CONTEXT-runPromise AFTER catch: (" + |
|||
this.name + |
|||
") currentUid:" + |
|||
currentUid + |
|||
" len:" + |
|||
this._set.length + |
|||
" " + |
|||
util.inspect(context) |
|||
) |
|||
} |
|||
this.exit(context) |
|||
throw err |
|||
}) |
|||
} |
|||
|
|||
Namespace.prototype.bind = function bindFactory(fn, context) { |
|||
if (!context) { |
|||
if (!this.active) { |
|||
context = this.createContext() |
|||
} else { |
|||
context = this.active |
|||
} |
|||
} |
|||
|
|||
let self = this |
|||
return function clsBind() { |
|||
self.enter(context) |
|||
try { |
|||
return fn.apply(this, arguments) |
|||
} catch (exception) { |
|||
if (exception) { |
|||
exception[ERROR_SYMBOL] = context |
|||
} |
|||
throw exception |
|||
} finally { |
|||
self.exit(context) |
|||
} |
|||
} |
|||
} |
|||
|
|||
Namespace.prototype.enter = function enter(context) { |
|||
assert.ok(context, "context must be provided for entering") |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const asyncHooksCurrentId = async_hooks.executionAsyncId() |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
`${indentStr}CONTEXT-ENTER: (${ |
|||
this.name |
|||
}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${ |
|||
this._set.length |
|||
} ${util.inspect(context)}` |
|||
) |
|||
} |
|||
|
|||
this._set.push(this.active) |
|||
this.active = context |
|||
} |
|||
|
|||
Namespace.prototype.exit = function exit(context) { |
|||
assert.ok(context, "context must be provided for exiting") |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const asyncHooksCurrentId = async_hooks.executionAsyncId() |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat(this._indent < 0 ? 0 : this._indent) |
|||
debug2( |
|||
`${indentStr}CONTEXT-EXIT: (${ |
|||
this.name |
|||
}) currentUid:${currentUid} triggerId:${triggerId} asyncHooksCurrentId:${asyncHooksCurrentId} len:${ |
|||
this._set.length |
|||
} ${util.inspect(context)}` |
|||
) |
|||
} |
|||
|
|||
// Fast path for most exits that are at the top of the stack
|
|||
if (this.active === context) { |
|||
assert.ok(this._set.length, "can't remove top context") |
|||
this.active = this._set.pop() |
|||
return |
|||
} |
|||
|
|||
// Fast search in the stack using lastIndexOf
|
|||
let index = this._set.lastIndexOf(context) |
|||
|
|||
if (index < 0) { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
debug2( |
|||
"??ERROR?? context exiting but not entered - ignoring: " + |
|||
util.inspect(context) |
|||
) |
|||
} |
|||
assert.ok( |
|||
index >= 0, |
|||
"context not currently entered; can't exit. \n" + |
|||
util.inspect(this) + |
|||
"\n" + |
|||
util.inspect(context) |
|||
) |
|||
} else { |
|||
assert.ok(index, "can't remove top context") |
|||
this._set.splice(index, 1) |
|||
} |
|||
} |
|||
|
|||
Namespace.prototype.bindEmitter = function bindEmitter(emitter) { |
|||
assert.ok( |
|||
emitter.on && emitter.addListener && emitter.emit, |
|||
"can only bind real EEs" |
|||
) |
|||
|
|||
let namespace = this |
|||
let thisSymbol = "context@" + this.name |
|||
|
|||
// Capture the context active at the time the emitter is bound.
|
|||
function attach(listener) { |
|||
if (!listener) { |
|||
return |
|||
} |
|||
if (!listener[CONTEXTS_SYMBOL]) { |
|||
listener[CONTEXTS_SYMBOL] = Object.create(null) |
|||
} |
|||
|
|||
listener[CONTEXTS_SYMBOL][thisSymbol] = { |
|||
namespace: namespace, |
|||
context: namespace.active, |
|||
} |
|||
} |
|||
|
|||
// At emit time, bind the listener within the correct context.
|
|||
function bind(unwrapped) { |
|||
if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) { |
|||
return unwrapped |
|||
} |
|||
|
|||
let wrapped = unwrapped |
|||
let unwrappedContexts = unwrapped[CONTEXTS_SYMBOL] |
|||
Object.keys(unwrappedContexts).forEach(function (name) { |
|||
let thunk = unwrappedContexts[name] |
|||
wrapped = thunk.namespace.bind(wrapped, thunk.context) |
|||
}) |
|||
return wrapped |
|||
} |
|||
|
|||
wrapEmitter(emitter, attach, bind) |
|||
} |
|||
|
|||
/** |
|||
* If an error comes out of a namespace, it will have a context attached to it. |
|||
* This function knows how to find it. |
|||
* |
|||
* @param {Error} exception Possibly annotated error. |
|||
*/ |
|||
Namespace.prototype.fromException = function fromException(exception) { |
|||
return exception[ERROR_SYMBOL] |
|||
} |
|||
|
|||
function getNamespace(name) { |
|||
return process.namespaces[name] |
|||
} |
|||
|
|||
function createNamespace(name) { |
|||
assert.ok(name, "namespace must be given a name.") |
|||
|
|||
if (DEBUG_CLS_HOOKED) { |
|||
debug2(`NS-CREATING NAMESPACE (${name})`) |
|||
} |
|||
let namespace = new Namespace(name) |
|||
namespace.id = currentUid |
|||
|
|||
const hook = async_hooks.createHook({ |
|||
init(asyncId, type, triggerId, resource) { |
|||
currentUid = async_hooks.executionAsyncId() |
|||
|
|||
//CHAIN Parent's Context onto child if none exists. This is needed to pass net-events.spec
|
|||
// let initContext = namespace.active;
|
|||
// if(!initContext && triggerId) {
|
|||
// let parentContext = namespace._contexts.get(triggerId);
|
|||
// if (parentContext) {
|
|||
// namespace.active = parentContext;
|
|||
// namespace._contexts.set(currentUid, parentContext);
|
|||
// if (DEBUG_CLS_HOOKED) {
|
|||
// const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
|
|||
// debug2(`${indentStr}INIT [${type}] (${name}) WITH PARENT CONTEXT asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, true)} resource:${resource}`);
|
|||
// }
|
|||
// } else if (DEBUG_CLS_HOOKED) {
|
|||
// const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
|
|||
// debug2(`${indentStr}INIT [${type}] (${name}) MISSING CONTEXT asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, true)} resource:${resource}`);
|
|||
// }
|
|||
// }else {
|
|||
// namespace._contexts.set(currentUid, namespace.active);
|
|||
// if (DEBUG_CLS_HOOKED) {
|
|||
// const indentStr = ' '.repeat(namespace._indent < 0 ? 0 : namespace._indent);
|
|||
// debug2(`${indentStr}INIT [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect(namespace.active, true)} resource:${resource}`);
|
|||
// }
|
|||
// }
|
|||
if (namespace.active) { |
|||
namespace._contexts.set(asyncId, namespace.active) |
|||
|
|||
if (DEBUG_CLS_HOOKED) { |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}INIT [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} resource:${resource}` |
|||
) |
|||
} |
|||
} else if (currentUid === 0) { |
|||
// CurrentId will be 0 when triggered from C++. Promise events
|
|||
// https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md#triggerid
|
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const triggerIdContext = namespace._contexts.get(triggerId) |
|||
if (triggerIdContext) { |
|||
namespace._contexts.set(asyncId, triggerIdContext) |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}INIT USING CONTEXT FROM TRIGGERID [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} resource:${resource}` |
|||
) |
|||
} |
|||
} else if (DEBUG_CLS_HOOKED) { |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}INIT MISSING CONTEXT [${type}] (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} resource:${resource}` |
|||
) |
|||
} |
|||
} |
|||
|
|||
if (DEBUG_CLS_HOOKED && type === "PROMISE") { |
|||
debug2(util.inspect(resource, { showHidden: true })) |
|||
const parentId = resource.parentId |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}INIT RESOURCE-PROMISE [${type}] (${name}) parentId:${parentId} asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} resource:${resource}` |
|||
) |
|||
} |
|||
}, |
|||
before(asyncId) { |
|||
currentUid = async_hooks.executionAsyncId() |
|||
let context |
|||
|
|||
/* |
|||
if(currentUid === 0){ |
|||
// CurrentId will be 0 when triggered from C++. Promise events
|
|||
// https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md#triggerid
|
|||
//const triggerId = async_hooks.triggerAsyncId();
|
|||
context = namespace._contexts.get(asyncId); // || namespace._contexts.get(triggerId);
|
|||
}else{ |
|||
context = namespace._contexts.get(currentUid); |
|||
} |
|||
*/ |
|||
|
|||
//HACK to work with promises until they are fixed in node > 8.1.1
|
|||
context = |
|||
namespace._contexts.get(asyncId) || namespace._contexts.get(currentUid) |
|||
|
|||
if (context) { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}BEFORE (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} context:${util.inspect(context)}` |
|||
) |
|||
namespace._indent += 2 |
|||
} |
|||
|
|||
namespace.enter(context) |
|||
} else if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}BEFORE MISSING CONTEXT (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} namespace._contexts:${util.inspect(namespace._contexts, { |
|||
showHidden: true, |
|||
depth: 2, |
|||
colors: true, |
|||
})}` |
|||
) |
|||
namespace._indent += 2 |
|||
} |
|||
}, |
|||
after(asyncId) { |
|||
currentUid = async_hooks.executionAsyncId() |
|||
let context // = namespace._contexts.get(currentUid);
|
|||
/* |
|||
if(currentUid === 0){ |
|||
// CurrentId will be 0 when triggered from C++. Promise events
|
|||
// https://github.com/nodejs/node/blob/master/doc/api/async_hooks.md#triggerid
|
|||
//const triggerId = async_hooks.triggerAsyncId();
|
|||
context = namespace._contexts.get(asyncId); // || namespace._contexts.get(triggerId);
|
|||
}else{ |
|||
context = namespace._contexts.get(currentUid); |
|||
} |
|||
*/ |
|||
//HACK to work with promises until they are fixed in node > 8.1.1
|
|||
context = |
|||
namespace._contexts.get(asyncId) || namespace._contexts.get(currentUid) |
|||
|
|||
if (context) { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
namespace._indent -= 2 |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}AFTER (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} context:${util.inspect(context)}` |
|||
) |
|||
} |
|||
|
|||
namespace.exit(context) |
|||
} else if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
namespace._indent -= 2 |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}AFTER MISSING CONTEXT (${name}) asyncId:${asyncId} currentUid:${currentUid} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} context:${util.inspect(context)}` |
|||
) |
|||
} |
|||
}, |
|||
destroy(asyncId) { |
|||
currentUid = async_hooks.executionAsyncId() |
|||
if (DEBUG_CLS_HOOKED) { |
|||
const triggerId = async_hooks.triggerAsyncId() |
|||
const indentStr = " ".repeat( |
|||
namespace._indent < 0 ? 0 : namespace._indent |
|||
) |
|||
debug2( |
|||
`${indentStr}DESTROY (${name}) currentUid:${currentUid} asyncId:${asyncId} triggerId:${triggerId} active:${util.inspect( |
|||
namespace.active, |
|||
{ showHidden: true, depth: 2, colors: true } |
|||
)} context:${util.inspect(namespace._contexts.get(currentUid))}` |
|||
) |
|||
} |
|||
|
|||
namespace._contexts.delete(asyncId) |
|||
}, |
|||
}) |
|||
|
|||
hook.enable() |
|||
namespace._hook = hook |
|||
|
|||
process.namespaces[name] = namespace |
|||
return namespace |
|||
} |
|||
|
|||
function destroyNamespace(name) { |
|||
let namespace = getNamespace(name) |
|||
|
|||
assert.ok(namespace, "can't delete nonexistent namespace! \"" + name + '"') |
|||
assert.ok( |
|||
namespace.id, |
|||
"don't assign to process.namespaces directly! " + util.inspect(namespace) |
|||
) |
|||
|
|||
namespace._hook.disable() |
|||
namespace._contexts = null |
|||
process.namespaces[name] = null |
|||
} |
|||
|
|||
function reset() { |
|||
// must unregister async listeners
|
|||
if (process.namespaces) { |
|||
Object.keys(process.namespaces).forEach(function (name) { |
|||
destroyNamespace(name) |
|||
}) |
|||
} |
|||
process.namespaces = Object.create(null) |
|||
} |
|||
|
|||
process.namespaces = process.namespaces || {} |
|||
|
|||
//const fs = require('fs');
|
|||
function debug2(...args) { |
|||
if (DEBUG_CLS_HOOKED) { |
|||
//fs.writeSync(1, `${util.format(...args)}\n`);
|
|||
process._rawDebug(`${util.format(...args)}`) |
|||
} |
|||
} |
|||
|
|||
/*function getFunctionName(fn) { |
|||
if (!fn) { |
|||
return fn; |
|||
} |
|||
if (typeof fn === 'function') { |
|||
if (fn.name) { |
|||
return fn.name; |
|||
} |
|||
return (fn.toString().trim().match(/^function\s*([^\s(]+)/) || [])[1]; |
|||
} else if (fn.constructor && fn.constructor.name) { |
|||
return fn.constructor.name; |
|||
} |
|||
}*/ |
|||
@ -1,84 +1,47 @@ |
|||
const cls = require("cls-hooked") |
|||
const cls = require("../clshooked") |
|||
const { newid } = require("../hashing") |
|||
|
|||
const REQUEST_ID_KEY = "requestId" |
|||
|
|||
class FunctionContext { |
|||
static getMiddleware( |
|||
updateCtxFn = null, |
|||
destroyFn = null, |
|||
contextName = "session" |
|||
) { |
|||
const namespace = this.createNamespace(contextName) |
|||
|
|||
return async function (ctx, next) { |
|||
await new Promise( |
|||
namespace.bind(function (resolve, reject) { |
|||
// store a contextual request ID that can be used anywhere (audit logs)
|
|||
namespace.set(REQUEST_ID_KEY, newid()) |
|||
namespace.bindEmitter(ctx.req) |
|||
namespace.bindEmitter(ctx.res) |
|||
|
|||
if (updateCtxFn) { |
|||
updateCtxFn(ctx) |
|||
} |
|||
next() |
|||
.then(resolve) |
|||
.catch(reject) |
|||
.finally(() => { |
|||
if (destroyFn) { |
|||
return destroyFn(ctx) |
|||
} |
|||
}) |
|||
}) |
|||
) |
|||
} |
|||
const MAIN_CTX = cls.createNamespace("main") |
|||
|
|||
function getContextStorage(namespace) { |
|||
if (namespace && namespace.active) { |
|||
let contextData = namespace.active |
|||
delete contextData.id |
|||
delete contextData._ns_name |
|||
return contextData |
|||
} |
|||
return {} |
|||
} |
|||
|
|||
static run(callback, contextName = "session") { |
|||
const namespace = this.createNamespace(contextName) |
|||
|
|||
return namespace.runAndReturn(callback) |
|||
class FunctionContext { |
|||
static run(callback) { |
|||
return MAIN_CTX.runAndReturn(async () => { |
|||
const namespaceId = newid() |
|||
MAIN_CTX.set(REQUEST_ID_KEY, namespaceId) |
|||
const namespace = cls.createNamespace(namespaceId) |
|||
let response = await namespace.runAndReturn(callback) |
|||
cls.destroyNamespace(namespaceId) |
|||
return response |
|||
}) |
|||
} |
|||
|
|||
static setOnContext(key, value, contextName = "session") { |
|||
const namespace = this.createNamespace(contextName) |
|||
static setOnContext(key, value) { |
|||
const namespaceId = MAIN_CTX.get(REQUEST_ID_KEY) |
|||
const namespace = cls.getNamespace(namespaceId) |
|||
namespace.set(key, value) |
|||
} |
|||
|
|||
static getContextStorage() { |
|||
if (this._namespace && this._namespace.active) { |
|||
let contextData = this._namespace.active |
|||
delete contextData.id |
|||
delete contextData._ns_name |
|||
return contextData |
|||
} |
|||
|
|||
return {} |
|||
} |
|||
|
|||
static getFromContext(key) { |
|||
const context = this.getContextStorage() |
|||
const namespaceId = MAIN_CTX.get(REQUEST_ID_KEY) |
|||
const namespace = cls.getNamespace(namespaceId) |
|||
const context = getContextStorage(namespace) |
|||
if (context) { |
|||
return context[key] |
|||
} else { |
|||
return null |
|||
} |
|||
} |
|||
|
|||
static destroyNamespace(name = "session") { |
|||
if (this._namespace) { |
|||
cls.destroyNamespace(name) |
|||
this._namespace = null |
|||
} |
|||
} |
|||
|
|||
static createNamespace(name = "session") { |
|||
if (!this._namespace) { |
|||
this._namespace = cls.createNamespace(name) |
|||
} |
|||
return this._namespace |
|||
} |
|||
} |
|||
|
|||
module.exports = FunctionContext |
|||
|
|||
@ -0,0 +1,68 @@ |
|||
<script> |
|||
import "@spectrum-css/fieldgroup/dist/index-vars.css" |
|||
import "@spectrum-css/radio/dist/index-vars.css" |
|||
import { createEventDispatcher } from "svelte" |
|||
|
|||
export let direction = "vertical" |
|||
export let value = [] |
|||
export let options = [] |
|||
export let error = null |
|||
export let disabled = false |
|||
export let getOptionLabel = option => option |
|||
export let getOptionValue = option => option |
|||
|
|||
const dispatch = createEventDispatcher() |
|||
const onChange = e => { |
|||
let tempValue = value |
|||
let isChecked = e.target.checked |
|||
if (!tempValue.includes(e.target.value) && isChecked) { |
|||
tempValue.push(e.target.value) |
|||
} |
|||
value = tempValue |
|||
dispatch( |
|||
"change", |
|||
tempValue.filter(val => val !== e.target.value || isChecked) |
|||
) |
|||
} |
|||
</script> |
|||
|
|||
<div class={`spectrum-FieldGroup spectrum-FieldGroup--${direction}`}> |
|||
{#if options && Array.isArray(options)} |
|||
{#each options as option} |
|||
<div |
|||
title={getOptionLabel(option)} |
|||
class="spectrum-Checkbox spectrum-FieldGroup-item" |
|||
class:is-invalid={!!error} |
|||
> |
|||
<label |
|||
class="spectrum-Checkbox spectrum-Checkbox--sizeM spectrum-FieldGroup-item" |
|||
> |
|||
<input |
|||
on:change={onChange} |
|||
value={getOptionValue(option)} |
|||
type="checkbox" |
|||
class="spectrum-Checkbox-input" |
|||
{disabled} |
|||
checked={value.includes(getOptionValue(option))} |
|||
/> |
|||
<span class="spectrum-Checkbox-box"> |
|||
<svg |
|||
class="spectrum-Icon spectrum-UIIcon-Checkmark100 spectrum-Checkbox-checkmark" |
|||
focusable="false" |
|||
aria-hidden="true" |
|||
> |
|||
<use xlink:href="#spectrum-css-icon-Checkmark100" /> |
|||
</svg> |
|||
</span> |
|||
<span class="spectrum-Checkbox-label">{getOptionLabel(option)}</span> |
|||
</label> |
|||
</div> |
|||
{/each} |
|||
{/if} |
|||
</div> |
|||
|
|||
<style> |
|||
.spectrum-Checkbox-input { |
|||
opacity: 0; |
|||
} |
|||
</style> |
|||
@ -1,11 +1,15 @@ |
|||
{ |
|||
"baseUrl": "http://localhost:4100", |
|||
"video": false, |
|||
"video": true, |
|||
"projectId": "bmbemn", |
|||
"env": { |
|||
"PORT": "4100", |
|||
"WORKER_PORT": "4200", |
|||
"JWT_SECRET": "test", |
|||
"HOST_IP": "" |
|||
}, |
|||
"retries": { |
|||
"runMode": 2, |
|||
"openMode": 0 |
|||
} |
|||
} |
|||
|
|||
File diff suppressed because one or more lines are too long
@ -0,0 +1,13 @@ |
|||
// createApp test
|
|||
export const CREATE_APP_BUTTON = '[data-cy="create-app-btn"]' |
|||
export const TEMPLATE_CATEGORY_FILTER = ".template-category-filters" |
|||
export const TEMPLATE_CATEGORY = ".template-categories" |
|||
export const APP_TABLE = ".appTable" |
|||
export const SPECTRUM_BUTTON_TEMPLATE = ".spectrum-Button" |
|||
export const TEMPLATE_CATEGORY_ACTIONGROUP = ".template-category" |
|||
export const TEMPLATE_CATEGORY_FILTER_ACTIONBUTTON = |
|||
".template-category-filters .spectrum-ActionButton" |
|||
export const SPECTRUM_MODAL = ".spectrum-Modal" |
|||
export const APP_NAME_INPUT = "input" // we need to update this with atribute cy-data
|
|||
export const SPECTRUM_BUTTON_GROUP = ".spectrum-ButtonGroup" |
|||
export const SPECTRUM_MODAL_INPUT = ".spectrum-Modal input" |
|||
File diff suppressed because it is too large
Loading…
Reference in new issue