-
-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathwatcherService.js
More file actions
118 lines (98 loc) · 2.48 KB
/
watcherService.js
File metadata and controls
118 lines (98 loc) · 2.48 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
'use strict'
const { executionAsyncId, createHook, AsyncResource } = require('node:async_hooks')
const { EventEmitter } = require('node:events')
class CustomResource extends AsyncResource {
constructor (type, traceId) {
super(type)
this.traceId = traceId
}
}
class AsyncWatcher extends EventEmitter {
setupInitHook () {
// init is called during object construction. The resource may not have
// completed construction when this callback runs, therefore all fields of the
// resource referenced by "asyncId" may not have been populated.
this.init = (asyncId, type, triggerAsyncId, resource) => {
this.emit('INIT', {
asyncId,
type,
triggerAsyncId,
executionAsyncId: executionAsyncId(),
resource,
})
}
return this
}
setupDestroyHook () {
// Destroy is called when an AsyncWrap instance is destroyed.
this.destroy = (asyncId) => {
this.emit('DESTROY', {
asyncId,
executionAsyncId: executionAsyncId(),
})
}
return this
}
start () {
createHook({
init: this.init.bind(this),
destroy: this.destroy.bind(this),
}).enable()
return this
}
}
class AsyncHookContainer {
constructor (types) {
const checkedTypes = types
const idMap = new Map()
const resourceMap = new Map()
const watcher = new AsyncWatcher()
const check = (t) => {
try {
return checkedTypes.includes(t)
} catch {
return false
}
}
watcher
.setupInitHook()
.setupDestroyHook()
.start()
.on('INIT', ({ asyncId, type, resource, triggerAsyncId }) => {
idMap.set(asyncId, triggerAsyncId)
if (check(type)) {
resourceMap.set(asyncId, resource)
}
})
.on('DESTROY', ({ asyncId }) => {
idMap.delete(asyncId)
resourceMap.delete(asyncId)
})
this.types = checkedTypes
this.idMap = idMap
this.resourceMap = resourceMap
this.watcher = watcher
}
getStore (asyncId) {
let resource = this.resourceMap.get(asyncId)
if (resource != null) {
return resource
}
let id = this.idMap.get(asyncId)
let sentinel = 0
while (id != null && sentinel < 100) {
resource = this.resourceMap.get(id)
if (resource != null) {
return resource
}
id = this.idMap.get(id)
sentinel += 1
}
return undefined
}
}
module.exports = {
AsyncWatcher,
AsyncHookContainer,
CustomResource,
}