js-rpc2 2.3.0 → 2.3.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-rpc2",
3
- "version": "2.3.0",
3
+ "version": "2.3.2",
4
4
  "description": "js web websocket http rpc",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/src/lib.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Packr } from 'msgpackr'
2
2
 
3
3
  /**
4
- * @import { CALLBACK_ITEM, ExtensionApi, RPC_DATA, RPC_DATA_ARG_ITEM } from "./types.js"
4
+ * @import { CALLBACK_ITEM, RPC_DATA, RPC_DATA_ARG_ITEM } from "./types.js"
5
5
  */
6
6
 
7
7
  const JS_RPC_WITH_CRYPTO = true
@@ -407,8 +407,7 @@ export function buildRpcItemData(items) {
407
407
  }
408
408
 
409
409
  /**
410
- * @template T
411
- * @param {ExtensionApi<T>} extension
410
+ * @param {object} extension
412
411
  * @param {WritableStreamDefaultWriter<Uint8Array<ArrayBuffer>>} writer
413
412
  * @param {Uint8Array<ArrayBuffer>} buffer
414
413
  * @param {(msg:string)=>void} logger
@@ -501,13 +500,11 @@ export function createRPCProxy(apiInvoke) {
501
500
  */
502
501
 
503
502
  /**
504
- * @template T
505
503
  * @param {{
506
504
  * rpcKey: string;
507
- * extension: ExtensionApi<T>;
505
+ * extension: object;
508
506
  * logger?: (msg:string)=>void;
509
507
  * async?: boolean;
510
- * context?:any;
511
508
  * }} param
512
509
  */
