prool 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/_lib/instance.d.ts +5 -2
- package/_lib/instance.d.ts.map +1 -1
- package/_lib/instance.js +19 -1
- package/_lib/instance.js.map +1 -1
- package/_lib/pool.d.ts +1 -0
- package/_lib/pool.d.ts.map +1 -1
- package/_lib/pool.js +55 -51
- package/_lib/pool.js.map +1 -1
- package/_lib/server.d.ts.map +1 -1
- package/_lib/server.js +42 -34
- package/_lib/server.js.map +1 -1
- package/instance.test.ts +32 -0
- package/instance.ts +31 -3
- package/package.json +1 -1
- package/pool.test.ts +41 -0
- package/pool.ts +66 -58
- package/server.test.ts +101 -18
- package/server.ts +42 -34
- package/tsconfig.build.tsbuildinfo +1 -1
package/pool.ts
CHANGED
|
@@ -13,6 +13,7 @@ export type Pool<key = number> = Pick<
|
|
|
13
13
|
}
|
|
14
14
|
destroy(key: key): Promise<void>
|
|
15
15
|
destroyAll(): Promise<void>
|
|
16
|
+
restart(key: key): Promise<void>
|
|
16
17
|
start(key: key, options?: { port?: number }): Promise<Instance_>
|
|
17
18
|
stop(key: key): Promise<void>
|
|
18
19
|
stopAll(): Promise<void>
|
|
@@ -56,6 +57,7 @@ export function definePool<key = number>(
|
|
|
56
57
|
const promises = {
|
|
57
58
|
destroy: new Map<key, Promise<void>>(),
|
|
58
59
|
destroyAll: undefined as Promise<void> | undefined,
|
|
60
|
+
restart: new Map<key, Promise<void>>(),
|
|
59
61
|
start: new Map<key, Promise<Instance_>>(),
|
|
60
62
|
stop: new Map<key, Promise<void>>(),
|
|
61
63
|
stopAll: undefined as Promise<void> | undefined,
|
|
@@ -71,16 +73,14 @@ export function definePool<key = number>(
|
|
|
71
73
|
|
|
72
74
|
const resolver = Promise.withResolvers<void>()
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
promises.destroy.set(key, resolver.promise)
|
|
76
|
+
promises.destroy.set(key, resolver.promise)
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
resolver.reject
|
|
83
|
-
}
|
|
78
|
+
this.stop(key)
|
|
79
|
+
.then(() => {
|
|
80
|
+
instances.delete(key)
|
|
81
|
+
resolver.resolve()
|
|
82
|
+
})
|
|
83
|
+
.catch(resolver.reject)
|
|
84
84
|
|
|
85
85
|
return resolver.promise
|
|
86
86
|
},
|
|
@@ -89,17 +89,35 @@ export function definePool<key = number>(
|
|
|
89
89
|
|
|
90
90
|
const resolver = Promise.withResolvers<void>()
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
promises.destroyAll = resolver.promise
|
|
92
|
+
promises.destroyAll = resolver.promise
|
|
94
93
|
|
|
95
|
-
|
|
94
|
+
Promise.all([...instances.keys()].map((key) => this.destroy(key)))
|
|
95
|
+
.then(() => {
|
|
96
|
+
promises.destroyAll = undefined
|
|
97
|
+
resolver.resolve()
|
|
98
|
+
})
|
|
99
|
+
.catch(resolver.reject)
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
return resolver.promise
|
|
102
|
+
},
|
|
103
|
+
async restart(key) {
|
|
104
|
+
const restartPromise = promises.restart.get(key)
|
|
105
|
+
if (restartPromise) return restartPromise
|
|
98
106
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
107
|
+
const resolver = Promise.withResolvers<void>()
|
|
108
|
+
|
|
109
|
+
const instance_ = instances.get(key)
|
|
110
|
+
if (!instance_) return
|
|
111
|
+
|
|
112
|
+
promises.restart.set(key, resolver.promise)
|
|
113
|
+
|
|
114
|
+
instance_
|
|
115
|
+
.restart()
|
|
116
|
+
.then(resolver.resolve)
|
|
117
|
+
.catch(resolver.reject)
|
|
118
|
+
.finally(() => promises.restart.delete(key))
|
|
119
|
+
|
|
120
|
+
return resolver.promise
|
|
103
121
|
},
|
|
104
122
|
async start(key, options = {}) {
|
|
105
123
|
const startPromise = promises.start.get(key)
|
|
@@ -107,24 +125,21 @@ export function definePool<key = number>(
|
|
|
107
125
|
|
|
108
126
|
const resolver = Promise.withResolvers<Instance_>()
|
|
109
127
|
|
|
110
|
-
|
|
111
|
-
|
|
128
|
+
if (limit && instances.size >= limit)
|
|
129
|
+
throw new Error(`Instance limit of ${limit} reached.`)
|
|
112
130
|
|
|
113
|
-
|
|
114
|
-
throw new Error(`Instance limit of ${limit} reached.`)
|
|
131
|
+
promises.start.set(key, resolver.promise)
|
|
115
132
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
resolver.reject
|
|
125
|
-
|
|
126
|
-
promises.start.delete(key)
|
|
127
|
-
}
|
|
133
|
+
const { port = await getPort() } = options
|
|
134
|
+
const instance_ = instances.get(key) || instance.create({ port })
|
|
135
|
+
instance_
|
|
136
|
+
.start()
|
|
137
|
+
.then(() => {
|
|
138
|
+
instances.set(key, instance_)
|
|
139
|
+
resolver.resolve(instance_)
|
|
140
|
+
})
|
|
141
|
+
.catch(resolver.reject)
|
|
142
|
+
.finally(() => promises.start.delete(key))
|
|
128
143
|
|
|
129
144
|
return resolver.promise
|
|
130
145
|
},
|
|
@@ -132,42 +147,35 @@ export function definePool<key = number>(
|
|
|
132
147
|
const stopPromise = promises.stop.get(key)
|
|
133
148
|
if (stopPromise) return stopPromise
|
|
134
149
|
|
|
135
|
-
const
|
|
150
|
+
const instance_ = instances.get(key)
|
|
151
|
+
if (!instance_) return
|
|
136
152
|
|
|
137
|
-
|
|
138
|
-
promises.stop.set(key, resolver.promise)
|
|
139
|
-
|
|
140
|
-
const instance_ = instances.get(key)
|
|
141
|
-
if (!instance_) {
|
|
142
|
-
resolver.resolve()
|
|
143
|
-
return
|
|
144
|
-
}
|
|
153
|
+
const resolver = Promise.withResolvers<void>()
|
|
145
154
|
|
|
146
|
-
|
|
155
|
+
promises.stop.set(key, resolver.promise)
|
|
156
|
+
instance_
|
|
157
|
+
.stop()
|
|
158
|
+
.then(resolver.resolve)
|
|
159
|
+
.catch(resolver.reject)
|
|
160
|
+
.finally(() => promises.stop.delete(key))
|
|
147
161
|
|
|
148
|
-
|
|
149
|
-
} catch (error) {
|
|
150
|
-
resolver.reject(error)
|
|
151
|
-
} finally {
|
|
152
|
-
promises.stop.delete(key)
|
|
153
|
-
}
|
|
162
|
+
return resolver.promise
|
|
154
163
|
},
|
|
155
164
|
async stopAll() {
|
|
156
165
|
if (promises.stopAll) return promises.stopAll
|
|
157
166
|
|
|
158
167
|
const resolver = Promise.withResolvers<void>()
|
|
159
168
|
|
|
160
|
-
|
|
161
|
-
promises.stopAll = resolver.promise
|
|
162
|
-
|
|
163
|
-
await Promise.all([...instances.keys()].map((key) => this.stop(key)))
|
|
169
|
+
promises.stopAll = resolver.promise
|
|
164
170
|
|
|
165
|
-
|
|
171
|
+
Promise.all([...instances.keys()].map((key) => this.stop(key)))
|
|
172
|
+
.then(() => {
|
|
173
|
+
promises.stopAll = undefined
|
|
174
|
+
resolver.resolve()
|
|
175
|
+
})
|
|
176
|
+
.catch(resolver.reject)
|
|
166
177
|
|
|
167
|
-
|
|
168
|
-
} catch (error) {
|
|
169
|
-
resolver.reject(error)
|
|
170
|
-
}
|
|
178
|
+
return resolver.promise
|
|
171
179
|
},
|
|
172
180
|
|
|
173
181
|
get size() {
|
package/server.test.ts
CHANGED
|
@@ -7,49 +7,49 @@ describe.each([{ instance: anvil() }])(
|
|
|
7
7
|
'instance: $instance.name',
|
|
8
8
|
({ instance }) => {
|
|
9
9
|
test('default', async () => {
|
|
10
|
-
const
|
|
10
|
+
const server = createServer({
|
|
11
11
|
instance,
|
|
12
12
|
})
|
|
13
|
-
expect(
|
|
13
|
+
expect(server).toBeDefined()
|
|
14
14
|
|
|
15
|
-
await
|
|
16
|
-
expect(
|
|
15
|
+
await server.start()
|
|
16
|
+
expect(server.address()).toBeDefined()
|
|
17
17
|
|
|
18
18
|
// Stop via instance method.
|
|
19
|
-
await
|
|
20
|
-
expect(
|
|
19
|
+
await server.stop()
|
|
20
|
+
expect(server.address()).toBeNull()
|
|
21
21
|
|
|
22
|
-
const stop = await
|
|
23
|
-
expect(
|
|
22
|
+
const stop = await server.start()
|
|
23
|
+
expect(server.address()).toBeDefined()
|
|
24
24
|
|
|
25
25
|
// Stop via return value.
|
|
26
26
|
await stop()
|
|
27
|
-
expect(
|
|
27
|
+
expect(server.address()).toBeNull()
|
|
28
28
|
})
|
|
29
29
|
|
|
30
30
|
test('args: port', async () => {
|
|
31
|
-
const
|
|
31
|
+
const server = createServer({
|
|
32
32
|
instance,
|
|
33
33
|
port: 3000,
|
|
34
34
|
})
|
|
35
|
-
expect(
|
|
35
|
+
expect(server).toBeDefined()
|
|
36
36
|
|
|
37
|
-
const stop = await
|
|
38
|
-
expect(
|
|
37
|
+
const stop = await server.start()
|
|
38
|
+
expect(server.address()?.port).toBe(3000)
|
|
39
39
|
await stop()
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
test('args: host', async () => {
|
|
43
|
-
const
|
|
43
|
+
const server = createServer({
|
|
44
44
|
instance,
|
|
45
45
|
host: 'localhost',
|
|
46
46
|
port: 3000,
|
|
47
47
|
})
|
|
48
|
-
expect(
|
|
48
|
+
expect(server).toBeDefined()
|
|
49
49
|
|
|
50
|
-
const stop = await
|
|
51
|
-
expect(
|
|
52
|
-
expect(
|
|
50
|
+
const stop = await server.start()
|
|
51
|
+
expect(server.address()?.address).toBe('::1')
|
|
52
|
+
expect(server.address()?.port).toBe(3000)
|
|
53
53
|
await stop()
|
|
54
54
|
})
|
|
55
55
|
|
|
@@ -95,6 +95,19 @@ describe.each([{ instance: anvil() }])(
|
|
|
95
95
|
await stop()
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
+
test('request: /restart', async () => {
|
|
99
|
+
const server = createServer({
|
|
100
|
+
instance,
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const stop = await server.start()
|
|
104
|
+
const { port } = server.address()!
|
|
105
|
+
const response = await fetch(`http://localhost:${port}/1/restart`)
|
|
106
|
+
expect(response.status).toBe(200)
|
|
107
|
+
|
|
108
|
+
await stop()
|
|
109
|
+
})
|
|
110
|
+
|
|
98
111
|
test('ws', async () => {
|
|
99
112
|
const server = createServer({
|
|
100
113
|
instance,
|
|
@@ -224,6 +237,76 @@ describe("instance: 'anvil'", () => {
|
|
|
224
237
|
await stop()
|
|
225
238
|
})
|
|
226
239
|
|
|
240
|
+
test('request: /restart', async () => {
|
|
241
|
+
const server = createServer({
|
|
242
|
+
instance: anvil(),
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
const stop = await server.start()
|
|
246
|
+
const { port } = server.address()!
|
|
247
|
+
|
|
248
|
+
// Mine block number
|
|
249
|
+
await fetch(`http://localhost:${port}/1`, {
|
|
250
|
+
body: JSON.stringify({
|
|
251
|
+
method: 'anvil_mine',
|
|
252
|
+
params: ['0x69', '0x0'],
|
|
253
|
+
id: 0,
|
|
254
|
+
jsonrpc: '2.0',
|
|
255
|
+
}),
|
|
256
|
+
headers: {
|
|
257
|
+
'Content-Type': 'application/json',
|
|
258
|
+
},
|
|
259
|
+
method: 'POST',
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
// Check block numbers
|
|
263
|
+
expect(
|
|
264
|
+
await fetch(`http://localhost:${port}/1`, {
|
|
265
|
+
body: JSON.stringify({
|
|
266
|
+
method: 'eth_blockNumber',
|
|
267
|
+
id: 0,
|
|
268
|
+
jsonrpc: '2.0',
|
|
269
|
+
}),
|
|
270
|
+
headers: {
|
|
271
|
+
'Content-Type': 'application/json',
|
|
272
|
+
},
|
|
273
|
+
method: 'POST',
|
|
274
|
+
}).then((x) => x.json()),
|
|
275
|
+
).toMatchInlineSnapshot(`
|
|
276
|
+
{
|
|
277
|
+
"id": 0,
|
|
278
|
+
"jsonrpc": "2.0",
|
|
279
|
+
"result": "0x69",
|
|
280
|
+
}
|
|
281
|
+
`)
|
|
282
|
+
|
|
283
|
+
// Restart
|
|
284
|
+
await fetch(`http://localhost:${port}/1/restart`)
|
|
285
|
+
|
|
286
|
+
// Check block numbers
|
|
287
|
+
expect(
|
|
288
|
+
await fetch(`http://localhost:${port}/1`, {
|
|
289
|
+
body: JSON.stringify({
|
|
290
|
+
method: 'eth_blockNumber',
|
|
291
|
+
id: 0,
|
|
292
|
+
jsonrpc: '2.0',
|
|
293
|
+
}),
|
|
294
|
+
headers: {
|
|
295
|
+
'Content-Type': 'application/json',
|
|
296
|
+
},
|
|
297
|
+
method: 'POST',
|
|
298
|
+
}).then((x) => x.json()),
|
|
299
|
+
).toMatchInlineSnapshot(`
|
|
300
|
+
{
|
|
301
|
+
"id": 0,
|
|
302
|
+
"jsonrpc": "2.0",
|
|
303
|
+
"result": "0x0",
|
|
304
|
+
}
|
|
305
|
+
`)
|
|
306
|
+
|
|
307
|
+
await stop()
|
|
308
|
+
})
|
|
309
|
+
|
|
227
310
|
test('request: /messages', async () => {
|
|
228
311
|
const server = createServer({
|
|
229
312
|
instance: anvil(),
|
package/server.ts
CHANGED
|
@@ -56,44 +56,46 @@ export function createServer(
|
|
|
56
56
|
|
|
57
57
|
const { id, path } = extractPath(url)
|
|
58
58
|
|
|
59
|
-
if (typeof id === 'number'
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return
|
|
59
|
+
if (typeof id === 'number') {
|
|
60
|
+
if (path === '/') {
|
|
61
|
+
const { host, port } = pool.get(id) || (await pool.start(id))
|
|
62
|
+
return proxy.web(request, response, {
|
|
63
|
+
target: `http://${host}:${port}`,
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
if (path === '/start') {
|
|
67
|
+
const { host, port } = await pool.start(id)
|
|
68
|
+
return done(response, 200, { host, port })
|
|
69
|
+
}
|
|
70
|
+
if (path === '/stop') {
|
|
71
|
+
await pool.stop(id)
|
|
72
|
+
return done(response, 200)
|
|
73
|
+
}
|
|
74
|
+
if (path === '/restart') {
|
|
75
|
+
await pool.restart(id)
|
|
76
|
+
return done(response, 200)
|
|
77
|
+
}
|
|
78
|
+
if (path === '/messages') {
|
|
79
|
+
const messages = pool.get(id)?.messages.get() || []
|
|
80
|
+
return done(response, 200, messages)
|
|
81
|
+
}
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
if (path === '/healthcheck')
|
|
86
|
-
response.writeHead(200, { 'Content-Type': 'application/json' }).end()
|
|
87
|
-
return
|
|
88
|
-
}
|
|
84
|
+
if (path === '/healthcheck') return done(response, 200)
|
|
89
85
|
|
|
90
|
-
response
|
|
91
|
-
return
|
|
86
|
+
return done(response, 404)
|
|
92
87
|
} catch (error) {
|
|
93
|
-
response
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
return done(response, 400, { message: (error as Error).message })
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
proxy.on('proxyReq', (proxyReq, req) => {
|
|
93
|
+
;(req as any)._proxyReq = proxyReq
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
proxy.on('error', (err, req) => {
|
|
97
|
+
if (req.socket.destroyed && (err as any).code === 'ECONNRESET') {
|
|
98
|
+
;(req as any)._proxyReq.abort()
|
|
97
99
|
}
|
|
98
100
|
})
|
|
99
101
|
|
|
@@ -135,3 +137,9 @@ export function createServer(
|
|
|
135
137
|
},
|
|
136
138
|
})
|
|
137
139
|
}
|
|
140
|
+
|
|
141
|
+
function done(res: ServerResponse, statusCode: number, json?: unknown) {
|
|
142
|
+
return res
|
|
143
|
+
.writeHead(statusCode, { 'Content-Type': 'application/json' })
|
|
144
|
+
.end(json ? JSON.stringify(json) : undefined)
|
|
145
|
+
}
|