js-rpc2 1.0.2 → 1.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/package.json +1 -1
- package/src/lib.js +86 -53
- package/src/lib.test.js +45 -1
package/package.json
CHANGED
package/src/lib.js
CHANGED
@@ -120,6 +120,19 @@ export async function parseBufferData(buffer, key, iv) {
|
|
120
120
|
return [queue, remain]
|
121
121
|
}
|
122
122
|
|
123
|
+
export function processPackets() {
|
124
|
+
let last = new Uint8Array(0)
|
125
|
+
return new TransformStream({
|
126
|
+
async transform(chunk, controller) {
|
127
|
+
let [queueReceive, remain] = await parseBufferData(Uint8Array_concat([last, chunk]), null, null)
|
128
|
+
last = remain
|
129
|
+
if (queueReceive.length > 0) {
|
130
|
+
let buffer = await buildBufferData(queueReceive, null, null)
|
131
|
+
controller.enqueue(buffer)
|
132
|
+
}
|
133
|
+
}
|
134
|
+
})
|
135
|
+
}
|
123
136
|
|
124
137
|
/**
|
125
138
|
* @param {Uint8Array} buffer
|
@@ -360,26 +373,26 @@ export const RPC_TYPE_ERROR = 0xa07c0f84
|
|
360
373
|
*/
|
361
374
|
|
362
375
|
/**
|
363
|
-
* @typedef {{type:
|
376
|
+
* @typedef {{type:RPC_DATA_ARG_TYPE;data:object}} RPC_DATA_ARG_ITEM
|
364
377
|
* @typedef {{
|
365
378
|
* id:number;
|
366
379
|
* type:RPC_TYPES;
|
367
|
-
* data:{type:
|
380
|
+
* data:{type:RPC_DATA_ARG_TYPE;data:object}[];
|
368
381
|
* }} RPC_DATA
|
369
382
|
*/
|
370
383
|
|
371
|
-
export const
|
372
|
-
export const
|
373
|
-
export const
|
374
|
-
export const
|
375
|
-
export const
|
384
|
+
export const RPC_DATA_ARG_TYPE_OBJECT = 0xa7f68c
|
385
|
+
export const RPC_DATA_ARG_TYPE_FUNCTION = 0x7ff45f
|
386
|
+
export const RPC_DATA_ARG_TYPE_UINT8ARRAY = 0xedb218
|
387
|
+
export const RPC_DATA_ARG_TYPE_UNDEFINED = 0x7f77fe
|
388
|
+
export const RPC_DATA_ARG_TYPE_NULL = 0x5794f9
|
376
389
|
|
377
390
|
/**
|
378
|
-
* @typedef {
|
379
|
-
* |
|
380
|
-
* |
|
381
|
-
* |
|
382
|
-
* |
|
391
|
+
* @typedef {RPC_DATA_ARG_TYPE_OBJECT
|
392
|
+
* |RPC_DATA_ARG_TYPE_FUNCTION
|
393
|
+
* |RPC_DATA_ARG_TYPE_UINT8ARRAY
|
394
|
+
* |RPC_DATA_ARG_TYPE_UNDEFINED
|
395
|
+
* |RPC_DATA_ARG_TYPE_NULL} RPC_DATA_ARG_TYPE
|
383
396
|
*/
|
384
397
|
|
385
398
|
/**
|
@@ -392,23 +405,23 @@ export function buildRpcData(box) {
|
|
392
405
|
buildBufferNumberUInt32LE(box.data.length),
|
393
406
|
]
|
394
407
|
for (const o of box.data) {
|
395
|
-
if (o.type ==
|
408
|
+
if (o.type == RPC_DATA_ARG_TYPE_UINT8ARRAY) {
|
396
409
|
buffers.push(buildBufferNumberUInt32LE(o.type))
|
397
410
|
buffers.push(buildBufferNumberUInt32LE(o.data.length))
|
398
411
|
buffers.push(o.data)
|
399
412
|
}
|
400
|
-
if (o.type ==
|
413
|
+
if (o.type == RPC_DATA_ARG_TYPE_FUNCTION) {
|
401
414
|
buffers.push(buildBufferNumberUInt32LE(o.type))
|
402
415
|
buffers.push(buildBufferSizeString(o.data))
|
403
416
|
}
|
404
|
-
if (o.type ==
|
417
|
+
if (o.type == RPC_DATA_ARG_TYPE_OBJECT) {
|
405
418
|
buffers.push(buildBufferNumberUInt32LE(o.type))
|
406
419
|
buffers.push(buildBufferSizeString(JSON.stringify(o.data)))
|
407
420
|
}
|
408
|
-
if (o.type ==
|
421
|
+
if (o.type == RPC_DATA_ARG_TYPE_UNDEFINED) {
|
409
422
|
buffers.push(buildBufferNumberUInt32LE(o.type))
|
410
423
|
}
|
411
|
-
if (o.type ==
|
424
|
+
if (o.type == RPC_DATA_ARG_TYPE_NULL) {
|
412
425
|
buffers.push(buildBufferNumberUInt32LE(o.type))
|
413
426
|
}
|
414
427
|
}
|
@@ -432,28 +445,28 @@ export function parseRpcData(buffer) {
|
|
432
445
|
for (let i = 0; i < dataLength; i++) {
|
433
446
|
let type = readUInt32LE(buffer, offset)
|
434
447
|
offset += 4
|
435
|
-
if (type ==
|
448
|
+
if (type == RPC_DATA_ARG_TYPE_UINT8ARRAY) {
|
436
449
|
let size = readUInt32LE(buffer, offset)
|
437
450
|
offset += 4
|
438
451
|
let data = buffer.slice(offset, offset + size)
|
439
452
|
offset += size
|
440
453
|
args.push({ type: type, data })
|
441
454
|
}
|
442
|
-
if (type ==
|
455
|
+
if (type == RPC_DATA_ARG_TYPE_FUNCTION) {
|
443
456
|
let o = readBufferSizeString(buffer, offset)
|
444
457
|
offset += o.size
|
445
458
|
args.push({ type: type, data: o.string })
|
446
459
|
}
|
447
|
-
if (type ==
|
460
|
+
if (type == RPC_DATA_ARG_TYPE_OBJECT) {
|
448
461
|
let o = readBufferSizeString(buffer, offset)
|
449
462
|
offset += o.size
|
450
463
|
let data = o.string
|
451
464
|
args.push({ type: type, data: JSON.parse(data) })
|
452
465
|
}
|
453
|
-
if (type ==
|
466
|
+
if (type == RPC_DATA_ARG_TYPE_UNDEFINED) {
|
454
467
|
args.push({ type: type, data: undefined })
|
455
468
|
}
|
456
|
-
if (type ==
|
469
|
+
if (type == RPC_DATA_ARG_TYPE_NULL) {
|
457
470
|
args.push({ type: type, data: null })
|
458
471
|
}
|
459
472
|
}
|
@@ -469,23 +482,23 @@ export function buildRpcItemData(items) {
|
|
469
482
|
/** @type{RPC_DATA_ARG_ITEM[]} */
|
470
483
|
let arr = []
|
471
484
|
for (const item of items) {
|
472
|
-
/** @type{
|
485
|
+
/** @type{RPC_DATA_ARG_TYPE} */
|
473
486
|
let type = null
|
474
487
|
let data = null
|
475
488
|
if (item === undefined) {
|
476
|
-
type =
|
489
|
+
type = RPC_DATA_ARG_TYPE_UNDEFINED
|
477
490
|
data = item
|
478
491
|
} else if (item === null) {
|
479
|
-
type =
|
492
|
+
type = RPC_DATA_ARG_TYPE_NULL
|
480
493
|
data = item
|
481
494
|
} else if (item instanceof Uint8Array) {
|
482
|
-
type =
|
495
|
+
type = RPC_DATA_ARG_TYPE_UINT8ARRAY
|
483
496
|
data = item
|
484
497
|
} else if (typeof item == 'function') {
|
485
|
-
type =
|
498
|
+
type = RPC_DATA_ARG_TYPE_FUNCTION
|
486
499
|
data = item()
|
487
500
|
} else {
|
488
|
-
type =
|
501
|
+
type = RPC_DATA_ARG_TYPE_OBJECT
|
489
502
|
data = JSON.stringify(item)
|
490
503
|
}
|
491
504
|
arr.push({ type, data })
|
@@ -501,19 +514,19 @@ export function parseRpcItemData(array) {
|
|
501
514
|
let items = []
|
502
515
|
for (let i = 0; i < array.length; i++) {
|
503
516
|
const o = array[i]
|
504
|
-
if (o.type ==
|
517
|
+
if (o.type == RPC_DATA_ARG_TYPE_FUNCTION) {
|
505
518
|
o.data = o.data
|
506
519
|
}
|
507
|
-
if (o.type ==
|
520
|
+
if (o.type == RPC_DATA_ARG_TYPE_NULL) {
|
508
521
|
o.data = null
|
509
522
|
}
|
510
|
-
if (o.type ==
|
523
|
+
if (o.type == RPC_DATA_ARG_TYPE_UNDEFINED) {
|
511
524
|
o.data = undefined
|
512
525
|
}
|
513
|
-
if (o.type ==
|
526
|
+
if (o.type == RPC_DATA_ARG_TYPE_UINT8ARRAY) {
|
514
527
|
o.data = o.data
|
515
528
|
}
|
516
|
-
if (o.type ==
|
529
|
+
if (o.type == RPC_DATA_ARG_TYPE_OBJECT) {
|
517
530
|
o.data = JSON.parse(o.data)
|
518
531
|
}
|
519
532
|
items.push(o)
|
@@ -539,7 +552,7 @@ export async function rpcRunServerDecodeBuffer(extension, writer, buffer) {
|
|
539
552
|
let params = []
|
540
553
|
for (let i = 0; i < args.length; i++) {
|
541
554
|
const p = args[i]
|
542
|
-
if (p.type ==
|
555
|
+
if (p.type == RPC_DATA_ARG_TYPE_FUNCTION) {
|
543
556
|
const callback = async (/** @type {any[]} */ ...args) => {
|
544
557
|
/** @type{RPC_DATA} */
|
545
558
|
let box = { id: p.data, type: RPC_TYPE_CALLBACK, data: buildRpcItemData(args), }
|
@@ -561,7 +574,7 @@ export async function rpcRunServerDecodeBuffer(extension, writer, buffer) {
|
|
561
574
|
box = {
|
562
575
|
id: dataId,
|
563
576
|
type: RPC_TYPE_ERROR,
|
564
|
-
data: buildRpcItemData([
|
577
|
+
data: buildRpcItemData([error.message, error.stack]),
|
565
578
|
}
|
566
579
|
}
|
567
580
|
await writer.write(buildRpcData(box))
|
@@ -580,7 +593,11 @@ export function createRPCProxy(apiInvoke) {
|
|
580
593
|
}
|
581
594
|
proxy = new Proxy(Function, {
|
582
595
|
async apply(_target, _thisArg, argArray) {
|
583
|
-
|
596
|
+
try {
|
597
|
+
return await apiInvoke(String(p), argArray)
|
598
|
+
} catch (error) {
|
599
|
+
throw new Error(error.message, { cause: error })
|
600
|
+
}
|
584
601
|
}
|
585
602
|
})
|
586
603
|
map.set(p, proxy)
|
@@ -627,13 +644,24 @@ export function createRpcServerHelper(param) {
|
|
627
644
|
* writable: WritableStream<Uint8Array>;
|
628
645
|
* readable: ReadableStream<Uint8Array>;
|
629
646
|
* apiInvoke: (fnName: string, args: object[]) => Promise<object>;
|
630
|
-
*
|
631
|
-
* readable: ReadableStream<Uint8Array<ArrayBufferLike>>;
|
632
|
-
* witeable: WritableStream<Uint8Array<ArrayBufferLike>>;
|
633
|
-
* }
|
647
|
+
* reject: (error:object)=>void;
|
634
648
|
* }} RPC_HELPER_CLIENT
|
635
649
|
*/
|
636
650
|
|
651
|
+
class RPCError extends Error {
|
652
|
+
/**
|
653
|
+
* @param {string} message
|
654
|
+
* @param {string} stack
|
655
|
+
* @param {ErrorOptions} [option]
|
656
|
+
*/
|
657
|
+
constructor(message, stack, option) {
|
658
|
+
super(message, option)
|
659
|
+
if (stack) {
|
660
|
+
this.stack = stack
|
661
|
+
}
|
662
|
+
}
|
663
|
+
}
|
664
|
+
|
637
665
|
/**
|
638
666
|
* @param {{ rpcKey: string; }} param
|
639
667
|
*/
|
@@ -656,7 +684,7 @@ export function createRpcClientHelper(param) {
|
|
656
684
|
if (callbackFunctionMap.has(data.id)) {
|
657
685
|
let o = callbackFunctionMap.get(data.id)
|
658
686
|
if (data.type == RPC_TYPE_ERROR) {
|
659
|
-
o.promise.reject(new
|
687
|
+
o.promise.reject(new RPCError(items.at(0).data, items.at(1).data))
|
660
688
|
}
|
661
689
|
if (data.type == RPC_TYPE_RETURN) {
|
662
690
|
callbackFunctionMap.delete(data.id)
|
@@ -714,15 +742,18 @@ export function createRpcClientHelper(param) {
|
|
714
742
|
}
|
715
743
|
}
|
716
744
|
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
745
|
+
/**
|
746
|
+
* @param {object} error
|
747
|
+
*/
|
748
|
+
function reject(error) {
|
749
|
+
callbackFunctionMap.forEach((o) => {
|
750
|
+
o.promise?.reject(error)
|
751
|
+
})
|
752
|
+
callbackFunctionMap.clear()
|
722
753
|
}
|
723
754
|
|
724
755
|
/** @type{RPC_HELPER_CLIENT} */
|
725
|
-
let ret = { writable: decode.writable, readable: encode.readable, apiInvoke,
|
756
|
+
let ret = { writable: decode.writable, readable: encode.readable, apiInvoke, reject }
|
726
757
|
return ret
|
727
758
|
}
|
728
759
|
|
@@ -810,15 +841,17 @@ export function createRpcClientHttp(param) {
|
|
810
841
|
if (param.intercept) {
|
811
842
|
param.intercept(res)
|
812
843
|
}
|
813
|
-
|
814
|
-
res.body.pipeTo(transform.witeable).catch(e => console.error(e))
|
815
|
-
transform.readable.pipeTo(new WritableStream({
|
844
|
+
res.body.pipeThrough(processPackets()).pipeTo(new WritableStream({
|
816
845
|
async write(chunk) {
|
817
846
|
await writer.write(chunk)
|
818
847
|
}
|
819
|
-
})).catch((e) =>
|
820
|
-
|
848
|
+
})).catch((e) => {
|
849
|
+
helper.reject(e)
|
850
|
+
})
|
851
|
+
}).catch(e => {
|
852
|
+
helper.reject(e)
|
853
|
+
})
|
821
854
|
}
|
822
|
-
})).catch((err) =>
|
855
|
+
})).catch((err) => helper.reject(err))
|
823
856
|
return createRPCProxy(helper.apiInvoke)
|
824
857
|
}
|
package/src/lib.test.js
CHANGED
@@ -282,4 +282,48 @@ export async function runWithAbortController(func) {
|
|
282
282
|
await func(ac)
|
283
283
|
await sleep(1000)
|
284
284
|
} finally { ac.abort() }
|
285
|
-
}
|
285
|
+
}
|
286
|
+
|
287
|
+
|
288
|
+
test('error-stack', async () => {
|
289
|
+
// node --test-name-pattern="^error-stack$" src/lib.test.js
|
290
|
+
|
291
|
+
// server
|
292
|
+
const app = new Koa()
|
293
|
+
const router = new Router()
|
294
|
+
app.use(router.routes())
|
295
|
+
app.use(router.allowedMethods())
|
296
|
+
let server = createServer(app.callback()).listen(9000)
|
297
|
+
|
298
|
+
class RpcApi {
|
299
|
+
async hello() {
|
300
|
+
new URL('/')
|
301
|
+
}
|
302
|
+
}
|
303
|
+
|
304
|
+
const extension = new RpcApi()
|
305
|
+
|
306
|
+
createRpcServerKoaRouter({
|
307
|
+
path: '/rpc/abc',
|
308
|
+
router: router,
|
309
|
+
extension: extension,
|
310
|
+
})
|
311
|
+
|
312
|
+
|
313
|
+
// client
|
314
|
+
|
315
|
+
/** @type{RpcApi} */
|
316
|
+
const rpc = createRpcClientHttp({
|
317
|
+
// url: `/rpc/abc`, // in same site html page
|
318
|
+
url: `http://127.0.0.1:9000/rpc/abc`, // others
|
319
|
+
})
|
320
|
+
|
321
|
+
try {
|
322
|
+
let ret = await rpc.hello()
|
323
|
+
console.info(ret)
|
324
|
+
} catch (error) {
|
325
|
+
console.error(error)
|
326
|
+
}
|
327
|
+
server.close()
|
328
|
+
|
329
|
+
})
|