js-rpc2 2.4.1 → 2.4.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/README.md CHANGED
@@ -338,7 +338,7 @@ ipcMain.on('port', (event) => {
338
338
  import { ipcRenderer } from 'electron/renderer'
339
339
 
340
340
  window.onmessage = (/** @type {MessageEvent} */ event) => {
341
- if (event.origin == location.origin && event.data != 'port') {
341
+ if (event.isTrusted && event.data == 'port') {
342
342
  ipcRenderer.postMessage('port', null, [event.ports[0]])
343
343
  }
344
344
  }
@@ -1,133 +1,133 @@
1
- # Chrome Extensions RPC 通信使用说明
2
-
3
- ## 概述
4
-
5
- 本项目使用 `js-rpc2` 库实现在 Chrome 扩展各组件间的远程过程调用(RPC)通信,支持在 popup、content scripts 和 background 之间进行双向通信。
6
-
7
- ## 项目结构
8
-
9
- ### 组件说明
10
-
11
- - **background.js**: 后台脚本,提供核心服务接口
12
- - **content_scripts.js**: 内容脚本,运行在网页上下文中,可作为通信中继
13
- - **popup.js**: 扩展弹窗界面,用户交互入口
14
-
15
- ## 核心实现
16
-
17
- ### Background 脚本
18
-
19
- ```javascript
20
- import {createRpcServerChromeExtensions} from 'js-rpc2/src/lib.js'
21
-
22
- export class RpcBackgroundApi {
23
- /**
24
- * 带回调的示例方法
25
- * @param {(progress: string, date: Date) => Promise<void>} cb - 回调函数
26
- */
27
- async callback(cb) {
28
- for (let i = 0; i < 10; i++) {
29
- await sleep(1000)
30
- await cb(`from background index is ${i}`, new Date())
31
- }
32
- return 'over!'
33
- }
34
- }
35
-
36
- // 创建RPC服务端点
37
- createRpcServerChromeExtensions({
38
- chrome,
39
- key: 'rpc-popup->background',
40
- extension: new RpcBackgroundApi()
41
- })
42
-
43
- createRpcServerChromeExtensions({
44
- chrome,
45
- key: 'rpc-content-scripts->background',
46
- extension: new RpcBackgroundApi()
47
- })
48
- ```
49
-
50
- ### Content Scripts 脚本
51
-
52
- ```javascript
53
- import {createRpcServerChromeExtensions, createRpcClientChromeExtensions} from 'js-rpc2/src/lib.js'
54
-
55
- export class RpcContentScriptsApi {
56
- async callBackgroundWithCallback(name, callback) {
57
- return await rpcContentScriptBackground.callback(callback)
58
- }
59
- }
60
-
61
- // 创建RPC服务端点供popup调用
62
- createRpcServerChromeExtensions({
63
- chrome,
64
- key: 'rpc-popup->content-script',
65
- extension: new RpcContentScriptsApi()
66
- })
67
-
68
- // 创建RPC客户端连接到background
69
- export const rpcContentScriptBackground = createRpcClientChromeExtensions({
70
- chrome,
71
- key: 'rpc-content-scripts->background'
72
- })
73
- ```
74
-
75
- ### Popup 脚本
76
-
77
- ```javascript
78
- import {createRpcClientChromeExtensions} from 'js-rpc2/src/lib.js'
79
-
80
- // 获取当前活动标签页
81
- const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
82
-
83
- // 创建RPC客户端
84
- export const rpcPopupContentScripts = createRpcClientChromeExtensions({
85
- chrome,
86
- key: 'rpc-popup->content-script',
87
- tabId: tab.id
88
- })
89
-
90
- export const rpcPopupBackground = createRpcClientChromeExtensions({
91
- chrome,
92
- key: 'rpc-popup->background'
93
- })
94
-
95
- // 使用示例
96
- let resp = await rpcPopupContentScripts.callBackgroundWithCallback("name", async (progress, date) => {
97
- console.info('at popup callback', progress, date)
98
- })
99
- console.info("over!", resp)
100
-
101
- let resp2 = await rpcPopupBackground.callback(async (progress, date) => {
102
- console.info('at popup callback', progress, date)
103
- })
104
- console.info("over!", resp2)
105
- ```
106
-
107
- ## 通信模式
108
-
109
- ### 直接通信
110
- Popup → Background
111
- ```javascript
112
- rpcPopupBackground.callback(callbackFunction)
113
- ```
114
-
115
- ### 间接通信
116
- Popup → Content Script → Background
117
- ```javascript
118
- rpcPopupContentScripts.callBackgroundWithCallback(name, callbackFunction)
119
- ```
120
-
121
- ## 使用方法
122
-
123
- 1. 在各组件中导入相应的 RPC 创建函数
124
- 2. 定义服务接口类
125
- 3. 使用 `createRpcServerChromeExtensions` 创建服务端点
126
- 4. 使用 `createRpcClientChromeExtensions` 创建客户端连接
127
- 5. 通过客户端实例调用远程方法
128
-
129
- ## 注意事项
130
-
131
- - 确保 manifest.json 中正确配置了各组件的权限和通信策略
132
- - 注意处理异步回调的生命周期管理
1
+ # Chrome Extensions RPC 通信使用说明
2
+
3
+ ## 概述
4
+
5
+ 本项目使用 `js-rpc2` 库实现在 Chrome 扩展各组件间的远程过程调用(RPC)通信,支持在 popup、content scripts 和 background 之间进行双向通信。
6
+
7
+ ## 项目结构
8
+
9
+ ### 组件说明
10
+
11
+ - **background.js**: 后台脚本,提供核心服务接口
12
+ - **content_scripts.js**: 内容脚本,运行在网页上下文中,可作为通信中继
13
+ - **popup.js**: 扩展弹窗界面,用户交互入口
14
+
15
+ ## 核心实现
16
+
17
+ ### Background 脚本
18
+
19
+ ```javascript
20
+ import {createRpcServerChromeExtensions} from 'js-rpc2/src/lib.js'
21
+
22
+ export class RpcBackgroundApi {
23
+ /**
24
+ * 带回调的示例方法
25
+ * @param {(progress: string, date: Date) => Promise<void>} cb - 回调函数
26
+ */
27
+ async callback(cb) {
28
+ for (let i = 0; i < 10; i++) {
29
+ await sleep(1000)
30
+ await cb(`from background index is ${i}`, new Date())
31
+ }
32
+ return 'over!'
33
+ }
34
+ }
35
+
36
+ // 创建RPC服务端点
37
+ createRpcServerChromeExtensions({
38
+ chrome,
39
+ key: 'rpc-popup->background',
40
+ extension: new RpcBackgroundApi()
41
+ })
42
+
43
+ createRpcServerChromeExtensions({
44
+ chrome,
45
+ key: 'rpc-content-scripts->background',
46
+ extension: new RpcBackgroundApi()
47
+ })
48
+ ```
49
+
50
+ ### Content Scripts 脚本
51
+
52
+ ```javascript
53
+ import {createRpcServerChromeExtensions, createRpcClientChromeExtensions} from 'js-rpc2/src/lib.js'
54
+
55
+ export class RpcContentScriptsApi {
56
+ async callBackgroundWithCallback(name, callback) {
57
+ return await rpcContentScriptBackground.callback(callback)
58
+ }
59
+ }
60
+
61
+ // 创建RPC服务端点供popup调用
62
+ createRpcServerChromeExtensions({
63
+ chrome,
64
+ key: 'rpc-popup->content-script',
65
+ extension: new RpcContentScriptsApi()
66
+ })
67
+
68
+ // 创建RPC客户端连接到background
69
+ export const rpcContentScriptBackground = createRpcClientChromeExtensions({
70
+ chrome,
71
+ key: 'rpc-content-scripts->background'
72
+ })
73
+ ```
74
+
75
+ ### Popup 脚本
76
+
77
+ ```javascript
78
+ import {createRpcClientChromeExtensions} from 'js-rpc2/src/lib.js'
79
+
80
+ // 获取当前活动标签页
81
+ const [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
82
+
83
+ // 创建RPC客户端
84
+ export const rpcPopupContentScripts = createRpcClientChromeExtensions({
85
+ chrome,
86
+ key: 'rpc-popup->content-script',
87
+ tabId: tab.id
88
+ })
89
+
90
+ export const rpcPopupBackground = createRpcClientChromeExtensions({
91
+ chrome,
92
+ key: 'rpc-popup->background'
93
+ })
94
+
95
+ // 使用示例
96
+ let resp = await rpcPopupContentScripts.callBackgroundWithCallback("name", async (progress, date) => {
97
+ console.info('at popup callback', progress, date)
98
+ })
99
+ console.info("over!", resp)
100
+
101
+ let resp2 = await rpcPopupBackground.callback(async (progress, date) => {
102
+ console.info('at popup callback', progress, date)
103
+ })
104
+ console.info("over!", resp2)
105
+ ```
106
+
107
+ ## 通信模式
108
+
109
+ ### 直接通信
110
+ Popup → Background
111
+ ```javascript
112
+ rpcPopupBackground.callback(callbackFunction)
113
+ ```
114
+
115
+ ### 间接通信
116
+ Popup → Content Script → Background
117
+ ```javascript
118
+ rpcPopupContentScripts.callBackgroundWithCallback(name, callbackFunction)
119
+ ```
120
+
121
+ ## 使用方法
122
+
123
+ 1. 在各组件中导入相应的 RPC 创建函数
124
+ 2. 定义服务接口类
125
+ 3. 使用 `createRpcServerChromeExtensions` 创建服务端点
126
+ 4. 使用 `createRpcClientChromeExtensions` 创建客户端连接
127
+ 5. 通过客户端实例调用远程方法
128
+
129
+ ## 注意事项
130
+
131
+ - 确保 manifest.json 中正确配置了各组件的权限和通信策略
132
+ - 注意处理异步回调的生命周期管理
133
133
  - 建议为所有 RPC 接口添加适当的错误处理机制
package/doc/electron.md CHANGED
@@ -1,138 +1,138 @@
1
- # Electron RPC 通信使用说明
2
-
3
- ## 概述
4
-
5
- 本文档介绍如何在 Electron 应用中使用 `js-rpc2` 库实现主进程与渲染进程之间的 RPC 通信。通过 MessagePort 机制,实现跨进程的远程方法调用。
6
-
7
- ## 项目结构
8
-
9
- ### 组件说明
10
-
11
- - **main.js**: Electron 主进程,提供核心服务接口
12
- - **preload.js**: 预加载脚本,建立主进程与渲染进程的通信桥梁
13
- - **renderer.js**: 渲染进程,运行在浏览器环境中
14
- - **usage.js**: 使用示例,展示如何调用 RPC 方法
15
-
16
- ## 核心实现
17
-
18
- ### 主进程 (main.js)
19
-
20
- ```javascript
21
- import { ipcMain } from 'electron'
22
- import { createRpcServerElectronMessagePort } from 'js-rpc2/src/lib.js'
23
-
24
- class AppApi {
25
- asyncLocalStorage = new AsyncLocalStorage()
26
-
27
- async hello(param) {
28
- return 'wertyuioiuytre ' + param
29
- }
30
- }
31
-
32
- // 监听来自渲染进程的 port 消息
33
- ipcMain.on('port', (event) => {
34
- const port = event.ports[0]
35
- // 创建 RPC 服务端点
36
- createRpcServerElectronMessagePort({
37
- port,
38
- rpcKey: '',
39
- extension: new AppApi()
40
- })
41
- port.start()
42
- })
43
- ```
44
-
45
- ### 预加载脚本 (preload.js)
46
-
47
- ```javascript
48
- import { ipcRenderer } from 'electron/renderer'
49
-
50
- // 监听来自渲染进程的消息
51
- window.onmessage = (/** @type {MessageEvent} */ event) => {
52
- // 验证消息来源并转发给主进程
53
- if (event.origin == location.origin && event.data != 'port') {
54
- ipcRenderer.postMessage('port', null, [event.ports[0]])
55
- }
56
- }
57
- ```
58
-
59
- ### 渲染进程 (renderer.js)
60
-
61
- ```javascript
62
- import { createRpcClientMessagePort } from 'js-rpc2/src/lib.js'
63
-
64
- // 创建消息通道
65
- const channel = new MessageChannel();
66
-
67
- // 向主进程发送端口
68
- window.postMessage("port", location.origin, [channel.port1]);
69
-
70
- // 创建 RPC 客户端
71
- let rpc = createRpcClientMessagePort({
72
- port: channel.port2,
73
- rpcKey: ""
74
- });
75
- ```
76
-
77
- ### 使用示例 (usage.js)
78
-
79
- ```javascript
80
- async function postPortMessage() {
81
- // 调用远程方法
82
- let ret = await rpc.hello('6667');
83
- console.info("ret from rpc:", ret);
84
- }
85
- ```
86
-
87
- ## 通信流程
88
-
89
- 1. 渲染进程创建 `MessageChannel` 并通过 `postMessage` 将 `port1` 发送到预加载脚本
90
- 2. 预加载脚本验证消息来源并将端口转发给主进程
91
- 3. 主进程接收端口并创建 RPC 服务端点
92
- 4. 渲染进程使用 `port2` 创建 RPC 客户端
93
- 5. 客户端可以调用主进程中定义的服务方法
94
-
95
- ## 使用方法
96
-
97
- ### 1. 主进程设置
98
-
99
- 在主进程中定义服务类并创建 RPC 服务:
100
-
101
- ```javascript
102
- class AppApi {
103
- async yourMethod(params) {
104
- // 实现业务逻辑
105
- return result;
106
- }
107
- }
108
-
109
- ipcMain.on('port', (event) => {
110
- const port = event.ports[0]
111
- createRpcServerElectronMessagePort({
112
- port,
113
- rpcKey: '',
114
- extension: new AppApi()
115
- })
116
- port.start()
117
- })
118
- ```
119
-
120
- ### 2. 渲染进程调用
121
-
122
- 在渲染进程中建立连接并调用远程方法:
123
-
124
- ```javascript
125
- const channel = new MessageChannel();
126
- window.postMessage("port", location.origin, [channel.port1]);
127
- let rpc = createRpcClientMessagePort({ port: channel.port2, rpcKey: "" });
128
-
129
- // 调用远程方法
130
- let result = await rpc.yourMethod(params);
131
- ```
132
-
133
- ## 注意事项
134
-
135
- - 确保在 Electron 的安全策略下正确配置 `contextIsolation` 和 `sandbox` 选项
136
- - 预加载脚本中的消息验证是安全通信的关键
137
- - MessagePort 需要在两端都启动后才能正常通信
1
+ # Electron RPC 通信使用说明
2
+
3
+ ## 概述
4
+
5
+ 本文档介绍如何在 Electron 应用中使用 `js-rpc2` 库实现主进程与渲染进程之间的 RPC 通信。通过 MessagePort 机制,实现跨进程的远程方法调用。
6
+
7
+ ## 项目结构
8
+
9
+ ### 组件说明
10
+
11
+ - **main.js**: Electron 主进程,提供核心服务接口
12
+ - **preload.js**: 预加载脚本,建立主进程与渲染进程的通信桥梁
13
+ - **renderer.js**: 渲染进程,运行在浏览器环境中
14
+ - **usage.js**: 使用示例,展示如何调用 RPC 方法
15
+
16
+ ## 核心实现
17
+
18
+ ### 主进程 (main.js)
19
+
20
+ ```javascript
21
+ import { ipcMain } from 'electron'
22
+ import { createRpcServerElectronMessagePort } from 'js-rpc2/src/lib.js'
23
+
24
+ class AppApi {
25
+ asyncLocalStorage = new AsyncLocalStorage()
26
+
27
+ async hello(param) {
28
+ return 'wertyuioiuytre ' + param
29
+ }
30
+ }
31
+
32
+ // 监听来自渲染进程的 port 消息
33
+ ipcMain.on('port', (event) => {
34
+ const port = event.ports[0]
35
+ // 创建 RPC 服务端点
36
+ createRpcServerElectronMessagePort({
37
+ port,
38
+ rpcKey: '',
39
+ extension: new AppApi()
40
+ })
41
+ port.start()
42
+ })
43
+ ```
44
+
45
+ ### 预加载脚本 (preload.js)
46
+
47
+ ```javascript
48
+ import { ipcRenderer } from 'electron/renderer'
49
+
50
+ // 监听来自渲染进程的消息
51
+ window.onmessage = (/** @type {MessageEvent} */ event) => {
52
+ // 验证消息来源并转发给主进程
53
+ if (event.isTrusted && event.data == 'port') {
54
+ ipcRenderer.postMessage('port', null, [event.ports[0]])
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### 渲染进程 (renderer.js)
60
+
61
+ ```javascript
62
+ import { createRpcClientMessagePort } from 'js-rpc2/src/lib.js'
63
+
64
+ // 创建消息通道
65
+ const channel = new MessageChannel();
66
+
67
+ // 向主进程发送端口
68
+ window.postMessage("port", location.origin, [channel.port1]);
69
+
70
+ // 创建 RPC 客户端
71
+ let rpc = createRpcClientMessagePort({
72
+ port: channel.port2,
73
+ rpcKey: ""
74
+ });
75
+ ```
76
+
77
+ ### 使用示例 (usage.js)
78
+
79
+ ```javascript
80
+ async function postPortMessage() {
81
+ // 调用远程方法
82
+ let ret = await rpc.hello('6667');
83
+ console.info("ret from rpc:", ret);
84
+ }
85
+ ```
86
+
87
+ ## 通信流程
88
+
89
+ 1. 渲染进程创建 `MessageChannel` 并通过 `postMessage` 将 `port1` 发送到预加载脚本
90
+ 2. 预加载脚本验证消息来源并将端口转发给主进程
91
+ 3. 主进程接收端口并创建 RPC 服务端点
92
+ 4. 渲染进程使用 `port2` 创建 RPC 客户端
93
+ 5. 客户端可以调用主进程中定义的服务方法
94
+
95
+ ## 使用方法
96
+
97
+ ### 1. 主进程设置
98
+
99
+ 在主进程中定义服务类并创建 RPC 服务:
100
+
101
+ ```javascript
102
+ class AppApi {
103
+ async yourMethod(params) {
104
+ // 实现业务逻辑
105
+ return result;
106
+ }
107
+ }
108
+
109
+ ipcMain.on('port', (event) => {
110
+ const port = event.ports[0]
111
+ createRpcServerElectronMessagePort({
112
+ port,
113
+ rpcKey: '',
114
+ extension: new AppApi()
115
+ })
116
+ port.start()
117
+ })
118
+ ```
119
+
120
+ ### 2. 渲染进程调用
121
+
122
+ 在渲染进程中建立连接并调用远程方法:
123
+
124
+ ```javascript
125
+ const channel = new MessageChannel();
126
+ window.postMessage("port", location.origin, [channel.port1]);
127
+ let rpc = createRpcClientMessagePort({ port: channel.port2, rpcKey: "" });
128
+
129
+ // 调用远程方法
130
+ let result = await rpc.yourMethod(params);
131
+ ```
132
+
133
+ ## 注意事项
134
+
135
+ - 确保在 Electron 的安全策略下正确配置 `contextIsolation` 和 `sandbox` 选项
136
+ - 预加载脚本中的消息验证是安全通信的关键
137
+ - MessagePort 需要在两端都启动后才能正常通信
138
138
  - 异步方法调用需要正确处理 Promise 返回值
@@ -1,187 +1,187 @@
1
- # 在 Node.js Worker Threads 中使用 js-rpc
2
-
3
- Node.js Worker Threads 是一种在 Node.js 中实现并行处理的机制,js-rpc 提供了在主线程和 Worker 线程之间进行 RPC 调用的能力。
4
-
5
- ## 概述
6
-
7
- js-rpc 在 Node.js Worker Threads 中的使用主要包括两个部分:
8
- 1. 在 Worker 线程中创建 RPC 服务器:使用 [createRpcServerNodeJSWorker](../src/lib.js#L993)
9
- 2. 在主线程中创建 RPC 客户端:使用 [createRpcClientNodeJSWorker](../src/lib.js#L1013)
10
-
11
- ## 完整示例
12
-
13
- ### 1. Worker 线程代码 (worker.js)
14
-
15
- ```js
16
- // 导入必要的模块
17
- import { parentPort } from 'worker_threads'
18
- import { createRpcServerNodeJSWorker } from 'js-rpc2/src/lib.js'
19
-
20
- // 定义可被远程调用的函数
21
- async function readClipboard() {
22
- // 实现读取剪贴板的逻辑
23
- // 这里只是示例,实际实现取决于你的需求
24
- return 'clipboard content'
25
- }
26
-
27
- async function writeClipboard(data) {
28
- // 实现写入剪贴板的逻辑
29
- console.log('Writing to clipboard:', data)
30
- return true
31
- }
32
-
33
- async function writeClipboardText(text) {
34
- // 实现写入文本到剪贴板的逻辑
35
- console.log('Writing text to clipboard:', text)
36
- return true
37
- }
38
-
39
- async function readClipboardText() {
40
- // 实现读取剪贴板文本的逻辑
41
- return 'clipboard text'
42
- }
43
-
44
- async function readClipboardHtml() {
45
- // 实现读取剪贴板 HTML 内容的逻辑
46
- return '<p>clipboard html</p>'
47
- }
48
-
49
- async function readClipboardImage() {
50
- // 实现读取剪贴板图片的逻辑
51
- return new Uint8Array([1, 2, 3, 4]) // 示例二进制数据
52
- }
53
-
54
- // 将所有函数导出为一个 API 对象
55
- export const ExtensionApi = {
56
- readClipboard,
57
- writeClipboard,
58
- writeClipboardText,
59
- readClipboardText,
60
- readClipboardHtml,
61
- readClipboardImage,
62
- }
63
-
64
- // 创建 RPC 服务器
65
- createRpcServerNodeJSWorker({
66
- parentPort,
67
- extension: ExtensionApi,
68
- logger: (msg) => console.log('[Worker]', msg) // 可选的日志记录器
69
- })
70
- ```
71
-
72
- ### 2. 主线程代码 (main.js)
73
-
74
- ```js
75
- // 导入必要的模块
76
- import { createRpcClientNodeJSWorker } from 'js-rpc2/src/lib.js'
77
- import { Worker } from 'worker_threads'
78
-
79
- // 创建 Worker 实例
80
- export const worker = new Worker(new URL('./worker.js', import.meta.url))
81
-
82
- // 创建 RPC 客户端
83
- /** @type{ExtensionApi} */
84
- const rpc = createRpcClientNodeJSWorker({ worker: worker })
85
-
86
- // 取消 Worker 的引用,允许程序在没有其他任务时退出
87
- worker.unref()
88
-
89
- // 包装远程调用函数
90
- export async function readClipboard() {
91
- return await rpc.readClipboard()
92
- }
93
-
94
- /**
95
- * 写入剪贴板内容
96
- * @param {'text'|'richtext'|'image'} type - 数据类型
97
- * @param {string|Buffer} data - 要写入的数据
98
- */
99
- export async function writeClipboard(type, data) {
100
- return await rpc.writeClipboard(type, data)
101
- }
102
-
103
- /**
104
- * 写入文本到剪贴板
105
- * @param {string} text - 要写入的文本
106
- */
107
- export async function writeClipboardText(text) {
108
- return rpc.writeClipboardText(text)
109
- }
110
-
111
- export async function readClipboardText() {
112
- return rpc.readClipboardText()
113
- }
114
-
115
- export async function readClipboardHtml() {
116
- return rpc.readClipboardHtml()
117
- }
118
-
119
- export async function readClipboardImage() {
120
- return rpc.readClipboardImage()
121
- }
122
-
123
- // 使用示例
124
- async function example() {
125
- // 调用远程函数
126
- const text = await readClipboardText()
127
- console.log('Clipboard text:', text)
128
-
129
- await writeClipboardText('Hello from main thread!')
130
-
131
- const image = await readClipboardImage()
132
- console.log('Clipboard image size:', image.length)
133
- }
134
- ```
135
-
136
- ## API 说明
137
-
138
- ### createRpcServerNodeJSWorker
139
-
140
- 在 Worker 线程中创建 RPC 服务器。
141
-
142
- ```js
143
- /**
144
- * @param {{
145
- * parentPort: NodeJSMessagePort;
146
- * extension: Object;
147
- * logger?:(msg:string)=>void;
148
- * }} param
149
- */
150
- export function createRpcServerNodeJSWorker(param)
151
- ```
152
-
153
- 参数说明:
154
- - `parentPort`: Worker 线程的 parentPort 对象,用于与主线程通信
155
- - `extension`: 包含可被远程调用函数的对象
156
- - `logger`: 可选的日志记录函数
157
-
158
- ### createRpcClientNodeJSWorker
159
-
160
- 在主线程中创建 RPC 客户端。
161
-
162
- ```js
163
- /**
164
- * @param {{
165
- * worker:NodeJSWorker;
166
- * }} param
167
- */
168
- export function createRpcClientNodeJSWorker(param)
169
- ```
170
-
171
- 参数说明:
172
- - `worker`: Worker 实例
173
-
174
- ## 特性
175
-
176
- 1. **透明的远程调用**:在主线程中调用 Worker 中的函数就像调用本地函数一样简单
177
- 2. **支持异步函数**:所有远程函数都可以是异步的
178
- 3. **参数和返回值序列化**:自动处理参数和返回值的序列化/反序列化
179
- 4. **类型安全**:通过 JSDoc 注解提供完整的类型支持
180
- 5. **错误处理**:远程函数抛出的错误会正确传播到调用方
181
-
182
- ## 注意事项
183
-
184
- 1. 确保 Worker 线程中的函数是可序列化的
185
- 2. 大数据传输可能影响性能,考虑使用流式传输
186
- 3. 避免在远程函数中使用闭包引用 Worker 外部的变量
1
+ # 在 Node.js Worker Threads 中使用 js-rpc
2
+
3
+ Node.js Worker Threads 是一种在 Node.js 中实现并行处理的机制,js-rpc 提供了在主线程和 Worker 线程之间进行 RPC 调用的能力。
4
+
5
+ ## 概述
6
+
7
+ js-rpc 在 Node.js Worker Threads 中的使用主要包括两个部分:
8
+ 1. 在 Worker 线程中创建 RPC 服务器:使用 [createRpcServerNodeJSWorker](../src/lib.js#L993)
9
+ 2. 在主线程中创建 RPC 客户端:使用 [createRpcClientNodeJSWorker](../src/lib.js#L1013)
10
+
11
+ ## 完整示例
12
+
13
+ ### 1. Worker 线程代码 (worker.js)
14
+
15
+ ```js
16
+ // 导入必要的模块
17
+ import { parentPort } from 'worker_threads'
18
+ import { createRpcServerNodeJSWorker } from 'js-rpc2/src/lib.js'
19
+
20
+ // 定义可被远程调用的函数
21
+ async function readClipboard() {
22
+ // 实现读取剪贴板的逻辑
23
+ // 这里只是示例,实际实现取决于你的需求
24
+ return 'clipboard content'
25
+ }
26
+
27
+ async function writeClipboard(data) {
28
+ // 实现写入剪贴板的逻辑
29
+ console.log('Writing to clipboard:', data)
30
+ return true
31
+ }
32
+
33
+ async function writeClipboardText(text) {
34
+ // 实现写入文本到剪贴板的逻辑
35
+ console.log('Writing text to clipboard:', text)
36
+ return true
37
+ }
38
+
39
+ async function readClipboardText() {
40
+ // 实现读取剪贴板文本的逻辑
41
+ return 'clipboard text'
42
+ }
43
+
44
+ async function readClipboardHtml() {
45
+ // 实现读取剪贴板 HTML 内容的逻辑
46
+ return '<p>clipboard html</p>'
47
+ }
48
+
49
+ async function readClipboardImage() {
50
+ // 实现读取剪贴板图片的逻辑
51
+ return new Uint8Array([1, 2, 3, 4]) // 示例二进制数据
52
+ }
53
+
54
+ // 将所有函数导出为一个 API 对象
55
+ export const ExtensionApi = {
56
+ readClipboard,
57
+ writeClipboard,
58
+ writeClipboardText,
59
+ readClipboardText,
60
+ readClipboardHtml,
61
+ readClipboardImage,
62
+ }
63
+
64
+ // 创建 RPC 服务器
65
+ createRpcServerNodeJSWorker({
66
+ parentPort,
67
+ extension: ExtensionApi,
68
+ logger: (msg) => console.log('[Worker]', msg) // 可选的日志记录器
69
+ })
70
+ ```
71
+
72
+ ### 2. 主线程代码 (main.js)
73
+
74
+ ```js
75
+ // 导入必要的模块
76
+ import { createRpcClientNodeJSWorker } from 'js-rpc2/src/lib.js'
77
+ import { Worker } from 'worker_threads'
78
+
79
+ // 创建 Worker 实例
80
+ export const worker = new Worker(new URL('./worker.js', import.meta.url))
81
+
82
+ // 创建 RPC 客户端
83
+ /** @type{ExtensionApi} */
84
+ const rpc = createRpcClientNodeJSWorker({ worker: worker })
85
+
86
+ // 取消 Worker 的引用,允许程序在没有其他任务时退出
87
+ worker.unref()
88
+
89
+ // 包装远程调用函数
90
+ export async function readClipboard() {
91
+ return await rpc.readClipboard()
92
+ }
93
+
94
+ /**
95
+ * 写入剪贴板内容
96
+ * @param {'text'|'richtext'|'image'} type - 数据类型
97
+ * @param {string|Buffer} data - 要写入的数据
98
+ */
99
+ export async function writeClipboard(type, data) {
100
+ return await rpc.writeClipboard(type, data)
101
+ }
102
+
103
+ /**
104
+ * 写入文本到剪贴板
105
+ * @param {string} text - 要写入的文本
106
+ */
107
+ export async function writeClipboardText(text) {
108
+ return rpc.writeClipboardText(text)
109
+ }
110
+
111
+ export async function readClipboardText() {
112
+ return rpc.readClipboardText()
113
+ }
114
+
115
+ export async function readClipboardHtml() {
116
+ return rpc.readClipboardHtml()
117
+ }
118
+
119
+ export async function readClipboardImage() {
120
+ return rpc.readClipboardImage()
121
+ }
122
+
123
+ // 使用示例
124
+ async function example() {
125
+ // 调用远程函数
126
+ const text = await readClipboardText()
127
+ console.log('Clipboard text:', text)
128
+
129
+ await writeClipboardText('Hello from main thread!')
130
+
131
+ const image = await readClipboardImage()
132
+ console.log('Clipboard image size:', image.length)
133
+ }
134
+ ```
135
+
136
+ ## API 说明
137
+
138
+ ### createRpcServerNodeJSWorker
139
+
140
+ 在 Worker 线程中创建 RPC 服务器。
141
+
142
+ ```js
143
+ /**
144
+ * @param {{
145
+ * parentPort: NodeJSMessagePort;
146
+ * extension: Object;
147
+ * logger?:(msg:string)=>void;
148
+ * }} param
149
+ */
150
+ export function createRpcServerNodeJSWorker(param)
151
+ ```
152
+
153
+ 参数说明:
154
+ - `parentPort`: Worker 线程的 parentPort 对象,用于与主线程通信
155
+ - `extension`: 包含可被远程调用函数的对象
156
+ - `logger`: 可选的日志记录函数
157
+
158
+ ### createRpcClientNodeJSWorker
159
+
160
+ 在主线程中创建 RPC 客户端。
161
+
162
+ ```js
163
+ /**
164
+ * @param {{
165
+ * worker:NodeJSWorker;
166
+ * }} param
167
+ */
168
+ export function createRpcClientNodeJSWorker(param)
169
+ ```
170
+
171
+ 参数说明:
172
+ - `worker`: Worker 实例
173
+
174
+ ## 特性
175
+
176
+ 1. **透明的远程调用**:在主线程中调用 Worker 中的函数就像调用本地函数一样简单
177
+ 2. **支持异步函数**:所有远程函数都可以是异步的
178
+ 3. **参数和返回值序列化**:自动处理参数和返回值的序列化/反序列化
179
+ 4. **类型安全**:通过 JSDoc 注解提供完整的类型支持
180
+ 5. **错误处理**:远程函数抛出的错误会正确传播到调用方
181
+
182
+ ## 注意事项
183
+
184
+ 1. 确保 Worker 线程中的函数是可序列化的
185
+ 2. 大数据传输可能影响性能,考虑使用流式传输
186
+ 3. 避免在远程函数中使用闭包引用 Worker 外部的变量
187
187
  4. Worker 线程在没有任务时会自动退出,如需保持运行请适当管理引用
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-rpc2",
3
- "version": "2.4.1",
3
+ "version": "2.4.2",
4
4
  "description": "js web websocket http rpc",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/src/lib.js CHANGED
@@ -696,13 +696,13 @@ export function createRpcClientWebSocket(param) {
696
696
  signal.resolve()
697
697
  })
698
698
  ws.addEventListener('error', (e) => {
699
- if (param.intercept) {
700
- param.intercept(e)
701
- }
702
699
  console.error('createRpcClientWebSocket createWebSocket ws error', e)
703
700
  promise.resolve()
704
701
  })
705
- ws.addEventListener('close', () => {
702
+ ws.addEventListener('close', (e) => {
703
+ if (param.intercept) {
704
+ param.intercept(e)
705
+ }
706
706
  console.error('createRpcClientWebSocket createWebSocket ws close')
707
707
  promise.resolve()
708
708
  })