This repository has been archived by the owner on Jul 9, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontext.ts
106 lines (90 loc) · 2.34 KB
/
context.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import { Injectable } from '@travetto/di';
import * as async_hooks from 'async_hooks';
@Injectable()
export class Context {
threads = new Map<number, number>();
storage = new Map<number, any>();
hooks: async_hooks.AsyncHook;
active = 0;
constructor() {
this.hooks = async_hooks.createHook({
before: this.enter.bind(this),
init: this.enter.bind(this),
after: this.leave.bind(this),
promiseResolve: this.leave.bind(this),
destroy: this.leave.bind(this)
});
this.run = this.run.bind(this);
}
enter(asyncId: number) {
const exAsyncId = async_hooks.executionAsyncId();
const triggerId = async_hooks.triggerAsyncId() || asyncId;
const target = this.threads.get(triggerId)! || this.threads.get(exAsyncId)!;
if (target) {
this.threads.set(asyncId, target);
}
}
leave(asyncId: number) {
const exAsyncId = async_hooks.executionAsyncId();
if (this.threads.has(asyncId)) {
this.threads.delete(asyncId);
} else if (this.threads.has(exAsyncId)) {
this.threads.delete(exAsyncId);
}
}
_storage(val: any): void;
_storage(): any;
_storage(val?: any) {
const currId = async_hooks.executionAsyncId();
const key = this.threads.get(currId)!;
if (val) {
this.storage.set(key, val);
} else {
let obj = this.storage.get(key);
if (!obj) {
obj = {};
this._storage(obj);
}
return obj;
}
}
clear() {
const obj = this._storage();
const keys = Object.keys(obj);
for (const k of keys) {
delete obj[k];
}
}
get = () => this._storage();
set = (val: any) => this._storage(val);
async run(fn: () => Promise<any>, init: any = {}) {
if (!this.active) {
this.hooks.enable();
}
// Force new context
await new Promise(r => process.nextTick(r));
const runId = async_hooks.executionAsyncId() || async_hooks.triggerAsyncId();
let val;
let err;
this.active += 1;
this.storage.set(runId, init);
this.threads.set(runId, runId);
try {
val = await fn();
} catch (e) {
require('fs').writeSync(1, e.stack);
err = e;
}
this.active -= 1;
this.storage.delete(runId);
this.threads.delete(runId);
if (!this.active) {
this.hooks.disable();
}
if (err) {
throw err;
} else {
return val;
}
}
}