@nmtjs/protocol 0.8.1 → 0.9.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 +7 -7
- 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/server/protocol.ts
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
-
import { type Callback,
|
|
2
|
-
import {
|
|
1
|
+
import { type Callback, defer, throwError } from '@nmtjs/common'
|
|
2
|
+
import {
|
|
3
|
+
type AnyInjectable,
|
|
4
|
+
type Container,
|
|
5
|
+
Hook,
|
|
6
|
+
type Logger,
|
|
7
|
+
Scope,
|
|
8
|
+
} from '@nmtjs/core'
|
|
3
9
|
import { concat, decodeNumber, encodeNumber } from '../common/binary.ts'
|
|
4
10
|
import type { ProtocolBlob, ProtocolBlobMetadata } from '../common/blob.ts'
|
|
5
11
|
import { ErrorCode, ServerMessageType } from '../common/enums.ts'
|
|
6
12
|
import type { ProtocolRPC } from '../common/types.ts'
|
|
7
|
-
import
|
|
13
|
+
import {
|
|
14
|
+
isIterableResult,
|
|
15
|
+
type ProtocolApi,
|
|
16
|
+
type ProtocolApiCallOptions,
|
|
17
|
+
} from './api.ts'
|
|
8
18
|
import {
|
|
9
19
|
Connection,
|
|
10
20
|
ConnectionContext,
|
|
11
21
|
type ConnectionOptions,
|
|
12
22
|
} from './connection.ts'
|
|
13
23
|
import type { Format } from './format.ts'
|
|
24
|
+
import { ProtocolInjectables } from './injectables.ts'
|
|
14
25
|
import type { ProtocolRegistry } from './registry.ts'
|
|
15
26
|
import { ProtocolClientStream, ProtocolServerStream } from './stream.ts'
|
|
16
27
|
import type { Transport } from './transport.ts'
|
|
@@ -43,13 +54,17 @@ export class ProtocolError extends Error {
|
|
|
43
54
|
}
|
|
44
55
|
}
|
|
45
56
|
|
|
57
|
+
export type ProtocolConnectionTransport = {
|
|
58
|
+
send: Transport<any>['send']
|
|
59
|
+
}
|
|
60
|
+
|
|
46
61
|
export class ProtocolConnections {
|
|
47
62
|
readonly #collection = new Map<
|
|
48
63
|
string,
|
|
49
64
|
{
|
|
50
65
|
connection: Connection
|
|
51
66
|
context: ConnectionContext
|
|
52
|
-
transport:
|
|
67
|
+
transport: ProtocolConnectionTransport
|
|
53
68
|
}
|
|
54
69
|
>()
|
|
55
70
|
|
|
@@ -69,7 +84,7 @@ export class ProtocolConnections {
|
|
|
69
84
|
}
|
|
70
85
|
|
|
71
86
|
async add<T>(
|
|
72
|
-
transport:
|
|
87
|
+
transport: ProtocolConnectionTransport,
|
|
73
88
|
options: ConnectionOptions<T>,
|
|
74
89
|
params: ResolveFormatParams,
|
|
75
90
|
) {
|
|
@@ -77,16 +92,19 @@ export class ProtocolConnections {
|
|
|
77
92
|
const format = getFormat(this.application.format, params)
|
|
78
93
|
const container = this.application.container.fork(Scope.Connection)
|
|
79
94
|
const context = new ConnectionContext(container, format)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
95
|
+
container.provide(ProtocolInjectables.connection, connection)
|
|
96
|
+
try {
|
|
97
|
+
await this.initialize(connection)
|
|
98
|
+
this.#collection.set(connection.id, { connection, context, transport })
|
|
99
|
+
return { connection, context }
|
|
100
|
+
} finally {
|
|
101
|
+
container.dispose().catch((error) => {
|
|
102
|
+
this.application.logger.error(
|
|
103
|
+
{ error, connection },
|
|
104
|
+
'Error during disposing connection',
|
|
105
|
+
)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
90
108
|
}
|
|
91
109
|
|
|
92
110
|
async remove(connectionId: string) {
|
|
@@ -128,6 +146,14 @@ export class ProtocolConnections {
|
|
|
128
146
|
)
|
|
129
147
|
}
|
|
130
148
|
}
|
|
149
|
+
|
|
150
|
+
async initialize(connection: Connection) {
|
|
151
|
+
await this.application.registry.hooks.call(
|
|
152
|
+
Hook.OnConnect,
|
|
153
|
+
{ concurrent: false },
|
|
154
|
+
connection,
|
|
155
|
+
)
|
|
156
|
+
}
|
|
131
157
|
}
|
|
132
158
|
|
|
133
159
|
export class ProtocolClientStreams {
|
|
@@ -162,12 +188,12 @@ export class ProtocolClientStreams {
|
|
|
162
188
|
|
|
163
189
|
push(connectionId: string, streamId: number, chunk: ArrayBuffer) {
|
|
164
190
|
const stream = this.get(connectionId, streamId)
|
|
165
|
-
stream.
|
|
191
|
+
stream.write(Buffer.from(chunk))
|
|
166
192
|
}
|
|
167
193
|
|
|
168
194
|
end(connectionId: string, streamId: number) {
|
|
169
195
|
const stream = this.get(connectionId, streamId)
|
|
170
|
-
stream.
|
|
196
|
+
stream.end(null)
|
|
171
197
|
this.remove(connectionId, streamId)
|
|
172
198
|
}
|
|
173
199
|
|
|
@@ -204,6 +230,7 @@ export class ProtocolServerStreams {
|
|
|
204
230
|
}
|
|
205
231
|
|
|
206
232
|
pull(connectionId: string, streamId: number) {
|
|
233
|
+
console.log('Pulling stream', streamId)
|
|
207
234
|
const stream = this.get(connectionId, streamId)
|
|
208
235
|
stream.resume()
|
|
209
236
|
}
|
|
@@ -215,10 +242,16 @@ export class ProtocolServerStreams {
|
|
|
215
242
|
}
|
|
216
243
|
}
|
|
217
244
|
|
|
245
|
+
export type ProtocolRPCOptions = {
|
|
246
|
+
signal?: AbortSignal
|
|
247
|
+
provides?: [AnyInjectable, any][]
|
|
248
|
+
metadata?: ProtocolApiCallOptions['metadata']
|
|
249
|
+
}
|
|
250
|
+
|
|
218
251
|
export class Protocol {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
252
|
+
#connections: ProtocolConnections
|
|
253
|
+
#clientStreams: ProtocolClientStreams
|
|
254
|
+
#serverStreams: ProtocolServerStreams
|
|
222
255
|
|
|
223
256
|
constructor(
|
|
224
257
|
protected readonly application: {
|
|
@@ -229,18 +262,44 @@ export class Protocol {
|
|
|
229
262
|
api: ProtocolApi
|
|
230
263
|
},
|
|
231
264
|
) {
|
|
232
|
-
this
|
|
233
|
-
this
|
|
234
|
-
this
|
|
265
|
+
this.#connections = new ProtocolConnections(this.application)
|
|
266
|
+
this.#clientStreams = new ProtocolClientStreams(this.#connections)
|
|
267
|
+
this.#serverStreams = new ProtocolServerStreams(this.#connections)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async call(options: ProtocolApiCallOptions) {
|
|
271
|
+
const { container, connection } = options
|
|
272
|
+
try {
|
|
273
|
+
return await this.application.api.call(options)
|
|
274
|
+
} catch (error) {
|
|
275
|
+
if (error instanceof ProtocolError === false) {
|
|
276
|
+
this.application.logger.error(
|
|
277
|
+
{ error, connection },
|
|
278
|
+
'Error during RPC call',
|
|
279
|
+
)
|
|
280
|
+
throw new ProtocolError(
|
|
281
|
+
ErrorCode.InternalServerError,
|
|
282
|
+
'Internal server error',
|
|
283
|
+
)
|
|
284
|
+
}
|
|
285
|
+
throw error
|
|
286
|
+
} finally {
|
|
287
|
+
container.dispose().catch((error) => {
|
|
288
|
+
this.application.logger.error(
|
|
289
|
+
{ error, connection },
|
|
290
|
+
"Error during disposing connection's container",
|
|
291
|
+
)
|
|
292
|
+
})
|
|
293
|
+
}
|
|
235
294
|
}
|
|
236
295
|
|
|
237
296
|
async rpc(
|
|
238
297
|
connectionId: string,
|
|
239
298
|
rpc: ProtocolRPC,
|
|
240
|
-
params:
|
|
299
|
+
params: ProtocolRPCOptions = {},
|
|
241
300
|
) {
|
|
242
301
|
const { connection, context, transport } =
|
|
243
|
-
this
|
|
302
|
+
this.#connections.get(connectionId)
|
|
244
303
|
const { calls, format } = context
|
|
245
304
|
const { callId, namespace, procedure, payload } = rpc
|
|
246
305
|
const abortController = new AbortController()
|
|
@@ -248,35 +307,37 @@ export class Protocol {
|
|
|
248
307
|
? AbortSignal.any([params.signal, abortController.signal])
|
|
249
308
|
: abortController.signal
|
|
250
309
|
|
|
251
|
-
|
|
252
|
-
abort: () => abortController.abort(),
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
calls.set(callId, call)
|
|
256
|
-
call.promise.finally(() => calls.delete(callId))
|
|
310
|
+
calls.set(callId, abortController)
|
|
257
311
|
|
|
258
312
|
const callIdEncoded = encodeNumber(callId, 'Uint32')
|
|
259
313
|
const container = context.container.fork(Scope.Call)
|
|
260
314
|
|
|
315
|
+
if (params.provides) {
|
|
316
|
+
for (const [key, value] of params.provides) {
|
|
317
|
+
container.provide(key, value)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
261
321
|
try {
|
|
262
|
-
const response = await this.
|
|
322
|
+
const response = await this.call({
|
|
263
323
|
connection,
|
|
264
324
|
container,
|
|
265
325
|
namespace,
|
|
266
326
|
payload,
|
|
267
327
|
procedure,
|
|
268
328
|
signal,
|
|
329
|
+
metadata: params.metadata,
|
|
269
330
|
})
|
|
270
331
|
|
|
271
332
|
const responseEncoded = format.encoder.encodeRPC(
|
|
272
333
|
{
|
|
273
334
|
callId,
|
|
274
|
-
|
|
335
|
+
result: response.output,
|
|
275
336
|
},
|
|
276
337
|
{
|
|
277
338
|
addStream: (blob) => {
|
|
278
|
-
const
|
|
279
|
-
const stream = this
|
|
339
|
+
const streamId = context.streamId++
|
|
340
|
+
const stream = this.#serverStreams.add(connectionId, streamId, blob)
|
|
280
341
|
stream.on('data', (chunk) => {
|
|
281
342
|
stream.pause()
|
|
282
343
|
const buf = Buffer.from(chunk)
|
|
@@ -284,43 +345,48 @@ export class Protocol {
|
|
|
284
345
|
connection,
|
|
285
346
|
ServerMessageType.ServerStreamPush,
|
|
286
347
|
concat(
|
|
287
|
-
encodeNumber(
|
|
348
|
+
encodeNumber(streamId, 'Uint32'),
|
|
288
349
|
(buf.buffer as ArrayBuffer).slice(
|
|
289
350
|
buf.byteOffset,
|
|
290
351
|
buf.byteOffset + buf.byteLength,
|
|
291
352
|
),
|
|
292
353
|
),
|
|
354
|
+
{ callId, streamId },
|
|
293
355
|
)
|
|
294
356
|
})
|
|
295
357
|
stream.on('error', (err) => {
|
|
296
358
|
transport.send(
|
|
297
359
|
connection,
|
|
298
360
|
ServerMessageType.ServerStreamAbort,
|
|
299
|
-
encodeNumber(
|
|
361
|
+
encodeNumber(streamId, 'Uint32'),
|
|
362
|
+
{ callId, streamId },
|
|
300
363
|
)
|
|
301
364
|
})
|
|
302
365
|
stream.on('end', () => {
|
|
366
|
+
console.log('Stream ended')
|
|
303
367
|
transport.send(
|
|
304
368
|
connection,
|
|
305
369
|
ServerMessageType.ServerStreamEnd,
|
|
306
|
-
encodeNumber(
|
|
370
|
+
encodeNumber(streamId, 'Uint32'),
|
|
371
|
+
{ callId, streamId },
|
|
307
372
|
)
|
|
308
373
|
})
|
|
309
374
|
return stream
|
|
310
375
|
},
|
|
311
376
|
getStream: (id) => {
|
|
312
|
-
return this.
|
|
377
|
+
return this.#serverStreams.get(connectionId, id)
|
|
313
378
|
},
|
|
314
379
|
},
|
|
315
380
|
)
|
|
316
381
|
|
|
317
382
|
if ('subscription' in response) {
|
|
318
383
|
throwError('Unimplemented')
|
|
319
|
-
} else if (
|
|
384
|
+
} else if (isIterableResult(response)) {
|
|
320
385
|
transport.send(
|
|
321
386
|
connection,
|
|
322
387
|
ServerMessageType.RpcStreamResponse,
|
|
323
388
|
responseEncoded,
|
|
389
|
+
{ callId },
|
|
324
390
|
)
|
|
325
391
|
try {
|
|
326
392
|
const ab = new AbortController()
|
|
@@ -330,20 +396,28 @@ export class Protocol {
|
|
|
330
396
|
? response.iterable()
|
|
331
397
|
: response.iterable
|
|
332
398
|
for await (const chunk of iterable) {
|
|
333
|
-
|
|
399
|
+
ab.signal.throwIfAborted()
|
|
334
400
|
const chunkEncoded = format.encoder.encode(chunk)
|
|
335
401
|
transport.send(
|
|
336
402
|
connection,
|
|
337
403
|
ServerMessageType.RpcStreamChunk,
|
|
338
404
|
concat(callIdEncoded, chunkEncoded),
|
|
405
|
+
{ callId },
|
|
339
406
|
)
|
|
340
407
|
}
|
|
408
|
+
transport.send(
|
|
409
|
+
connection,
|
|
410
|
+
ServerMessageType.RpcStreamEnd,
|
|
411
|
+
callIdEncoded,
|
|
412
|
+
{ callId },
|
|
413
|
+
)
|
|
341
414
|
} catch (error) {
|
|
342
415
|
this.application.logger.error(error)
|
|
343
416
|
transport.send(
|
|
344
417
|
connection,
|
|
345
418
|
ServerMessageType.RpcStreamAbort,
|
|
346
419
|
callIdEncoded,
|
|
420
|
+
{ callId },
|
|
347
421
|
)
|
|
348
422
|
} finally {
|
|
349
423
|
context.rpcStreams.delete(callId)
|
|
@@ -354,22 +428,10 @@ export class Protocol {
|
|
|
354
428
|
connection,
|
|
355
429
|
ServerMessageType.RpcResponse,
|
|
356
430
|
responseEncoded,
|
|
431
|
+
{ callId },
|
|
357
432
|
)
|
|
358
433
|
}
|
|
359
434
|
} catch (error) {
|
|
360
|
-
if (error instanceof ProtocolError === false) {
|
|
361
|
-
this.application.logger.error(
|
|
362
|
-
{ error, connection },
|
|
363
|
-
'Error during RPC call',
|
|
364
|
-
)
|
|
365
|
-
|
|
366
|
-
// biome-ignore lint/suspicious/noCatchAssign:
|
|
367
|
-
error = new ProtocolError(
|
|
368
|
-
ErrorCode.InternalServerError,
|
|
369
|
-
'Internal server error',
|
|
370
|
-
)
|
|
371
|
-
}
|
|
372
|
-
|
|
373
435
|
const payload = format.encoder.encodeRPC(
|
|
374
436
|
{ callId, error },
|
|
375
437
|
{
|
|
@@ -381,12 +443,17 @@ export class Protocol {
|
|
|
381
443
|
},
|
|
382
444
|
},
|
|
383
445
|
)
|
|
384
|
-
|
|
446
|
+
|
|
447
|
+
transport.send(connection, ServerMessageType.RpcResponse, payload, {
|
|
448
|
+
error,
|
|
449
|
+
callId,
|
|
450
|
+
})
|
|
385
451
|
} finally {
|
|
452
|
+
calls.delete(callId)
|
|
386
453
|
container.dispose().catch((error) => {
|
|
387
454
|
this.application.logger.error(
|
|
388
455
|
{ error, connection },
|
|
389
|
-
|
|
456
|
+
'Error during disposing connection',
|
|
390
457
|
)
|
|
391
458
|
})
|
|
392
459
|
}
|
|
@@ -395,31 +462,34 @@ export class Protocol {
|
|
|
395
462
|
async rpcRaw(
|
|
396
463
|
connectionId: string,
|
|
397
464
|
buffer: ArrayBuffer,
|
|
398
|
-
params:
|
|
465
|
+
params: ProtocolRPCOptions = {},
|
|
399
466
|
) {
|
|
400
467
|
const { connection, context, transport } =
|
|
401
|
-
this
|
|
468
|
+
this.#connections.get(connectionId)
|
|
402
469
|
|
|
403
470
|
const { format } = context
|
|
404
471
|
|
|
405
472
|
const rpc = format.decoder.decodeRPC(buffer, {
|
|
406
|
-
addStream: (
|
|
407
|
-
|
|
473
|
+
addStream: (streamId, callId, metadata) => {
|
|
474
|
+
return this.#clientStreams.add(
|
|
408
475
|
connectionId,
|
|
409
|
-
|
|
476
|
+
streamId,
|
|
410
477
|
metadata,
|
|
411
478
|
(size) => {
|
|
412
479
|
transport.send(
|
|
413
480
|
connection,
|
|
414
481
|
ServerMessageType.ClientStreamPull,
|
|
415
|
-
concat(
|
|
482
|
+
concat(
|
|
483
|
+
encodeNumber(streamId, 'Uint32'),
|
|
484
|
+
encodeNumber(size, 'Uint32'),
|
|
485
|
+
),
|
|
486
|
+
{ callId, streamId },
|
|
416
487
|
)
|
|
417
488
|
},
|
|
418
489
|
)
|
|
419
|
-
return stream
|
|
420
490
|
},
|
|
421
491
|
getStream: (id) => {
|
|
422
|
-
return this.
|
|
492
|
+
return this.#clientStreams.get(connectionId, id)
|
|
423
493
|
},
|
|
424
494
|
})
|
|
425
495
|
|
|
@@ -427,7 +497,7 @@ export class Protocol {
|
|
|
427
497
|
}
|
|
428
498
|
|
|
429
499
|
rpcAbort(connectionId: string, callId: number) {
|
|
430
|
-
const { context } = this
|
|
500
|
+
const { context } = this.#connections.get(connectionId)
|
|
431
501
|
const call = context.calls.get(callId) ?? throwError('Call not found')
|
|
432
502
|
call.abort()
|
|
433
503
|
}
|
|
@@ -438,7 +508,7 @@ export class Protocol {
|
|
|
438
508
|
}
|
|
439
509
|
|
|
440
510
|
rpcStreamAbort(connectionId: string, callId: number) {
|
|
441
|
-
const { context } = this
|
|
511
|
+
const { context } = this.#connections.get(connectionId)
|
|
442
512
|
const ab =
|
|
443
513
|
context.rpcStreams.get(callId) ?? throwError('Call stream not found')
|
|
444
514
|
ab.abort()
|
|
@@ -452,4 +522,76 @@ export class Protocol {
|
|
|
452
522
|
notify(connectionId: string, event, payload) {
|
|
453
523
|
throw Error('Unimplemented')
|
|
454
524
|
}
|
|
525
|
+
|
|
526
|
+
addConnection(
|
|
527
|
+
transport: ProtocolConnectionTransport,
|
|
528
|
+
options: ConnectionOptions,
|
|
529
|
+
params: ResolveFormatParams,
|
|
530
|
+
) {
|
|
531
|
+
return this.#connections.add(transport, options, params)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
removeConnection(connectionId: string) {
|
|
535
|
+
return this.#connections.remove(connectionId)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
getConnection(connectionId: string) {
|
|
539
|
+
return this.#connections.get(connectionId)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
initializeConnection(connection: Connection) {
|
|
543
|
+
return this.#connections.initialize(connection)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
getClientStream(
|
|
547
|
+
connectionId: string,
|
|
548
|
+
streamId: number,
|
|
549
|
+
): ProtocolClientStream {
|
|
550
|
+
return this.#clientStreams.get(connectionId, streamId)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
addClientStream(
|
|
554
|
+
connectionId: string,
|
|
555
|
+
streamId: number,
|
|
556
|
+
metadata: ProtocolBlobMetadata,
|
|
557
|
+
read: Callback,
|
|
558
|
+
) {
|
|
559
|
+
return this.#clientStreams.add(connectionId, streamId, metadata, read)
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
removeClientStream(connectionId: string, streamId: number) {
|
|
563
|
+
return this.#clientStreams.remove(connectionId, streamId)
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
pushClientStream(connectionId: string, streamId: number, chunk: ArrayBuffer) {
|
|
567
|
+
return this.#clientStreams.push(connectionId, streamId, chunk)
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
endClientStream(connectionId: string, streamId: number) {
|
|
571
|
+
return this.#clientStreams.end(connectionId, streamId)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
abortClientStream(connectionId: string, streamId: number, error?: Error) {
|
|
575
|
+
return this.#clientStreams.abort(connectionId, streamId, error)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
getServerStream(connectionId: string, streamId: number) {
|
|
579
|
+
return this.#serverStreams.get(connectionId, streamId)
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
addServerStream(connectionId: string, streamId: number, blob: ProtocolBlob) {
|
|
583
|
+
return this.#serverStreams.add(connectionId, streamId, blob)
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
removeServerStream(connectionId: string, streamId: number) {
|
|
587
|
+
return this.#serverStreams.remove(connectionId, streamId)
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
pullServerStream(connectionId: string, streamId: number) {
|
|
591
|
+
return this.#serverStreams.pull(connectionId, streamId)
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
abortServerStream(connectionId: string, streamId: number, error?: Error) {
|
|
595
|
+
return this.#serverStreams.abort(connectionId, streamId, error)
|
|
596
|
+
}
|
|
455
597
|
}
|
package/src/server/stream.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
PassThrough,
|
|
3
|
-
Readable,
|
|
4
|
-
type ReadableOptions,
|
|
5
|
-
type TransformOptions,
|
|
6
|
-
} from 'node:stream'
|
|
1
|
+
import { PassThrough, Readable, type ReadableOptions } from 'node:stream'
|
|
7
2
|
import { ReadableStream } from 'node:stream/web'
|
|
8
3
|
import type { ProtocolBlob, ProtocolBlobMetadata } from '../common/blob.ts'
|
|
9
4
|
|
|
10
|
-
export class ProtocolClientStream extends
|
|
5
|
+
export class ProtocolClientStream extends PassThrough {
|
|
11
6
|
constructor(
|
|
12
7
|
public readonly id: number,
|
|
13
8
|
public readonly metadata: ProtocolBlobMetadata,
|
package/src/server/transport.ts
CHANGED
|
@@ -3,8 +3,10 @@ import type { BasePlugin, PluginContext } from '@nmtjs/core'
|
|
|
3
3
|
import type { ServerMessageType } from '../common/enums.ts'
|
|
4
4
|
import type { Connection } from './connection.ts'
|
|
5
5
|
import { kTransportPlugin } from './constants.ts'
|
|
6
|
+
import type { Format } from './format.ts'
|
|
6
7
|
import type { Protocol } from './protocol.ts'
|
|
7
8
|
import type { ProtocolRegistry } from './registry.ts'
|
|
9
|
+
import type { ProtocolSendMetadata } from './types.ts'
|
|
8
10
|
|
|
9
11
|
export interface Transport<T = unknown> {
|
|
10
12
|
start: () => Promise<void>
|
|
@@ -13,12 +15,14 @@ export interface Transport<T = unknown> {
|
|
|
13
15
|
connection: Connection<T>,
|
|
14
16
|
messageType: ServerMessageType,
|
|
15
17
|
buffer: ArrayBuffer,
|
|
16
|
-
|
|
18
|
+
metadata: ProtocolSendMetadata,
|
|
19
|
+
) => any
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
export interface TransportPluginContext extends PluginContext {
|
|
20
23
|
protocol: Protocol
|
|
21
24
|
registry: ProtocolRegistry
|
|
25
|
+
format: Format
|
|
22
26
|
}
|
|
23
27
|
|
|
24
28
|
export interface TransportPlugin<Type = unknown, Options = unknown>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProtocolServerBlobStream } from '../client/stream.ts'
|
|
2
|
+
import type { ProtocolBlob, ProtocolBlobInterface } from '../common/blob.ts'
|
|
3
|
+
import type { ProtocolClientStream } from './stream.ts'
|
|
4
|
+
|
|
5
|
+
export type InputType<T> = T extends ProtocolBlobInterface
|
|
6
|
+
? ProtocolClientStream
|
|
7
|
+
: T extends object
|
|
8
|
+
? { [K in keyof T]: InputType<T[K]> }
|
|
9
|
+
: T
|
|
10
|
+
|
|
11
|
+
export type OutputType<T> = T extends ProtocolBlobInterface
|
|
12
|
+
? ProtocolBlob
|
|
13
|
+
: T extends object
|
|
14
|
+
? { [K in keyof T]: OutputType<T[K]> }
|
|
15
|
+
: T
|
|
16
|
+
|
|
17
|
+
export type ProtocolSendMetadata = {
|
|
18
|
+
streamId?: number
|
|
19
|
+
callId?: number
|
|
20
|
+
error?: any
|
|
21
|
+
}
|
package/src/server/utils.ts
CHANGED
|
@@ -5,15 +5,22 @@ export type ResolveFormatParams = {
|
|
|
5
5
|
acceptType?: string | null
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
export class UnsupportedFormatError extends Error {}
|
|
9
|
+
|
|
10
|
+
export class UnsupportedContentTypeError extends UnsupportedFormatError {}
|
|
11
|
+
|
|
12
|
+
export class UnsupportedAcceptTypeError extends UnsupportedFormatError {}
|
|
13
|
+
|
|
8
14
|
export const getFormat = (
|
|
9
15
|
format: Format,
|
|
10
16
|
{ acceptType, contentType }: ResolveFormatParams,
|
|
11
17
|
) => {
|
|
12
18
|
const encoder = contentType ? format.supportsEncoder(contentType) : undefined
|
|
13
|
-
if (!encoder)
|
|
19
|
+
if (!encoder)
|
|
20
|
+
throw new UnsupportedContentTypeError('Unsupported Content-Type')
|
|
14
21
|
|
|
15
22
|
const decoder = acceptType ? format.supportsDecoder(acceptType) : undefined
|
|
16
|
-
if (!decoder) throw new
|
|
23
|
+
if (!decoder) throw new UnsupportedAcceptTypeError('Unsupported Accept-Type')
|
|
17
24
|
|
|
18
25
|
return {
|
|
19
26
|
encoder,
|