moonbridge-ts 0.5.0 → 0.6.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/README.md +237 -229
- package/dist/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.d.ts +5 -4
- package/dist/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.d.ts.map +1 -1
- package/dist/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.js +44 -9
- package/dist/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.js.map +1 -1
- package/dist/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.mjs +44 -9
- package/dist/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.mjs.map +1 -1
- package/dist/moonbridge-ipc/client/moonbridge_ipc_client.d.ts +7 -2
- package/dist/moonbridge-ipc/client/moonbridge_ipc_client.d.ts.map +1 -1
- package/dist/moonbridge-ipc/client/moonbridge_ipc_client.js.map +1 -1
- package/dist/moonbridge-ipc/client/moonbridge_ipc_client.mjs.map +1 -1
- package/dist/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.d.ts +7 -0
- package/dist/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.d.ts.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.js +78 -0
- package/dist/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.js.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.mjs +76 -0
- package/dist/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.mjs.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_annotation.d.ts +55 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_annotation.d.ts.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_annotation.js +71 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_annotation.js.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_annotation.mjs +65 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_annotation.mjs.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_service_factory.d.ts +57 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_service_factory.d.ts.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_service_factory.js +16 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_service_factory.js.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_service_factory.mjs +14 -0
- package/dist/moonbridge-ipc/client/rpc/rpc_service_factory.mjs.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/service/job/ipc_request_job.d.ts +14 -0
- package/dist/moonbridge-ipc/client/rpc/service/job/ipc_request_job.d.ts.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/service/job/ipc_request_job.js +27 -0
- package/dist/moonbridge-ipc/client/rpc/service/job/ipc_request_job.js.map +1 -0
- package/dist/moonbridge-ipc/client/rpc/service/job/ipc_request_job.mjs +25 -0
- package/dist/moonbridge-ipc/client/rpc/service/job/ipc_request_job.mjs.map +1 -0
- package/dist/moonbridge-ipc/client/types/ipc_messenger.d.ts +30 -14
- package/dist/moonbridge-ipc/client/types/ipc_messenger.d.ts.map +1 -1
- package/dist/moonbridge-ipc/index.d.ts +3 -0
- package/dist/moonbridge-ipc/index.d.ts.map +1 -1
- package/dist/moonbridge-ipc/index.js +21 -0
- package/dist/moonbridge-ipc/index.mjs +3 -0
- package/package.json +2 -2
- package/src/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.ts +66 -21
- package/src/moonbridge-ipc/client/moonbridge_ipc_client.ts +7 -2
- package/src/moonbridge-ipc/client/rpc/internal/rpc_service_proxy.ts +103 -0
- package/src/moonbridge-ipc/client/rpc/rpc_annotation.ts +125 -0
- package/src/moonbridge-ipc/client/rpc/rpc_service_factory.ts +61 -0
- package/src/moonbridge-ipc/client/rpc/service/job/ipc_request_job.ts +33 -0
- package/src/moonbridge-ipc/client/types/ipc_messenger.ts +33 -15
- package/src/moonbridge-ipc/index.ts +3 -0
- package/tests/unit/ipc_messenger.route.test.ts +71 -0
- package/tests/unit/rpc_service_factory.test.ts +94 -0
- package/tests/unit/rpc_service_proxy.test.ts +145 -0
package/README.md
CHANGED
|
@@ -1,303 +1,311 @@
|
|
|
1
1
|
# moonbridge-ts
|
|
2
2
|
|
|
3
|
-
基于 MoonBridge 通信协议的 TypeScript IPC
|
|
3
|
+
基于 MoonBridge 通信协议的 TypeScript IPC 库,面向 WebSocket 场景(浏览器、WPS 加载项、Node)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 1. moonbridge-ts 是什么?
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
`moonbridge-ts` 是 moonbridge IPC 的 TypeScript 实现,用于在不同进程/应用之间进行消息通信。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
角色模型与 Flutter 版本一致:
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **公开 API**:对外方法签名、参数语义、返回值约定与 Flutter 端对应抽象一致,使两端调用方式可互换理解。
|
|
14
|
-
- **目录与层级**:目录结构、模块划分与 Flutter `lib/` 一致(如 `client/`、`general/encode`、`general/message`、`general/transport`),便于按相同路径在两端定位。
|
|
15
|
-
- **平台封装例外**:仅在**平台能力差异**(如 WebSocket 的运行时 API 不同)时,底层实现可不同,但**对外暴露的 API(方法名、参数与语义)须与 Flutter 端抽象完全一致**(如 `TransportClient.connectWithServer()`、`sendData()`、`isClientConnected`、`onErrorAndClose()`)。
|
|
16
|
-
- **实施顺序**:先**第一步**完全还原 `lib/general/`(encode、message、transport、config、error、lock、statistics、utils、app_launch),再**第二步**对齐 client/、extension/ 及根入口 index.ts。
|
|
11
|
+
1. 客户端:发送请求、接收请求、处理回调、发布/订阅事件。
|
|
12
|
+
2. 服务端:负责客户端注册、消息转发、会话建立、唤醒目标客户端。
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
当前 TS 版本传输层仅提供 WebSocket 通道(`ws://`)。
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
角色环境限制:
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
1. `server` 角色需要监听端口,浏览器环境受限,`MoonBridgeIpcServer` 只能在 Node.js 环境使用。
|
|
19
|
+
2. `client` 角色不需要监听端口,`MoonBridgeIpcClient` 可在 Node.js 和浏览器环境使用。
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
moonbridge-ts 是 **MoonBridge IPC 在 TypeScript 侧的客户端与服务端实现**,与 Flutter 端「客户端 / 服务端」角色模型一致:
|
|
27
|
-
|
|
28
|
-
- **客户端**:负责消息的发送与接收(本库实现**客户端**角色)。
|
|
29
|
-
- **服务端**:由 NPC 侧 moonbridge-ipc-flutter 承担,负责消息的中转与分发(本库同时提供 **MoonBridgeIpcServer** 用于服务端场景)。
|
|
21
|
+
## 2. 当前提供的能力
|
|
30
22
|
|
|
31
|
-
|
|
23
|
+
1. 支持单应用/多应用跨进程通信(经 IPC 服务端转发)。
|
|
24
|
+
2. 支持 Request/Response/Error 三类消息与回调链路。
|
|
25
|
+
3. 支持消息拦截(`MessageInterceptor`)。
|
|
26
|
+
4. 支持连接状态监听(`ConnectionObserver`)。
|
|
27
|
+
5. 支持心跳保活(默认开启,默认 3000ms)。
|
|
28
|
+
6. 支持客户端身份认证(服务端白名单 `ClientIdentityProvider`)。
|
|
29
|
+
7. 支持自动唤醒目标应用(`autoLaunch` + `AppLauncher`)。
|
|
30
|
+
8. 支持 1 对 1 指定客户端通信。
|
|
31
|
+
9. 支持 EventBus 广播通信。
|
|
32
|
+
10. 支持端口候选策略(`PortCandidateRule`,服务端按规则尝试绑定端口,客户端按规则尝试连接端口)。
|
|
33
|
+
11. 支持 WPS 场景 deeplink 唤醒(`WpsAppLauncher`)。
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
### 2.1 `PortCandidateRule` 作用说明
|
|
34
36
|
|
|
35
|
-
|
|
37
|
+
`PortCandidateRule` 用于在端口不确定或端口可能被占用时,给 server/client 提供一致的端口尝试规则:
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
1. 服务端启动时,如果初始端口被占用,会按 `PortCandidateRule` 生成的有序端口列表继续尝试绑定,直到某个端口启动成功,或所有候选端口尝试完毕后启动失败。
|
|
40
|
+
2. 客户端连接时,会按同一规则生成的有序端口列表依次尝试连接;每个端口都会执行连接和握手校验,直到连接并握手成功,或所有候选端口尝试完毕后连接失败。
|
|
41
|
+
3. 该机制可避免“固定端口冲突导致整体不可用”,并确保 server 与 client 共享相同的端口探索顺序。
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
- **握手与协议**:连接建立后发送 Handshake,校验对端为 MoonBridge IPC 服务后再进入会话。
|
|
41
|
-
- **连接管理**:连接状态机(disconnected / connecting / connected / disconnecting)、有限次数重试与固定间隔(与 Flutter IpcConnectionManager 对齐)。
|
|
42
|
-
- **发送请求并接收响应**:`messenger.postMessage(target, { args: [..., callback] })`,将回调作为 args 末位传入,服务端响应时调用 callback。
|
|
43
|
-
- **接收对端请求**:`registerHandler(moduleName, methodName, handler)` 注册本地方法;对端发送 TYPE_NAME_REQUEST 时派发到 handler,参数中 callbackId 替换为 ResultCallback,业务调用 `callback.invoke(result)` 回写 TYPE_NAME_RESPONSE;未注册则回写 TYPE_NAME_ERROR。协议与 [contracts](../specs/001-moonbridge-js-receive-extensions/contracts/message-formats.md) 一致(仓库内路径)。
|
|
44
|
-
- **心跳保活**:连接建立后按 `heartbeatIntervalMs`(默认 30s)发送 TYPE_NAME_PING;可配置 `heartbeatEnabled`、`heartbeatIntervalMs`。
|
|
45
|
-
- **EventBus**:`client.getEventBus().register(eventName, callback)` 订阅,`client.postEvent(type, source?, data?)` 发布;收到 TYPE_NAME_EVENT 时按事件名派发。
|
|
46
|
-
- **可配置**:serverAddress、serverPort、path、clientName、heartbeatIntervalMs、heartbeatEnabled 等,与 Flutter 端配置概念一致。
|
|
43
|
+
## 3. API 设计概览
|
|
47
44
|
|
|
48
|
-
###
|
|
45
|
+
### 客户端(`MoonBridgeIpcClient`)
|
|
49
46
|
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
47
|
+
- `MoonBridgeIpcClient.builder()`
|
|
48
|
+
- `connect(onResult?)`
|
|
49
|
+
- `disconnect()`
|
|
50
|
+
- `isConnected()`
|
|
51
|
+
- `messenger.call(target).args(...).onError(...).strategy(...).send()`
|
|
52
|
+
- `rpcServiceFactory.createService(ServiceType, clientName?)`
|
|
53
|
+
- `eventBus.register(subscriber)`
|
|
54
|
+
- `eventBus.unregister(subscriber)`
|
|
55
|
+
- `eventBus.post(event)`
|
|
55
56
|
|
|
56
|
-
###
|
|
57
|
+
### 服务端(`MoonBridgeIpcServer`)
|
|
57
58
|
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
59
|
+
- `MoonBridgeIpcServer.builder()`
|
|
60
|
+
- `start(): Promise<boolean>`
|
|
61
|
+
- `stop(): Promise<void>`
|
|
62
|
+
- `clientIdentityProviders([...])`
|
|
63
|
+
- `messagePreprocessor(...)`
|
|
64
|
+
- `onMessageReceived(...)`
|
|
65
|
+
- `wakeAppInterceptor(...)`
|
|
61
66
|
|
|
62
|
-
###
|
|
67
|
+
### 传输层(与 Flutter 抽象保持一致)
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
- 支持应用安装路径查询和类型转换。
|
|
69
|
+
`TransportClient` 统一接口:
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
- `connectWithServer()`
|
|
72
|
+
- `sendData(data)`
|
|
73
|
+
- `onMessage(cb)`
|
|
74
|
+
- `onErrorAndClose({ onError, onServerClose })`
|
|
75
|
+
- `close()`
|
|
76
|
+
- `isClientConnected`
|
|
68
77
|
|
|
69
|
-
##
|
|
78
|
+
## 4. 接入流程与示例
|
|
70
79
|
|
|
71
|
-
|
|
80
|
+
### 4.1 安装
|
|
72
81
|
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
│ moonbridge/ 核心模块层 │
|
|
76
|
-
│ ├── kernel/ Bridge、BridgeModule 核心抽象 │
|
|
77
|
-
│ ├── annotation/ @MoonBridgeModule、@MoonBridgeMethod 装饰器 │
|
|
78
|
-
│ └── logger/ 日志抽象 │
|
|
79
|
-
├──────────────────────────────────────────────────────────────────────────┤
|
|
80
|
-
│ moonbridge-ipc/ IPC 通信层 │
|
|
81
|
-
│ ├── client/ IPC 客户端(MoonBridgeIpcClient) │
|
|
82
|
-
│ │ ├── internal/ 内部实现(连接管理、桥接、执行器等) │
|
|
83
|
-
│ │ └── types/ 客户端类型定义 │
|
|
84
|
-
│ ├── server/ IPC 服务端(MoonBridgeIpcServer) │
|
|
85
|
-
│ │ └── credential/ 客户端身份认证 │
|
|
86
|
-
│ ├── general/ 通用层(与 Flutter lib/general 对应) │
|
|
87
|
-
│ │ ├── encode/ IpcMessageEncoder 消息编码 │
|
|
88
|
-
│ │ ├── message/ 消息类型常量、负载类型 │
|
|
89
|
-
│ │ └── error/ IpcError 与错误码 │
|
|
90
|
-
│ └── extension/ 扩展能力 │
|
|
91
|
-
├──────────────────────────────────────────────────────────────────────────┤
|
|
92
|
-
│ wps-launcher/ WPS 应用启动层 │
|
|
93
|
-
│ └── launcher/ WpsAppLauncher 实现 │
|
|
94
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
82
|
+
```bash
|
|
83
|
+
npm install moonbridge-ts
|
|
95
84
|
```
|
|
96
85
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
## 4. 目录结构
|
|
106
|
-
|
|
107
|
-
```text
|
|
108
|
-
moonbridge-ts/
|
|
109
|
-
├── src/
|
|
110
|
-
│ ├── moonbridge/ # 核心模块层
|
|
111
|
-
│ │ ├── kernel/
|
|
112
|
-
│ │ │ ├── bridge.ts # Bridge 抽象
|
|
113
|
-
│ │ │ ├── bridge_module.ts # BridgeModule 基类
|
|
114
|
-
│ │ │ ├── result_callback.ts # 结果回调
|
|
115
|
-
│ │ │ └── executor.ts # 执行器
|
|
116
|
-
│ │ ├── annotation/
|
|
117
|
-
│ │ │ ├── decorators.ts # @MoonBridgeModule、@MoonBridgeMethod
|
|
118
|
-
│ │ │ └── registry.ts # MoonBridgeRegistry
|
|
119
|
-
│ │ ├── message/ # 消息解析
|
|
120
|
-
│ │ ├── module/ # 模块创建与方法调用
|
|
121
|
-
│ │ ├── logger/
|
|
122
|
-
│ │ │ └── logger.ts # 日志抽象
|
|
123
|
-
│ │ └── index.ts # 对外导出
|
|
124
|
-
│ ├── moonbridge-ipc/ # IPC 通信层
|
|
125
|
-
│ │ ├── client/
|
|
126
|
-
│ │ │ ├── moonbridge_ipc_client.ts # 客户端入口
|
|
127
|
-
│ │ │ ├── internal/ # 内部实现
|
|
128
|
-
│ │ │ │ ├── bridge/ # 桥接与执行
|
|
129
|
-
│ │ │ │ ├── ipc/ # IPC 核心
|
|
130
|
-
│ │ │ │ └── settings/ # 配置
|
|
131
|
-
│ │ │ └── types/ # 类型定义
|
|
132
|
-
│ │ ├── server/
|
|
133
|
-
│ │ │ ├── moonbridge_ipc_server.ts # 服务端入口
|
|
134
|
-
│ │ │ ├── credential/ # 客户端身份
|
|
135
|
-
│ │ │ └── internal/ # 内部实现
|
|
136
|
-
│ │ ├── general/
|
|
137
|
-
│ │ │ ├── encode/ # 消息编码
|
|
138
|
-
│ │ │ ├── message/ # 消息类型
|
|
139
|
-
│ │ │ └── error/ # 错误定义
|
|
140
|
-
│ │ ├── extension/ # 扩展
|
|
141
|
-
│ │ └── index.ts # 对外导出
|
|
142
|
-
│ ├── wps-launcher/ # WPS 应用启动
|
|
143
|
-
│ │ ├── launcher/
|
|
144
|
-
│ │ │ └── wps_app_launcher.ts
|
|
145
|
-
│ │ └── index.ts # 对外导出
|
|
146
|
-
│ └── index.ts # 根入口
|
|
147
|
-
├── tests/
|
|
148
|
-
│ ├── unit/
|
|
149
|
-
│ └── integration/
|
|
150
|
-
├── docs/
|
|
151
|
-
│ ├── ROADMAP.md
|
|
152
|
-
│ ├── REFACTOR_SCOPE.md
|
|
153
|
-
│ └── STRUCTURE.md
|
|
154
|
-
├── DEPENDENCIES.md
|
|
155
|
-
├── package.json
|
|
156
|
-
└── README.md
|
|
157
|
-
```
|
|
86
|
+
### 4.2 初始化服务端(Node)
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import {
|
|
90
|
+
MoonBridgeIpcServer,
|
|
91
|
+
WebSocketServerEndpoint,
|
|
92
|
+
ClientIdentity,
|
|
93
|
+
} from 'moonbridge-ts';
|
|
158
94
|
|
|
159
|
-
|
|
95
|
+
const endpoint = new WebSocketServerEndpoint({
|
|
96
|
+
address: '0.0.0.0',
|
|
97
|
+
port: 9091,
|
|
98
|
+
path: '/ws',
|
|
99
|
+
useTls: false,
|
|
100
|
+
});
|
|
160
101
|
|
|
161
|
-
|
|
102
|
+
const getClientIdentity = (clientName: string) => {
|
|
103
|
+
switch (clientName) {
|
|
104
|
+
case 'client_a':
|
|
105
|
+
return new ClientIdentity('client_a');
|
|
106
|
+
case 'client_b':
|
|
107
|
+
return new ClientIdentity('client_b');
|
|
108
|
+
default:
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
162
112
|
|
|
163
|
-
|
|
113
|
+
const server = MoonBridgeIpcServer.builder()
|
|
114
|
+
.serverName('moonbridge_server')
|
|
115
|
+
.useWebSocketChannel(endpoint)
|
|
116
|
+
.clientIdentityProviders([getClientIdentity])
|
|
117
|
+
.build(true);
|
|
164
118
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
119
|
+
const started = await server.start();
|
|
120
|
+
if (!started) {
|
|
121
|
+
throw new Error('IPC server start failed');
|
|
122
|
+
}
|
|
169
123
|
```
|
|
170
124
|
|
|
171
|
-
###
|
|
125
|
+
### 4.3 初始化客户端
|
|
172
126
|
|
|
173
|
-
```
|
|
127
|
+
```ts
|
|
174
128
|
import {
|
|
175
|
-
|
|
129
|
+
MoonBridgeIpcClient,
|
|
176
130
|
WebSocketServerEndpoint,
|
|
131
|
+
IpcMessageStrategy,
|
|
177
132
|
} from 'moonbridge-ts';
|
|
178
133
|
|
|
179
|
-
const client =
|
|
134
|
+
const client = MoonBridgeIpcClient.builder()
|
|
180
135
|
.clientName('client_a')
|
|
181
|
-
.useWebSocketChannel(
|
|
136
|
+
.useWebSocketChannel(
|
|
137
|
+
new WebSocketServerEndpoint({
|
|
138
|
+
address: '127.0.0.1',
|
|
139
|
+
port: 9091,
|
|
140
|
+
path: '/ws',
|
|
141
|
+
useTls: false,
|
|
142
|
+
}),
|
|
143
|
+
)
|
|
144
|
+
.messageStrategy(new IpcMessageStrategy(1, true))
|
|
182
145
|
.build(true);
|
|
183
146
|
|
|
184
|
-
client.connect((
|
|
185
|
-
if (
|
|
186
|
-
|
|
147
|
+
client.connect((isConnected, error) => {
|
|
148
|
+
if (isConnected) {
|
|
149
|
+
console.log('connect success');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
console.error('connect failed', error);
|
|
187
153
|
});
|
|
188
154
|
```
|
|
189
155
|
|
|
190
|
-
###
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
156
|
+
### 4.4 客户端接收消息(模块方式)
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import {
|
|
160
|
+
Bridge,
|
|
161
|
+
BridgeModule,
|
|
162
|
+
MoonBridgeMethod,
|
|
163
|
+
MoonBridgeModule,
|
|
164
|
+
ResultCallback,
|
|
165
|
+
} from 'moonbridge-ts';
|
|
166
|
+
|
|
167
|
+
@MoonBridgeModule('CallPhone')
|
|
168
|
+
export class CallModule extends BridgeModule {
|
|
169
|
+
constructor(bridge: Bridge) {
|
|
170
|
+
super(bridge);
|
|
205
171
|
}
|
|
206
|
-
);
|
|
207
|
-
```
|
|
208
172
|
|
|
209
|
-
|
|
173
|
+
@MoonBridgeMethod('callWithCallback')
|
|
174
|
+
callWithCallback(phoneNumber: string, callback: ResultCallback): void {
|
|
175
|
+
console.log(`[MoonBridge] call: ${phoneNumber}`);
|
|
176
|
+
callback.invoke(['callback - Success']);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
210
180
|
|
|
211
|
-
|
|
212
|
-
import { BridgeModule } from 'moonbridge-ts';
|
|
213
|
-
import { Bridge } from 'moonbridge-ts';
|
|
214
|
-
import { MoonBridgeModule, MoonBridgeMethod } from 'moonbridge-ts';
|
|
181
|
+
`tsconfig.json` 需开启:
|
|
215
182
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"experimentalDecorators": true,
|
|
186
|
+
"emitDecoratorMetadata": true,
|
|
187
|
+
"useDefineForClassFields": false
|
|
221
188
|
}
|
|
222
189
|
```
|
|
223
190
|
|
|
224
|
-
|
|
191
|
+
### 4.5 客户端发送消息
|
|
225
192
|
|
|
226
|
-
|
|
193
|
+
```ts
|
|
194
|
+
// 方式:call(推荐)
|
|
195
|
+
client.messenger
|
|
196
|
+
.call({ clientName: 'client_b', moduleName: 'CallPhone', methodName: 'callWithCallback' })
|
|
197
|
+
.args('0431-4610123', (response) => console.log('response:', response))
|
|
198
|
+
.onError((error) => console.error('ipc error:', error))
|
|
199
|
+
.send();
|
|
200
|
+
```
|
|
227
201
|
|
|
228
|
-
|
|
229
|
-
import { MoonBridgeIpcServerBuilder, WebSocketServerEndpoint } from 'moonbridge-ts';
|
|
202
|
+
### 4.6 EventBus(订阅与发布)
|
|
230
203
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
.build();
|
|
204
|
+
```ts
|
|
205
|
+
import { Subscriber } from 'moonbridge-ts';
|
|
206
|
+
import { Event } from 'moonbridge-ts/moonbridge-ipc/general/message/event';
|
|
235
207
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
else console.error('服务端启动失败', error);
|
|
208
|
+
const subscriber = new Subscriber('TestEvent', (event) => {
|
|
209
|
+
console.log('event:', event.type, event.data);
|
|
239
210
|
});
|
|
240
|
-
```
|
|
241
211
|
|
|
242
|
-
|
|
212
|
+
client.eventBus.register(subscriber);
|
|
213
|
+
await client.eventBus.post(new Event('TestEvent', 'client_a', { key: 'hello' }));
|
|
214
|
+
```
|
|
243
215
|
|
|
244
|
-
|
|
245
|
-
2. 在任务窗格页面中引入 IIFE:`<script src="path/to/index.global.js"></script>`,会暴露 `window.MoonbridgeJS`(含 `MoonBridgeIpcClientBuilder`、`WebSocketServerEndpoint` 等)。
|
|
246
|
-
3. 使用仓库内 `wps-addin/src/ipc/moonbridge/client.js` 提供的 `createNpcClient()`,内部会读取 `getConfig()` 的 npcWsUrl/npcWsPort 并组装 WebSocket 通道。
|
|
247
|
-
4. 端口与地址需按环境配置(见 `window.getConfig()` 或 `__NPC_LINK_CONFIG__`),避免误用固定配置。
|
|
248
|
-
5. 为「连接」「讲解当前页」「发送消息」等按钮绑定 `createNpcClient().connect()`、`client.messenger.postMessage(...)` 即可。
|
|
216
|
+
### 4.7 WPS 场景唤醒(可选)
|
|
249
217
|
|
|
250
|
-
|
|
218
|
+
```ts
|
|
219
|
+
import {
|
|
220
|
+
MoonBridgeIpcClient,
|
|
221
|
+
WebSocketServerEndpoint,
|
|
222
|
+
WpsAppLauncher,
|
|
223
|
+
} from 'moonbridge-ts';
|
|
251
224
|
|
|
252
|
-
|
|
225
|
+
const client = MoonBridgeIpcClient.builder()
|
|
226
|
+
.clientName('client_a')
|
|
227
|
+
.useWebSocketChannel(
|
|
228
|
+
new WebSocketServerEndpoint({
|
|
229
|
+
address: '127.0.0.1',
|
|
230
|
+
port: 9091,
|
|
231
|
+
path: '/ws',
|
|
232
|
+
useTls: false,
|
|
233
|
+
}),
|
|
234
|
+
)
|
|
235
|
+
.appLauncher(
|
|
236
|
+
new WpsAppLauncher({
|
|
237
|
+
appUrl: 'server://',
|
|
238
|
+
fallbackMethod: 'linkClick',
|
|
239
|
+
}),
|
|
240
|
+
)
|
|
241
|
+
.build();
|
|
242
|
+
```
|
|
253
243
|
|
|
254
|
-
|
|
244
|
+
### 4.8 RPC 风格调用(装饰器 + rpcServiceFactory)
|
|
255
245
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
| ClientIdentity | ClientIdentity |
|
|
265
|
-
| ResultCallback | ResultCallback |
|
|
246
|
+
```ts
|
|
247
|
+
import {
|
|
248
|
+
IpcCallRetry,
|
|
249
|
+
IpcRemoteCall,
|
|
250
|
+
IpcRemoteClient,
|
|
251
|
+
IpcRequestJob,
|
|
252
|
+
MoonBridgeIpcClient,
|
|
253
|
+
} from 'moonbridge-ts';
|
|
266
254
|
|
|
267
|
-
|
|
255
|
+
@IpcRemoteClient({ name: 'client_b' })
|
|
256
|
+
abstract class CallPhoneService {
|
|
257
|
+
@IpcCallRetry({ retries: 3 })
|
|
258
|
+
@IpcRemoteCall({ module: 'CallPhone', method: 'callPhone' })
|
|
259
|
+
callPhone(_number: string): IpcRequestJob {
|
|
260
|
+
return IpcRequestJob.stub();
|
|
261
|
+
}
|
|
268
262
|
|
|
269
|
-
|
|
263
|
+
@IpcRemoteCall({ module: 'CallPhone', method: 'callWithCallback' })
|
|
264
|
+
callPhoneWithCallback(_number: string, _onResponse: (response: unknown[]) => void): IpcRequestJob {
|
|
265
|
+
return IpcRequestJob.stub();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
270
268
|
|
|
271
|
-
|
|
269
|
+
const client = MoonBridgeIpcClient.builder()
|
|
270
|
+
.clientName('client_a')
|
|
271
|
+
// ...省略 useWebSocketChannel(...)
|
|
272
|
+
.build(true);
|
|
272
273
|
|
|
273
|
-
|
|
274
|
-
npm install
|
|
275
|
-
npm run build # 产出 dist/
|
|
276
|
-
npm run test # 单元测试(Vitest)
|
|
277
|
-
npm run lint # ESLint
|
|
278
|
-
npm run format # Prettier
|
|
279
|
-
```
|
|
274
|
+
const service = client.rpcServiceFactory.createService(CallPhoneService);
|
|
280
275
|
|
|
281
|
-
|
|
276
|
+
service?.callPhone('11111').onIpcError((error) => {
|
|
277
|
+
console.error('IPC error:', error);
|
|
278
|
+
}).send();
|
|
282
279
|
|
|
283
|
-
|
|
280
|
+
service?.callPhoneWithCallback('176****0000', (response) => {
|
|
281
|
+
console.log('response:', response);
|
|
282
|
+
}).onIpcError((error) => {
|
|
283
|
+
console.error('IPC error:', error);
|
|
284
|
+
}).send();
|
|
285
|
+
```
|
|
284
286
|
|
|
285
|
-
|
|
286
|
-
- 客户端身份与鉴权与 Flutter 端一致:基于 clientName 及可选的 ClientIdentity,无 Token/Cookie。
|
|
287
|
-
- 本库**实现客户端和服务端**,客户端连接 NPC(moonbridge-ipc-flutter),服务端可供 NPC 或其他客户端连接。
|
|
287
|
+
## 5. 与 Flutter README 的对齐点
|
|
288
288
|
|
|
289
|
-
|
|
289
|
+
1. 角色模型一致:客户端负责收发,服务端负责转发与会话构建。
|
|
290
|
+
2. Builder 使用方式一致:链式配置后 `build(...)`。
|
|
291
|
+
3. 协议语义一致:握手、注册、请求、响应、错误、心跳、事件。
|
|
292
|
+
4. 模块能力一致:`@MoonBridgeModule` + `@MoonBridgeMethod`。
|
|
293
|
+
5. 客户端身份机制一致:服务端白名单控制可接入客户端。
|
|
290
294
|
|
|
291
|
-
##
|
|
295
|
+
## 6. 重要差异与注意事项
|
|
292
296
|
|
|
293
|
-
|
|
297
|
+
1. `MoonBridgeIpcServer` 只能在 Node.js 环境使用(浏览器无法监听端口)。
|
|
298
|
+
2. `MoonBridgeIpcClient` 可在 Node.js 和浏览器环境使用(仅需主动连接,不需监听端口)。
|
|
299
|
+
3. TS 端当前只支持 WebSocket,不支持 TCP Socket 客户端。
|
|
300
|
+
4. `useTls: true`(`wss`)当前未实现,需使用 `ws`。
|
|
301
|
+
5. 服务端如果不配置 `clientIdentityProviders`,客户端会因白名单校验失败而无法完成注册。
|
|
302
|
+
6. 模块通过装饰器运行时注册,模块文件必须被加载(import)后才能生效。
|
|
303
|
+
7. RPC 服务代理依赖装饰器元数据:服务类型需使用 `@IpcRemoteClient` 和 `@IpcRemoteCall` 标注后再通过 `client.rpcServiceFactory.createService(...)` 创建。
|
|
294
304
|
|
|
295
|
-
|
|
305
|
+
## 7. 开发命令
|
|
296
306
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
- **查阅 specs 与 contracts**:仓库内 `specs/001-moonbridge-js-refactor/` 含本改造的 spec、plan、tasks、contracts;`contracts/` 下为单文件结构、注释、Flutter–JS 一比一约定。
|
|
303
|
-
- **规范豁免**:自动生成代码(如未来 RPC 生成器产物)、对第三方 API 的极薄 wrapper 可豁免完整注释与分区规范,仅需文件头与对外入口简短说明;见 research.md 与 spec Edge Cases。
|
|
307
|
+
```bash
|
|
308
|
+
npm run build
|
|
309
|
+
npm run test
|
|
310
|
+
npm run lint
|
|
311
|
+
```
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MoonBridge IPC 客户端实际实现与注册表,对应 Flutter lib/client/internal/moonbridge_ipc_client.internal.dart。
|
|
3
|
-
* JS 端不实现 RPC(getService 恒返回 undefined)。
|
|
4
3
|
*/
|
|
5
4
|
import { IpcClientSettings } from './settings/ipc_client_settings';
|
|
6
5
|
import { IpcConnectionCompletionHandler } from '../types/ipc_types';
|
|
7
6
|
import { MoonBridgeIpcClient } from '../moonbridge_ipc_client';
|
|
8
|
-
import { Messenger, MessageEndpoint,
|
|
7
|
+
import { Messenger, MessageEndpoint, RoutedMessage } from '../types/ipc_messenger';
|
|
9
8
|
import { EventBus } from '../types/ipc_event_bus';
|
|
10
9
|
import { IpcClientComponentProvider } from './ipc/ipc_client_component_provider';
|
|
11
10
|
import { IpcConnectionManager } from './ipc/connect/ipc_connection_manager';
|
|
@@ -14,6 +13,7 @@ import { IpcCommunicationAgent } from './ipc/communication/ipc_communication_age
|
|
|
14
13
|
import { IpcEventBus } from './ipc/eventbus/ipc_event_bus';
|
|
15
14
|
import { IpcConnectionKeeper } from './ipc/keep/ipc_connection_keeper';
|
|
16
15
|
import { IpcClientBridge } from './bridge/ipc_client_bridge';
|
|
16
|
+
import { RpcServiceFactory } from '../rpc/rpc_service_factory';
|
|
17
17
|
/**
|
|
18
18
|
* 实际 IPC 客户端实现:继承组件装配,并实现 MoonBridgeIpcClient、Messenger。
|
|
19
19
|
* 装配顺序与 Flutter RealMoonBridgeIpcClient 一致;JS 不传入 moduleFactories(见 spec 012)。
|
|
@@ -26,6 +26,7 @@ export declare class RealMoonBridgeIpcClient implements IpcClientComponentProvid
|
|
|
26
26
|
readonly ipcEventBus: IpcEventBus;
|
|
27
27
|
readonly connectionKeeper: IpcConnectionKeeper;
|
|
28
28
|
readonly bridge: IpcClientBridge;
|
|
29
|
+
readonly rpcServiceFactory: RpcServiceFactory;
|
|
29
30
|
constructor(settings: IpcClientSettings);
|
|
30
31
|
get clientName(): string;
|
|
31
32
|
connect(onResult?: IpcConnectionCompletionHandler): void;
|
|
@@ -33,8 +34,8 @@ export declare class RealMoonBridgeIpcClient implements IpcClientComponentProvid
|
|
|
33
34
|
isConnected(): boolean;
|
|
34
35
|
get messenger(): Messenger;
|
|
35
36
|
get eventBus(): EventBus;
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
call(target: MessageEndpoint): RoutedMessage;
|
|
38
|
+
private sendMessage;
|
|
38
39
|
private realPostMessage;
|
|
39
40
|
}
|
|
40
41
|
//# sourceMappingURL=moonbridge_ipc_client.internal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"moonbridge_ipc_client.internal.d.ts","sourceRoot":"","sources":["../../../../src/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"moonbridge_ipc_client.internal.d.ts","sourceRoot":"","sources":["../../../../src/moonbridge-ipc/client/internal/moonbridge_ipc_client.internal.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAEnE,OAAO,EAAE,8BAA8B,EAAoB,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAAE,qBAAqB,EAAE,MAAM,6CAA6C,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAA4B,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEzF;;;GAGG;AACH,qBAAa,uBAAwB,YAAW,0BAA0B,EAAE,mBAAmB,EAAE,SAAS;IACxG,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,iBAAiB,EAAE,oBAAoB,CAAC;IACjD,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC;IACnD,QAAQ,CAAC,kBAAkB,EAAE,qBAAqB,CAAC;IACnD,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC;IAC/C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;gBAIlC,QAAQ,EAAE,iBAAiB;IAuBvC,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,OAAO,CAAC,QAAQ,CAAC,EAAE,8BAA8B,GAAG,IAAI;IAKlD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC,WAAW,IAAI,OAAO;IAItB,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED,IAAI,QAAQ,IAAI,QAAQ,CAEvB;IAED,IAAI,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa;IAgB5C,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,eAAe;CAqCxB"}
|