513
510
  export function createRpcServerHelper(param) {
@@ -517,8 +514,6 @@ export function createRpcServerHelper(param) {
517
514
  let writer = encode.writable.getWriter()
518
515
  decode.readable.pipeTo(new WritableStream({
519
516
  async write(buffer) {
520
- let asyncLocalStorage = param.extension.asyncLocalStorage
521
- asyncLocalStorage?.enterWith(param.context)
522
517
  if (param.async) {
523
518
  rpcRunServerDecodeBuffer(param.extension, writer, buffer, param.logger).catch(console.error)
524
519
  } else {
@@ -763,11 +758,55 @@ export function createRpcClientHttp(param) {
763
758
  }
764
759
 
765
760
  /**
766
- * @template T
761
+ * @param {{
762
+ * url:string;
763
+ * rpcKey?:string;
764
+ * signal?:AbortSignal;
765
+ * intercept?:(res:Response)=>void;
766
+ * }} param
767
+ */
768
+ export function _testCreateRpcClientHttp(param) {
769
+ let helper = createRpcClientHelper({ rpcKey: param.rpcKey })
770
+ let writer = helper.writable.getWriter()
771
+ helper.readable.pipeTo(new WritableStream({
772
+ write(chunk) {
773
+ fetch(param.url, {
774
+ method: 'POST',
775
+ signal: param.signal,
776
+ // @ts-ignore
777
+ duplex: 'half',
778
+ body: new ReadableStream({
779
+ async pull(controller) {
780
+ controller.enqueue(chunk.slice(0, 10))
781
+ await sleep(1000)
782
+ controller.enqueue(chunk.slice(10))
783
+ controller.close()
784
+ }
785
+ }),
786
+ }).then(res => {
787
+ if (param.intercept) {
788
+ param.intercept(res)
789
+ }
790
+ res.body.pipeThrough(processPackets()).pipeTo(new WritableStream({
791
+ async write(chunk) {
792
+ await writer.write(chunk)
793
+ }
794
+ })).catch((e) => {
795
+ helper.reject(e)
796
+ })
797
+ }).catch(e => {
798
+ helper.reject(e)
799
+ })
800
+ }
801
+ })).catch((err) => helper.reject(err))
802
+ return createRPCProxy(helper.apiInvoke)
803
+ }
804
+
805
+ /**
767
806
  * @param {{
768
807
  * port:MessagePort;
769
808
  * rpcKey:string;
770
- * extension: ExtensionApi<T>;
809
+ * extension: object;
771
810
  * logger?:(msg:string)=>void;
772
811
  * }} param
773
812
  */
@@ -789,11 +828,10 @@ export function createRpcServerMessagePort(param) {
789
828
 
790
829
  /**
791
830
  * @import {Electron} from './types.js'
792
- * @template T
793
831
  * @param {{
794
832
  * port:Electron.MessagePortMain;
795
833
  * rpcKey:string;
796
- * extension: ExtensionApi<T>;
834
+ * extension: object;
797
835
  * logger?:(msg:string)=>void;
798
836
  * }} param
799
837
  */
@@ -835,34 +873,36 @@ export function createRpcClientMessagePort(param) {
835
873
 
836
874
  /**
837
875
  * @param {string} text
838
- * @returns
839
876
  */
840
877
  export function base64decode(text) {
841
- const _tidyB64 = (/** @type {string} */ s) => s.replace(/[^A-Za-z0-9\+\/]/g, '')
842
- const _unURI = (/** @type {string} */ a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'))
843
- text = _unURI(text)
844
- return new Uint8Array(globalThis.atob(text).split('').map(c => c.charCodeAt(0)))
878
+ const binaryString = atob(text)
879
+ const len = binaryString.length
880
+ const bytes = new Uint8Array(len)
881
+ for (let i = 0; i < len; i++) {
882
+ bytes[i] = binaryString.charCodeAt(i)
883
+ }
884
+ return bytes
845
885
  }
846
886
 
847
887
  /**
848
888
  * @param {Uint8Array<ArrayBuffer>} buffer
849
- * @returns
850
889
  */
851
- export function base64encode(buffer, urlsafe = false) {
852
- let b64 = globalThis.btoa(String.fromCharCode(...new Uint8Array(buffer)))
853
- if (urlsafe) {
854
- b64 = b64.replace(/=/g, '').replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_')
890
+ export function base64encode(buffer) {
891
+ const CHUNK_SZ = 0x8000
892
+ const chars = []
893
+ for (let i = 0; i < buffer.length; i += CHUNK_SZ) {
894
+ const chunk = buffer.subarray(i, i + CHUNK_SZ)
895
+ chars.push(String.fromCharCode.apply(null, chunk))
855
896
  }
856
- return b64
897
+ return btoa(chars.join(''))
857
898
  }
858
899
 
859
900
  /**
860
901
  * @import {chrome as Chrome} from './types.js'
861
- * @template T
862
902
  * @param {{
863
903
  * chrome:Chrome;
864
904
  * key: string;
865
- * extension: ExtensionApi<T>
905
+ * extension: {messageSender:Chrome.runtime.MessageSender;};
866
906
  * logger?:(msg:string)=>void;
867
907
  * }} param
868
908
  */
@@ -872,6 +912,7 @@ export function createRpcServerChromeExtensions(param) {
872
912
  chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
873
913
  if (request.action === param.key) {
874
914
  let tabId = sender.tab?.id
915
+ param.extension.messageSender = sender
875
916
  let { keyServer, keyClient } = request.data
876
917
  let helper = createRpcServerHelper({
877
918
  rpcKey: '', extension: param.extension, async: true, logger: param.logger,
package/src/lib.test.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { test } from 'node:test'
2
2
  import { deepStrictEqual, fail, ok, strictEqual } from 'node:assert'
3
- import { createRpcClientHttp, createRpcClientWebSocket, sleep, Uint8Array_from } from './lib.js'
3
+ import { _testCreateRpcClientHttp, createRpcClientHttp, createRpcClientWebSocket, sleep, Uint8Array_from } from './lib.js'
4
4
  import { createServer } from 'node:http'
5
5
  import { WebSocketServer } from 'ws'
6
6
  import Koa from 'koa'
@@ -292,6 +292,9 @@ test('测试RPC调用-KoaRouter-AsyncLocalStorage', async () => {
292
292
  hello: async function (/** @type {string} */ name) {
293
293
  let ctx = this.asyncLocalStorage.getStore()
294
294
  strictEqual(ctx.path, '/abc')
295
+ await sleep(100)
296
+ ctx = this.asyncLocalStorage.getStore()
297
+ strictEqual(ctx.path, '/abc')
295
298
  return `hello ${name}`
296
299
  },
297
300
  }
@@ -320,7 +323,7 @@ test('测试RPC调用-KoaRouter-AsyncLocalStorage', async () => {
320
323
  await sleep(100)
321
324
 
322
325
  /** @type{typeof extension} */
323
- let client = createRpcClientHttp({
326
+ let client = _testCreateRpcClientHttp({
324
327
  url: `http://127.0.0.1:9000/abc`,
325
328
  rpcKey: 'abc',
326
329
  signal: ac.signal,
package/src/server.js CHANGED
@@ -3,8 +3,8 @@ import { createRpcServerHelper } from "./lib.js"
3
3
  import { AsyncLocalStorage } from "node:async_hooks"
4
4
 
5
5
  /**
6
+ * @import { IncomingMessage } from "node:http"
6
7
  * @import {WebSocketServer} from 'ws'
7
- * @import {ExtensionApi} from './types.js'
8
8
  */
9
9
 
10
10
  export { createRpcServerHelper }
@@ -19,14 +19,13 @@ export { createRpcServerHelper }
19
19
  * path: string;
20
20
  * wss: WebSocketServer;
21
21
  * rpcKey:string;
22
- * extension: ExtensionApi<T>;
22
+ * extension: {asyncLocalStorage:AsyncLocalStorage<IncomingMessage>;};
23
23
  * logger?:(msg:string)=>void;
24
24
  * }} param
25
25
  */
26
26
  export function createRpcServerWebSocket(param) {
27
- if (!param.extension.asyncLocalStorage) {
28
- param.extension.asyncLocalStorage = new AsyncLocalStorage()
29
- }
27
+ let asyncLocalStorage = param.extension.asyncLocalStorage
28
+ if (!asyncLocalStorage) { asyncLocalStorage = new AsyncLocalStorage() }
30
29
  param.wss.on('connection', (ws, request) => {
31
30
  let url = request.url
32
31
  if (url != param.path) {
@@ -47,6 +46,7 @@ export function createRpcServerWebSocket(param) {
47
46
  if (writer.desiredSize <= 0) {
48
47
  ws.pause()
49
48
  }
49
+ asyncLocalStorage.enterWith(request)
50
50
  await writer.write(buffer)
51
51
  ws.resume()
52
52
  })
@@ -60,23 +60,27 @@ export function createRpcServerWebSocket(param) {
60
60
  }
61
61
 
62
62
  /**
63
- * @template T
64
63
  * @param {{
65
64
  * path: string;
66
65
  * router: Router<any, {}>;
67
66
  * rpcKey?:string;
68
67
  * logger?:(msg:string)=>void;
69
- * extension: ExtensionApi<T>;
68
+ * extension: {asyncLocalStorage:AsyncLocalStorage;};
70
69
  * }} param
71
70
  */
72
71
  export function createRpcServerKoaRouter(param) {
73
- if (!param.extension.asyncLocalStorage) {
74
- param.extension.asyncLocalStorage = new AsyncLocalStorage()
75
- }
72
+ let asyncLocalStorage = param.extension.asyncLocalStorage
73
+ if (!asyncLocalStorage) { asyncLocalStorage = new AsyncLocalStorage() }
76
74
  param.router.post(param.path, async (ctx) => {
77
- let helper = createRpcServerHelper({ rpcKey: param.rpcKey, extension: param.extension, logger: param.logger, context: ctx })
75
+ asyncLocalStorage.enterWith(ctx)
76
+ let helper = createRpcServerHelper({ rpcKey: param.rpcKey, extension: param.extension, logger: param.logger })
78
77
  let a = Readable.toWeb(ctx.req)
79
- await a.pipeTo(helper.writable)
78
+ await a.pipeThrough(new TransformStream({
79
+ async transform(chunk, controller) {
80
+ asyncLocalStorage.enterWith(ctx)
81
+ controller.enqueue(chunk)
82
+ }
83
+ })).pipeTo(helper.writable)
80
84
  ctx.status = 200
81
85
  ctx.response.set({
82
86
  'Connection': 'keep-alive',
package/src/types.ts CHANGED
@@ -1,8 +1,3 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
-
3
- export type ExtensionApi<T> = { asyncLocalStorage?: AsyncLocalStorage<T> } & object;
4
-
5
-
6
1
  export type RPC_TYPE_CALL = 0xdf68f4cb
7
2
  export type RPC_TYPE_RETURN = 0x68b17581
8
3
  export type RPC_TYPE_CALLBACK = 0x8d65e5cc