UNPKG

4.59 kBJavaScriptView Raw
1"use strict";
2/**
3 * Copyright 2018 Google LLC
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17Object.defineProperty(exports, "__esModule", { value: true });
18// Original file from Stackdriver Trace Agent for Node.js
19// https://github.com/GoogleCloudPlatform/cloud-trace-nodejs
20const asyncHook = require("async_hooks");
21const shimmer = require("shimmer");
22const WRAPPED = Symbol('context_wrapped');
23/** A map of AsyncResource IDs to Context objects. */
24let contexts = new Map();
25let current = {};
26// Create the hook.
27asyncHook.createHook({ init, before, destroy }).enable();
28// A list of well-known EventEmitter methods that add event listeners.
29const EVENT_EMITTER_METHODS = [
30 'addListener',
31 'on',
32 'once',
33 'prependListener',
34 'prependOnceListener',
35];
36class AsyncHooksNamespace {
37 get name() {
38 throw new Error('Not implemented');
39 }
40 get active() {
41 return current;
42 }
43 createContext() {
44 throw new Error('Not implemented');
45 }
46 get(k) {
47 return current[k];
48 }
49 set(k, v) {
50 current[k] = v;
51 return v;
52 }
53 run(fn) {
54 this.runAndReturn(fn);
55 return current;
56 }
57 runAndReturn(fn) {
58 const oldContext = current;
59 current = {};
60 if (oldContext['current_tag_map']) {
61 current['current_tag_map'] = oldContext['current_tag_map'];
62 }
63 const res = fn();
64 current = oldContext;
65 return res;
66 }
67 bind(cb) {
68 // TODO(kjin): Monitor https://github.com/Microsoft/TypeScript/pull/15473.
69 // When it's landed and released, we can remove these `any` casts.
70 // tslint:disable-next-line:no-any
71 if (cb[WRAPPED] || !current) {
72 return cb;
73 }
74 const boundContext = current;
75 const contextWrapper = function () {
76 const oldContext = current;
77 current = boundContext;
78 const res = cb.apply(this, arguments);
79 current = oldContext;
80 return res;
81 };
82 // tslint:disable-next-line:no-any
83 contextWrapper[WRAPPED] = true;
84 Object.defineProperty(contextWrapper, 'length', {
85 enumerable: false,
86 configurable: true,
87 writable: false,
88 value: cb.length,
89 });
90 return contextWrapper;
91 }
92 // This function is not technically needed and all tests currently pass
93 // without it (after removing call sites). While it is not a complete
94 // solution, restoring correct context before running every request/response
95 // event handler reduces the number of situations in which userspace queuing
96 // will cause us to lose context.
97 bindEmitter(ee) {
98 const ns = this;
99 EVENT_EMITTER_METHODS.forEach(method => {
100 if (ee[method]) {
101 shimmer.wrap(ee, method, oldMethod => {
102 return function (event, cb) {
103 return oldMethod.call(this, event, ns.bind(cb));
104 };
105 });
106 }
107 });
108 }
109}
110const namespace = new AsyncHooksNamespace();
111// AsyncWrap Hooks
112/** init is called during object construction. */
113function init(uid, provider, parentUid, parentHandle) {
114 contexts.set(uid, current);
115}
116/** before is called just before the resource's callback is called. */
117function before(uid) {
118 const maybeCurrent = contexts.get(uid);
119 if (maybeCurrent !== undefined) {
120 current = maybeCurrent;
121 }
122}
123/**
124 * destroy is called when the object is no longer used, so also delete
125 * its entry in the map.
126 */
127function destroy(uid) {
128 contexts.delete(uid);
129}
130function createNamespace() {
131 return namespace;
132}
133exports.createNamespace = createNamespace;
134function destroyNamespace() {
135 current = {};
136 contexts = new Map();
137}
138exports.destroyNamespace = destroyNamespace;
139function getNamespace() {
140 return namespace;
141}
142exports.getNamespace = getNamespace;
143function reset() {
144 throw new Error('Not implemented');
145}
146exports.reset = reset;
147//# sourceMappingURL=cls-ah.js.map
\No newline at end of file