@nmtjs/protocol 0.8.1 → 0.10.0
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/dist/client/events.js +2 -0
- package/dist/client/events.js.map +1 -1
- package/dist/client/format.js +2 -0
- package/dist/client/format.js.map +1 -1
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/protocol.js +205 -199
- package/dist/client/protocol.js.map +1 -1
- package/dist/client/stream.js +9 -12
- package/dist/client/stream.js.map +1 -1
- package/dist/client/types.js +3 -0
- package/dist/client/types.js.map +1 -0
- package/dist/common/binary.js +2 -0
- package/dist/common/binary.js.map +1 -1
- package/dist/common/blob.js +6 -2
- package/dist/common/blob.js.map +1 -1
- package/dist/common/enums.js +4 -1
- package/dist/common/enums.js.map +1 -1
- package/dist/common/index.js +2 -0
- package/dist/common/index.js.map +1 -1
- package/dist/common/types.js +2 -0
- package/dist/common/types.js.map +1 -1
- package/dist/server/api.js +4 -1
- package/dist/server/api.js.map +1 -1
- package/dist/server/connection.js +2 -0
- package/dist/server/connection.js.map +1 -1
- package/dist/server/constants.js +2 -0
- package/dist/server/constants.js.map +1 -1
- package/dist/server/format.js +2 -0
- package/dist/server/format.js.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/injectables.js +2 -0
- package/dist/server/injectables.js.map +1 -1
- package/dist/server/protocol.js +154 -55
- package/dist/server/protocol.js.map +1 -1
- package/dist/server/registry.js +2 -0
- package/dist/server/registry.js.map +1 -1
- package/dist/server/stream.js +3 -1
- package/dist/server/stream.js.map +1 -1
- package/dist/server/transport.js +2 -0
- package/dist/server/transport.js.map +1 -1
- package/dist/server/types.js +3 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/utils.js +7 -2
- package/dist/server/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/client/format.ts +34 -5
- package/src/client/index.ts +2 -0
- package/src/client/protocol.ts +381 -274
- package/src/client/stream.ts +7 -14
- package/src/client/types.ts +14 -0
- package/src/common/blob.ts +10 -3
- package/src/common/enums.ts +3 -1
- package/src/common/types.ts +28 -47
- package/src/server/api.ts +15 -1
- package/src/server/connection.ts +1 -5
- package/src/server/format.ts +14 -4
- package/src/server/index.ts +1 -0
- package/src/server/protocol.ts +208 -66
- package/src/server/stream.ts +2 -7
- package/src/server/transport.ts +5 -1
- package/src/server/types.ts +21 -0
- package/src/server/utils.ts +9 -2
package/src/client/protocol.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createPromise,
|
|
3
3
|
type InteractivePromise,
|
|
4
|
-
|
|
4
|
+
type OneOf,
|
|
5
5
|
} from '@nmtjs/common'
|
|
6
6
|
import { concat, decodeNumber, encodeNumber } from '../common/binary.ts'
|
|
7
7
|
import type { ProtocolBlobMetadata } from '../common/blob.ts'
|
|
@@ -10,7 +10,11 @@ import {
|
|
|
10
10
|
ErrorCode,
|
|
11
11
|
ServerMessageType,
|
|
12
12
|
} from '../common/enums.ts'
|
|
13
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
BaseProtocolError,
|
|
15
|
+
ProtocolRPC,
|
|
16
|
+
ProtocolRPCResponse,
|
|
17
|
+
} from '../common/types.ts'
|
|
14
18
|
import { EventEmitter } from './events.ts'
|
|
15
19
|
import type { BaseClientFormat } from './format.ts'
|
|
16
20
|
import {
|
|
@@ -19,7 +23,7 @@ import {
|
|
|
19
23
|
ProtocolServerStream,
|
|
20
24
|
} from './stream.ts'
|
|
21
25
|
|
|
22
|
-
export class ProtocolError extends Error {
|
|
26
|
+
export class ProtocolError extends Error implements BaseProtocolError {
|
|
23
27
|
code: string
|
|
24
28
|
data?: any
|
|
25
29
|
|
|
@@ -69,9 +73,9 @@ export class ProtocolClientStreams {
|
|
|
69
73
|
this.#collection.delete(streamId)
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
abort(streamId: number) {
|
|
76
|
+
abort(streamId: number, error?: Error) {
|
|
73
77
|
const stream = this.get(streamId)
|
|
74
|
-
stream.abort()
|
|
78
|
+
stream.abort(error)
|
|
75
79
|
this.remove(streamId)
|
|
76
80
|
}
|
|
77
81
|
|
|
@@ -95,8 +99,10 @@ export class ProtocolClientStreams {
|
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
export class ProtocolServerStreams
|
|
99
|
-
|
|
102
|
+
export class ProtocolServerStreams<
|
|
103
|
+
T extends ProtocolServerStream = ProtocolServerStream,
|
|
104
|
+
> {
|
|
105
|
+
readonly #collection = new Map<number, T>()
|
|
100
106
|
|
|
101
107
|
has(streamId: number) {
|
|
102
108
|
return this.#collection.has(streamId)
|
|
@@ -108,7 +114,7 @@ export class ProtocolServerStreams {
|
|
|
108
114
|
return stream
|
|
109
115
|
}
|
|
110
116
|
|
|
111
|
-
add(streamId: number, stream:
|
|
117
|
+
add(streamId: number, stream: T) {
|
|
112
118
|
this.#collection.set(streamId, stream)
|
|
113
119
|
return stream
|
|
114
120
|
}
|
|
@@ -153,14 +159,29 @@ export type ProtocolTransportEventMap = {
|
|
|
153
159
|
disconnected: []
|
|
154
160
|
}
|
|
155
161
|
|
|
156
|
-
export interface
|
|
157
|
-
|
|
158
|
-
|
|
162
|
+
export interface ProtocolSendMetadata {
|
|
163
|
+
callId?: number
|
|
164
|
+
streamId?: number
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export abstract class ProtocolTransport {
|
|
168
|
+
abstract connect(
|
|
159
169
|
auth: any,
|
|
160
|
-
|
|
170
|
+
transformer: ProtocolBaseTransformer,
|
|
171
|
+
): Promise<void>
|
|
172
|
+
abstract disconnect(): Promise<void>
|
|
173
|
+
abstract call(
|
|
174
|
+
namespace: string,
|
|
175
|
+
procedure: string,
|
|
176
|
+
payload: any,
|
|
177
|
+
options: ProtocolBaseClientCallOptions,
|
|
178
|
+
transformer: ProtocolBaseTransformer,
|
|
179
|
+
): Promise<ProtocolClientCall>
|
|
180
|
+
abstract send(
|
|
181
|
+
messageType: ClientMessageType,
|
|
182
|
+
buffer: ArrayBuffer,
|
|
183
|
+
metadata: ProtocolSendMetadata,
|
|
161
184
|
): Promise<void>
|
|
162
|
-
disconnect(): Promise<void>
|
|
163
|
-
send(messageType: ClientMessageType, buffer: ArrayBuffer): Promise<void>
|
|
164
185
|
}
|
|
165
186
|
|
|
166
187
|
export class ProtocolBaseTransformer {
|
|
@@ -179,7 +200,7 @@ export class ProtocolBaseTransformer {
|
|
|
179
200
|
}
|
|
180
201
|
|
|
181
202
|
export type ProtocolClientCall = InteractivePromise<any> &
|
|
182
|
-
Pick<ProtocolRPC, 'namespace' | 'procedure'>
|
|
203
|
+
Pick<ProtocolRPC, 'namespace' | 'procedure'> & { signal: AbortSignal }
|
|
183
204
|
|
|
184
205
|
export type ProtocolBaseClientOptions = {
|
|
185
206
|
transport: ProtocolTransport
|
|
@@ -190,11 +211,14 @@ export type ProtocolBaseClientOptions = {
|
|
|
190
211
|
|
|
191
212
|
export type ProtocolBaseClientCallOptions = {
|
|
192
213
|
signal?: AbortSignal
|
|
193
|
-
timeout
|
|
214
|
+
timeout: number
|
|
194
215
|
}
|
|
195
216
|
|
|
196
|
-
export
|
|
197
|
-
T extends Record<string, Record<string, any
|
|
217
|
+
export class BaseProtocol<
|
|
218
|
+
T extends Record<string, Record<string, any>> = Record<
|
|
219
|
+
string,
|
|
220
|
+
Record<string, any>
|
|
221
|
+
>,
|
|
198
222
|
> extends EventEmitter<
|
|
199
223
|
{
|
|
200
224
|
[N in keyof T]: {
|
|
@@ -204,318 +228,401 @@ export abstract class ProtocolBaseClient<
|
|
|
204
228
|
}
|
|
205
229
|
}[keyof T]
|
|
206
230
|
> {
|
|
207
|
-
readonly
|
|
208
|
-
|
|
209
|
-
readonly
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
>()
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
readonly
|
|
218
|
-
readonly transformer: ProtocolBaseTransformer = new ProtocolBaseTransformer()
|
|
219
|
-
readonly #timeout: number
|
|
220
|
-
|
|
221
|
-
#callId = 0
|
|
222
|
-
#streamId = 0
|
|
223
|
-
|
|
224
|
-
constructor(options: ProtocolBaseClientOptions) {
|
|
231
|
+
protected readonly clientStreams: ProtocolClientStreams =
|
|
232
|
+
new ProtocolClientStreams()
|
|
233
|
+
protected readonly serverStreams: ProtocolServerStreams<ProtocolServerBlobStream> =
|
|
234
|
+
new ProtocolServerStreams()
|
|
235
|
+
protected readonly rpcStreams: ProtocolServerStreams =
|
|
236
|
+
new ProtocolServerStreams()
|
|
237
|
+
protected readonly calls = new Map<number, ProtocolClientCall>()
|
|
238
|
+
protected callId = 0
|
|
239
|
+
protected streamId = 0
|
|
240
|
+
|
|
241
|
+
constructor(public readonly format: BaseClientFormat) {
|
|
225
242
|
super()
|
|
226
|
-
|
|
227
|
-
this.#transport = options.transport
|
|
228
|
-
this.#format = options.format
|
|
229
|
-
this.#timeout = options.timeout ?? 60000
|
|
230
|
-
|
|
231
|
-
this.#clientStreams = new ProtocolClientStreams()
|
|
232
|
-
this.#serverStreams = new ProtocolServerStreams()
|
|
233
|
-
this.#rpcStreams = new ProtocolServerStreams()
|
|
234
|
-
|
|
235
|
-
this.#transport.on(`${ServerMessageType.Event}`, (buffer) => {
|
|
236
|
-
const [namespace, event, payload] = this.#format.decode(buffer)
|
|
237
|
-
const name = `${namespace}/${event}`
|
|
238
|
-
const transformed = this.transformer.decodeEvent(
|
|
239
|
-
namespace,
|
|
240
|
-
event,
|
|
241
|
-
payload,
|
|
242
|
-
)
|
|
243
|
-
this.emit(name, transformed)
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
this.#transport.on(`${ServerMessageType.RpcResponse}`, (buffer) => {
|
|
247
|
-
const { call, error, payload } = this.#handleResponse(buffer)
|
|
248
|
-
if (error) call.reject(error)
|
|
249
|
-
else call.resolve(payload)
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
this.#transport.on(`${ServerMessageType.RpcStreamResponse}`, (buffer) => {
|
|
253
|
-
const { call, response, payload, error } = this.#handleResponse(buffer)
|
|
254
|
-
if (error) return call.reject(error)
|
|
255
|
-
console.log('Creating RPC stream', response)
|
|
256
|
-
const stream = new ProtocolServerStream()
|
|
257
|
-
this.#rpcStreams.add(response.callId, stream)
|
|
258
|
-
this.#rpcStreamData.set(response.callId, {
|
|
259
|
-
namespace: call.namespace,
|
|
260
|
-
procedure: call.procedure,
|
|
261
|
-
})
|
|
262
|
-
call.resolve({ payload, stream })
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
this.#transport.on(
|
|
266
|
-
`${ServerMessageType.RpcStreamChunk}`,
|
|
267
|
-
async (buffer) => {
|
|
268
|
-
const callId = decodeNumber(buffer, 'Uint32')
|
|
269
|
-
console.log('RPC stream chunk', callId)
|
|
270
|
-
|
|
271
|
-
const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)
|
|
272
|
-
if (chunk.byteLength === 0) {
|
|
273
|
-
this.#rpcStreams.end(callId)
|
|
274
|
-
this.#rpcStreamData.delete(callId)
|
|
275
|
-
} else {
|
|
276
|
-
const call = this.#rpcStreamData.get(callId)
|
|
277
|
-
console.log('RPC stream call', call)
|
|
278
|
-
if (call) {
|
|
279
|
-
const payload = this.#format.decode(chunk)
|
|
280
|
-
console.log('RPC stream payload', payload)
|
|
281
|
-
try {
|
|
282
|
-
const transformed = this.transformer.decodeRPCChunk(
|
|
283
|
-
call.namespace,
|
|
284
|
-
call.procedure,
|
|
285
|
-
payload,
|
|
286
|
-
)
|
|
287
|
-
await this.#rpcStreams.push(callId, transformed)
|
|
288
|
-
} catch (error) {
|
|
289
|
-
this.#send(
|
|
290
|
-
ClientMessageType.RpcStreamAbort,
|
|
291
|
-
encodeNumber(callId, 'Uint32'),
|
|
292
|
-
)
|
|
293
|
-
this.#rpcStreams.remove(callId)
|
|
294
|
-
this.#rpcStreamData.delete(callId)
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
},
|
|
299
|
-
)
|
|
300
|
-
|
|
301
|
-
this.#transport.on(`${ServerMessageType.RpcStreamAbort}`, (buffer) => {
|
|
302
|
-
const callId = decodeNumber(buffer, 'Uint32')
|
|
303
|
-
console.log('RPC stream abort', callId)
|
|
304
|
-
const call = this.#calls.get(callId)
|
|
305
|
-
if (call) {
|
|
306
|
-
this.#serverStreams.end(callId)
|
|
307
|
-
this.#rpcStreams.abort(callId)
|
|
308
|
-
}
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
this.#transport.on(
|
|
312
|
-
`${ServerMessageType.ServerStreamPush}`,
|
|
313
|
-
async (buffer) => {
|
|
314
|
-
const streamId = decodeNumber(buffer, 'Uint32')
|
|
315
|
-
const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)
|
|
316
|
-
console.log('Server stream push', streamId, chunk.byteLength)
|
|
317
|
-
try {
|
|
318
|
-
await this.#serverStreams.push(streamId, chunk)
|
|
319
|
-
this.#send(
|
|
320
|
-
ClientMessageType.ServerStreamPull,
|
|
321
|
-
encodeNumber(streamId, 'Uint32'),
|
|
322
|
-
)
|
|
323
|
-
} catch (error) {
|
|
324
|
-
this.#send(
|
|
325
|
-
ClientMessageType.ServerStreamAbort,
|
|
326
|
-
encodeNumber(streamId, 'Uint32'),
|
|
327
|
-
)
|
|
328
|
-
this.#serverStreams.remove(streamId)
|
|
329
|
-
}
|
|
330
|
-
},
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
this.#transport.on(`${ServerMessageType.ServerStreamEnd}`, (buffer) => {
|
|
334
|
-
const streamId = decodeNumber(buffer, 'Uint32')
|
|
335
|
-
console.log('Server stream end', streamId)
|
|
336
|
-
this.#serverStreams.end(streamId)
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
this.#transport.on(`${ServerMessageType.ServerStreamAbort}`, (buffer) => {
|
|
340
|
-
const streamId = decodeNumber(buffer, 'Uint32')
|
|
341
|
-
console.log('Server stream abort', streamId)
|
|
342
|
-
this.#serverStreams.abort(streamId)
|
|
343
|
-
})
|
|
344
|
-
|
|
345
|
-
this.#transport.on(`${ServerMessageType.ClientStreamAbort}`, (buffer) => {
|
|
346
|
-
const streamId = decodeNumber(buffer, 'Uint32')
|
|
347
|
-
console.log('Client stream abort', streamId)
|
|
348
|
-
this.#clientStreams.abort(streamId)
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
this.#transport.on(
|
|
352
|
-
`${ServerMessageType.ClientStreamPull}`,
|
|
353
|
-
async (buffer) => {
|
|
354
|
-
const streamId = decodeNumber(buffer, 'Uint32')
|
|
355
|
-
console.log('Client stream pull', streamId)
|
|
356
|
-
const size = decodeNumber(
|
|
357
|
-
buffer,
|
|
358
|
-
'Uint32',
|
|
359
|
-
Uint32Array.BYTES_PER_ELEMENT,
|
|
360
|
-
)
|
|
361
|
-
const streamIdEncoded = encodeNumber(streamId, 'Uint32')
|
|
362
|
-
try {
|
|
363
|
-
const chunk = await this.#clientStreams.pull(streamId, size)
|
|
364
|
-
if (chunk) {
|
|
365
|
-
this.#send(
|
|
366
|
-
ClientMessageType.ClientStreamPush,
|
|
367
|
-
concat(streamIdEncoded, chunk),
|
|
368
|
-
)
|
|
369
|
-
} else {
|
|
370
|
-
this.#send(ClientMessageType.ClientStreamEnd, streamIdEncoded)
|
|
371
|
-
this.#clientStreams.end(streamId)
|
|
372
|
-
}
|
|
373
|
-
} catch (error) {
|
|
374
|
-
console.error(error)
|
|
375
|
-
this.#send(ClientMessageType.ClientStreamAbort, streamIdEncoded)
|
|
376
|
-
}
|
|
377
|
-
},
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
this.#transport.on('disconnected', () => {
|
|
381
|
-
this.#clear()
|
|
382
|
-
})
|
|
383
243
|
}
|
|
384
244
|
|
|
385
|
-
|
|
386
|
-
return
|
|
245
|
+
get contentType() {
|
|
246
|
+
return this.format.contentType
|
|
387
247
|
}
|
|
388
248
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
249
|
+
handleCallResponse(
|
|
250
|
+
callId: number,
|
|
251
|
+
call: ProtocolClientCall,
|
|
252
|
+
response: OneOf<
|
|
253
|
+
[{ error: BaseProtocolError }, { result: any; stream?: any }]
|
|
254
|
+
>,
|
|
255
|
+
transformer: ProtocolBaseTransformer,
|
|
256
|
+
) {
|
|
257
|
+
if (response.error) {
|
|
258
|
+
call.reject(
|
|
259
|
+
new ProtocolError(
|
|
260
|
+
response.error.code,
|
|
261
|
+
response.error.message,
|
|
262
|
+
response.error.data,
|
|
263
|
+
),
|
|
264
|
+
)
|
|
265
|
+
} else {
|
|
266
|
+
try {
|
|
267
|
+
const transformed = transformer.decodeRPC(
|
|
268
|
+
call.namespace,
|
|
269
|
+
call.procedure,
|
|
270
|
+
response.result,
|
|
271
|
+
)
|
|
272
|
+
if (response.stream)
|
|
273
|
+
call.resolve({ result: transformed, stream: response.stream })
|
|
274
|
+
else call.resolve(transformed)
|
|
275
|
+
} catch (error) {
|
|
276
|
+
call.reject(
|
|
277
|
+
new ProtocolError(
|
|
278
|
+
ErrorCode.ClientRequestError,
|
|
279
|
+
'Unable to decode response',
|
|
280
|
+
error,
|
|
281
|
+
),
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
this.calls.delete(callId)
|
|
392
286
|
}
|
|
393
287
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
288
|
+
handleRpcResponse(
|
|
289
|
+
{ callId, error, result, streams }: ProtocolRPCResponse,
|
|
290
|
+
transformer: ProtocolBaseTransformer,
|
|
291
|
+
stream?: ProtocolServerStream,
|
|
292
|
+
) {
|
|
293
|
+
const call = this.calls.get(callId)
|
|
294
|
+
if (!call) throw new Error('Call not found')
|
|
295
|
+
for (const key in streams) {
|
|
296
|
+
const stream = streams[key]
|
|
297
|
+
this.serverStreams.add(stream.id, stream)
|
|
298
|
+
}
|
|
299
|
+
this.handleCallResponse(
|
|
300
|
+
callId,
|
|
301
|
+
call,
|
|
302
|
+
error ? { error } : { result, stream },
|
|
303
|
+
transformer,
|
|
399
304
|
)
|
|
400
|
-
return
|
|
305
|
+
return call
|
|
401
306
|
}
|
|
402
307
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
this
|
|
410
|
-
|
|
411
|
-
this.#clientStreams.clear(error)
|
|
412
|
-
this.#rpcStreams.clear(error)
|
|
413
|
-
this.#callId = 0
|
|
414
|
-
this.#streamId = 0
|
|
308
|
+
handleRpcStreamResponse(
|
|
309
|
+
response: ProtocolRPCResponse,
|
|
310
|
+
stream: ProtocolServerStream,
|
|
311
|
+
transformer: ProtocolBaseTransformer,
|
|
312
|
+
) {
|
|
313
|
+
const call = this.handleRpcResponse(response, transformer, stream)
|
|
314
|
+
this.rpcStreams.add(response.callId, stream)
|
|
315
|
+
return call
|
|
415
316
|
}
|
|
416
317
|
|
|
417
|
-
|
|
318
|
+
createCall(
|
|
418
319
|
namespace: string,
|
|
419
320
|
procedure: string,
|
|
420
|
-
|
|
421
|
-
options: ProtocolBaseClientCallOptions = {},
|
|
321
|
+
options: ProtocolBaseClientCallOptions,
|
|
422
322
|
) {
|
|
423
|
-
const timeoutSignal = AbortSignal.timeout(options.timeout
|
|
323
|
+
const timeoutSignal = AbortSignal.timeout(options.timeout)
|
|
424
324
|
const signal = options.signal
|
|
425
325
|
? AbortSignal.any([options.signal, timeoutSignal])
|
|
426
326
|
: timeoutSignal
|
|
427
327
|
|
|
428
|
-
const callId = ++this.#callId
|
|
429
328
|
const call = Object.assign(createPromise(), {
|
|
430
329
|
namespace,
|
|
431
330
|
procedure,
|
|
331
|
+
signal,
|
|
432
332
|
})
|
|
433
|
-
|
|
333
|
+
|
|
334
|
+
timeoutSignal.addEventListener(
|
|
335
|
+
'abort',
|
|
336
|
+
() => {
|
|
337
|
+
const error = new ProtocolError(
|
|
338
|
+
ErrorCode.RequestTimeout,
|
|
339
|
+
'Request timeout',
|
|
340
|
+
)
|
|
341
|
+
call.reject(error)
|
|
342
|
+
},
|
|
343
|
+
{ once: true },
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
return call
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
createRpc(
|
|
350
|
+
namespace: string,
|
|
351
|
+
procedure: string,
|
|
352
|
+
payload: any,
|
|
353
|
+
options: ProtocolBaseClientCallOptions,
|
|
354
|
+
transformer: ProtocolBaseTransformer,
|
|
355
|
+
) {
|
|
356
|
+
const callId = ++this.callId
|
|
357
|
+
const call = this.createCall(namespace, procedure, options)
|
|
358
|
+
const { buffer, streams } = this.format.encodeRPC(
|
|
434
359
|
{
|
|
435
360
|
callId,
|
|
436
361
|
namespace,
|
|
437
362
|
procedure,
|
|
438
|
-
payload:
|
|
363
|
+
payload: transformer.encodeRPC(namespace, procedure, payload),
|
|
439
364
|
},
|
|
440
365
|
{
|
|
441
366
|
addStream: (blob) => {
|
|
442
|
-
const streamId = ++this
|
|
443
|
-
|
|
444
|
-
blob.source,
|
|
445
|
-
streamId,
|
|
446
|
-
blob.metadata,
|
|
447
|
-
)
|
|
448
|
-
return stream
|
|
367
|
+
const streamId = ++this.streamId
|
|
368
|
+
return this.clientStreams.add(blob.source, streamId, blob.metadata)
|
|
449
369
|
},
|
|
450
370
|
getStream: (id) => {
|
|
451
|
-
const stream = this
|
|
371
|
+
const stream = this.clientStreams.get(id)
|
|
452
372
|
return stream
|
|
453
373
|
},
|
|
454
374
|
},
|
|
455
375
|
)
|
|
456
376
|
|
|
457
|
-
this
|
|
377
|
+
this.calls.set(callId, call)
|
|
378
|
+
|
|
379
|
+
return { callId, call, streams, buffer }
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
pushRpcStream(callId: number, chunk: any) {
|
|
383
|
+
this.rpcStreams.push(callId, chunk)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
endRpcStream(callId: number) {
|
|
387
|
+
this.rpcStreams.end(callId)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
abortRpcStream(callId: number) {
|
|
391
|
+
this.rpcStreams.abort(callId)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
removeClientStream(streamId: number) {
|
|
395
|
+
this.clientStreams.remove(streamId)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
pullClientStream(streamId: number, size: number) {
|
|
399
|
+
return this.clientStreams.pull(streamId, size)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
endClientStream(streamId: number) {
|
|
403
|
+
this.clientStreams.end(streamId)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
abortClientStream(streamId: number, error?: Error) {
|
|
407
|
+
this.clientStreams.abort(streamId, error)
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
addServerStream(stream: ProtocolServerBlobStream) {
|
|
411
|
+
this.serverStreams.add(stream.id, stream)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
removeServerStream(streamId: number) {
|
|
415
|
+
this.serverStreams.remove(streamId)
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
pushServerStream(streamId: number, chunk: ArrayBuffer) {
|
|
419
|
+
return this.serverStreams.push(streamId, chunk)
|
|
420
|
+
}
|
|
458
421
|
|
|
459
|
-
|
|
422
|
+
endServerStream(streamId: number) {
|
|
423
|
+
this.serverStreams.end(streamId)
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
abortServerStream(streamId: number, error?: Error) {
|
|
427
|
+
this.serverStreams.abort(streamId)
|
|
428
|
+
}
|
|
460
429
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
430
|
+
emitEvent(
|
|
431
|
+
namespace: string,
|
|
432
|
+
event: string,
|
|
433
|
+
payload: string,
|
|
434
|
+
transformer: ProtocolBaseTransformer,
|
|
435
|
+
) {
|
|
436
|
+
const transformed = transformer.decodeEvent(namespace, event, payload)
|
|
437
|
+
this.emit(`${namespace}/${event}`, transformed)
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export class Protocol<
|
|
442
|
+
T extends Record<string, Record<string, any>> = Record<
|
|
443
|
+
string,
|
|
444
|
+
Record<string, any>
|
|
445
|
+
>,
|
|
446
|
+
> extends BaseProtocol<T> {
|
|
447
|
+
handleServerMessage(
|
|
448
|
+
buffer: ArrayBuffer,
|
|
449
|
+
transport: ProtocolTransport,
|
|
450
|
+
transformer: ProtocolBaseTransformer,
|
|
451
|
+
) {
|
|
452
|
+
const type = decodeNumber(buffer, 'Uint8')
|
|
453
|
+
const messageBuffer = buffer.slice(Uint8Array.BYTES_PER_ELEMENT)
|
|
454
|
+
if (type in ServerMessageType) {
|
|
455
|
+
const messageType = type as ServerMessageType
|
|
456
|
+
if (typeof ServerMessageType[messageType] !== 'undefined') {
|
|
457
|
+
this[messageType](messageBuffer, transport, transformer)
|
|
458
|
+
} else {
|
|
459
|
+
throw new Error(`Unknown message type: ${messageType}`)
|
|
464
460
|
}
|
|
465
|
-
|
|
466
|
-
|
|
461
|
+
}
|
|
462
|
+
}
|
|
467
463
|
|
|
468
|
-
|
|
464
|
+
protected [ServerMessageType.Event](
|
|
465
|
+
buffer: ArrayBuffer,
|
|
466
|
+
transport: ProtocolTransport,
|
|
467
|
+
transformer: ProtocolBaseTransformer,
|
|
468
|
+
) {
|
|
469
|
+
const [namespace, event, payload] = this.format.decode(buffer)
|
|
470
|
+
this.emitEvent(namespace, event, payload, transformer)
|
|
469
471
|
}
|
|
470
472
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
473
|
+
protected [ServerMessageType.RpcResponse](
|
|
474
|
+
buffer: ArrayBuffer,
|
|
475
|
+
transport: ProtocolTransport,
|
|
476
|
+
transformer: ProtocolBaseTransformer,
|
|
477
|
+
) {
|
|
478
|
+
const response = this.format.decodeRPC(buffer, {
|
|
479
|
+
addStream: (id, callId, metadata) => {
|
|
480
|
+
return new ProtocolServerBlobStream(id, metadata, {
|
|
481
|
+
start: () => {
|
|
482
|
+
transport.send(
|
|
483
|
+
ClientMessageType.ServerStreamPull,
|
|
484
|
+
encodeNumber(id, 'Uint32'),
|
|
485
|
+
{ callId, streamId: id },
|
|
486
|
+
)
|
|
487
|
+
},
|
|
481
488
|
})
|
|
482
|
-
callStreams.push(stream)
|
|
483
|
-
this.#serverStreams.add(id, stream)
|
|
484
|
-
return stream
|
|
485
489
|
},
|
|
486
490
|
getStream: (id) => {
|
|
487
|
-
return this
|
|
491
|
+
return this.serverStreams.get(id)
|
|
488
492
|
},
|
|
489
493
|
})
|
|
494
|
+
this.handleRpcResponse(response, transformer)
|
|
495
|
+
}
|
|
490
496
|
|
|
491
|
-
|
|
497
|
+
protected [ServerMessageType.RpcStreamResponse](
|
|
498
|
+
buffer: ArrayBuffer,
|
|
499
|
+
transport: ProtocolTransport,
|
|
500
|
+
transformer: ProtocolBaseTransformer,
|
|
501
|
+
) {
|
|
502
|
+
const response = this.format.decodeRPC(buffer, {
|
|
503
|
+
addStream: (id, callId, metadata) => {
|
|
504
|
+
return new ProtocolServerBlobStream(id, metadata, {
|
|
505
|
+
start: () => {
|
|
506
|
+
transport.send(
|
|
507
|
+
ClientMessageType.ServerStreamPull,
|
|
508
|
+
encodeNumber(id, 'Uint32'),
|
|
509
|
+
{ callId, streamId: id },
|
|
510
|
+
)
|
|
511
|
+
},
|
|
512
|
+
})
|
|
513
|
+
},
|
|
514
|
+
getStream: (id) => {
|
|
515
|
+
return this.serverStreams.get(id)
|
|
516
|
+
},
|
|
517
|
+
})
|
|
492
518
|
|
|
493
|
-
const
|
|
519
|
+
const stream = new ProtocolServerStream({
|
|
520
|
+
transform: (chunk, controller) => {
|
|
521
|
+
const transformed = transformer.decodeRPCChunk(
|
|
522
|
+
call.namespace,
|
|
523
|
+
call.procedure,
|
|
524
|
+
chunk,
|
|
525
|
+
)
|
|
526
|
+
controller.enqueue(transformed)
|
|
527
|
+
},
|
|
528
|
+
})
|
|
494
529
|
|
|
495
|
-
|
|
496
|
-
|
|
530
|
+
const call = this.handleRpcStreamResponse(response, stream, transformer)
|
|
531
|
+
}
|
|
497
532
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
533
|
+
protected [ServerMessageType.RpcStreamChunk](
|
|
534
|
+
buffer: ArrayBuffer,
|
|
535
|
+
transport: ProtocolTransport,
|
|
536
|
+
transformer: ProtocolBaseTransformer,
|
|
537
|
+
) {
|
|
538
|
+
const callId = decodeNumber(buffer, 'Uint32')
|
|
539
|
+
const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)
|
|
540
|
+
const payload = this.format.decode(chunk)
|
|
541
|
+
this.pushRpcStream(callId, payload)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
protected [ServerMessageType.RpcStreamEnd](
|
|
545
|
+
buffer: ArrayBuffer,
|
|
546
|
+
transport: ProtocolTransport,
|
|
547
|
+
transformer: ProtocolBaseTransformer,
|
|
548
|
+
) {
|
|
549
|
+
const callId = decodeNumber(buffer, 'Uint32')
|
|
550
|
+
this.endRpcStream(callId)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
protected [ServerMessageType.RpcStreamAbort](
|
|
554
|
+
buffer: ArrayBuffer,
|
|
555
|
+
transport: ProtocolTransport,
|
|
556
|
+
transformer: ProtocolBaseTransformer,
|
|
557
|
+
) {
|
|
558
|
+
const callId = decodeNumber(buffer, 'Uint32')
|
|
559
|
+
this.abortRpcStream(callId)
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
protected [ServerMessageType.ServerStreamPush](
|
|
563
|
+
buffer: ArrayBuffer,
|
|
564
|
+
transport: ProtocolTransport,
|
|
565
|
+
transformer: ProtocolBaseTransformer,
|
|
566
|
+
) {
|
|
567
|
+
const streamId = decodeNumber(buffer, 'Uint32')
|
|
568
|
+
const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)
|
|
569
|
+
this.pushServerStream(streamId, chunk)
|
|
570
|
+
transport.send(
|
|
571
|
+
ClientMessageType.ServerStreamPull,
|
|
572
|
+
encodeNumber(streamId, 'Uint32'),
|
|
573
|
+
{ streamId },
|
|
574
|
+
)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
protected [ServerMessageType.ServerStreamEnd](
|
|
578
|
+
buffer: ArrayBuffer,
|
|
579
|
+
transport: ProtocolTransport,
|
|
580
|
+
transformer: ProtocolBaseTransformer,
|
|
581
|
+
) {
|
|
582
|
+
const streamId = decodeNumber(buffer, 'Uint32')
|
|
583
|
+
this.endServerStream(streamId)
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
protected [ServerMessageType.ServerStreamAbort](
|
|
587
|
+
buffer: ArrayBuffer,
|
|
588
|
+
transport: ProtocolTransport,
|
|
589
|
+
transformer: ProtocolBaseTransformer,
|
|
590
|
+
) {
|
|
591
|
+
const streamId = decodeNumber(buffer, 'Uint32')
|
|
592
|
+
this.abortServerStream(streamId)
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
protected [ServerMessageType.ClientStreamPull](
|
|
596
|
+
buffer: ArrayBuffer,
|
|
597
|
+
transport: ProtocolTransport,
|
|
598
|
+
transformer: ProtocolBaseTransformer,
|
|
599
|
+
) {
|
|
600
|
+
const streamId = decodeNumber(buffer, 'Uint32')
|
|
601
|
+
const size = decodeNumber(buffer, 'Uint32', Uint32Array.BYTES_PER_ELEMENT)
|
|
602
|
+
this.pullClientStream(streamId, size).then((chunk) => {
|
|
603
|
+
if (chunk) {
|
|
604
|
+
transport.send(
|
|
605
|
+
ClientMessageType.ClientStreamPush,
|
|
606
|
+
concat(encodeNumber(streamId, 'Uint32'), chunk),
|
|
607
|
+
{ streamId },
|
|
503
608
|
)
|
|
504
|
-
return { call, response, error }
|
|
505
609
|
} else {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
610
|
+
transport.send(
|
|
611
|
+
ClientMessageType.ClientStreamEnd,
|
|
612
|
+
encodeNumber(streamId, 'Uint32'),
|
|
613
|
+
{ streamId },
|
|
510
614
|
)
|
|
511
|
-
|
|
615
|
+
this.endClientStream(streamId)
|
|
512
616
|
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
for (const stream of callStreams) {
|
|
516
|
-
this.#serverStreams.abort(stream.id)
|
|
517
|
-
}
|
|
617
|
+
})
|
|
618
|
+
}
|
|
518
619
|
|
|
519
|
-
|
|
620
|
+
protected [ServerMessageType.ClientStreamAbort](
|
|
621
|
+
buffer: ArrayBuffer,
|
|
622
|
+
transport: ProtocolTransport,
|
|
623
|
+
transformer: ProtocolBaseTransformer,
|
|
624
|
+
) {
|
|
625
|
+
const streamId = decodeNumber(buffer, 'Uint32')
|
|
626
|
+
this.abortClientStream(streamId)
|
|
520
627
|
}
|
|
521
628
|
}
|