moonbridge-ts
v0.7.0
Published
MoonBridge IPC by WebSocket for node(server) and browser(client).
Downloads
1,484
Readme
moonbridge-ts
基于 MoonBridge 通信协议的 TypeScript IPC 库,面向 WebSocket 场景(浏览器、WPS 加载项、Node)。
1. moonbridge-ts 是什么?
moonbridge-ts 是 moonbridge IPC 的 TypeScript 实现,用于在不同进程/应用之间进行消息通信。
角色模型与 Flutter 版本一致:
- 客户端:发送请求、接收请求、处理回调、发布/订阅事件。
- 服务端:负责客户端注册、消息转发、会话建立、唤醒目标客户端。
当前 TS 版本传输层仅提供 WebSocket 通道(ws://)。
角色环境限制:
server角色需要监听端口,浏览器环境受限,MoonBridgeIpcServer只能在 Node.js 环境使用。client角色不需要监听端口,MoonBridgeIpcClient可在 Node.js 和浏览器环境使用。
2. 当前提供的能力
- 支持单应用/多应用跨进程通信(经 IPC 服务端转发)。
- 支持 Request/Response/Error 三类消息与回调链路。
- 支持消息拦截(
MessageInterceptor)。 - 支持连接状态监听(
ConnectionObserver)。 - 支持心跳保活(默认开启,默认 3000ms)。
- 支持客户端身份认证(服务端白名单
ClientIdentityProvider)。 - 支持自动唤醒目标应用(
autoLaunch+AppLauncher)。 - 支持 1 对 1 指定客户端通信。
- 支持 EventBus 广播通信。
- 支持端口候选策略(
PortCandidateRule,服务端按规则尝试绑定端口,客户端按规则尝试连接端口)。 - 支持 WPS 场景 deeplink 唤醒(
WpsAppLauncher)。
2.1 PortCandidateRule 作用说明
PortCandidateRule 用于在端口不确定或端口可能被占用时,给 server/client 提供一致的端口尝试规则:
- 服务端启动时,如果初始端口被占用,会按
PortCandidateRule生成的有序端口列表继续尝试绑定,直到某个端口启动成功,或所有候选端口尝试完毕后启动失败。 - 客户端连接时,会按同一规则生成的有序端口列表依次尝试连接;每个端口都会执行连接和握手校验,直到连接并握手成功,或所有候选端口尝试完毕后连接失败。
- 该机制可避免“固定端口冲突导致整体不可用”,并确保 server 与 client 共享相同的端口探索顺序。
3. API 设计概览
客户端(MoonBridgeIpcClient)
MoonBridgeIpcClient.builder()connect(onResult?)disconnect()isConnected()messenger.call(target).args(...).onError(...).strategy(...).send()rpcServiceFactory.createService(ServiceType, clientName?)eventBus.register(subscriber)eventBus.unregister(subscriber)eventBus.post(event)
服务端(MoonBridgeIpcServer)
MoonBridgeIpcServer.builder()start(): Promise<boolean>stop(): Promise<void>clientIdentityProviders([...])messagePreprocessor(...)onMessageReceived(...)wakeAppInterceptor(...)
传输层(与 Flutter 抽象保持一致)
TransportClient 统一接口:
connectWithServer()sendData(data)onMessage(cb)onErrorAndClose({ onError, onServerClose })close()isClientConnected
4. 接入流程与示例
4.1 安装
npm install moonbridge-ts4.2 初始化服务端(Node)
import {
MoonBridgeIpcServer,
WebSocketServerEndpoint,
ClientIdentity,
} from 'moonbridge-ts';
const endpoint = new WebSocketServerEndpoint({
address: '0.0.0.0',
port: 9091,
path: '/ws',
useTls: false,
});
const getClientIdentity = (clientName: string) => {
switch (clientName) {
case 'client_a':
return new ClientIdentity('client_a');
case 'client_b':
return new ClientIdentity('client_b');
default:
return undefined;
}
};
const server = MoonBridgeIpcServer.builder()
.serverName('moonbridge_server')
.useWebSocketChannel(endpoint)
.clientIdentityProviders([getClientIdentity])
.build(true);
const started = await server.start();
if (!started) {
throw new Error('IPC server start failed');
}4.3 初始化客户端
import {
MoonBridgeIpcClient,
WebSocketServerEndpoint,
IpcMessageStrategy,
} from 'moonbridge-ts';
const client = MoonBridgeIpcClient.builder()
.clientName('client_a')
.useWebSocketChannel(
new WebSocketServerEndpoint({
address: '127.0.0.1',
port: 9091,
path: '/ws',
useTls: false,
}),
)
.messageStrategy(new IpcMessageStrategy(1, true))
.build(true);
client.connect((isConnected, error) => {
if (isConnected) {
console.log('connect success');
return;
}
console.error('connect failed', error);
});4.4 客户端接收消息(模块方式)
import {
Bridge,
BridgeModule,
MoonBridgeMethod,
MoonBridgeModule,
ResultCallback,
} from 'moonbridge-ts';
@MoonBridgeModule('CallPhone')
export class CallModule extends BridgeModule {
constructor(bridge: Bridge) {
super(bridge);
}
@MoonBridgeMethod('callWithCallback')
callWithCallback(phoneNumber: string, callback: ResultCallback): void {
console.log(`[MoonBridge] call: ${phoneNumber}`);
callback.invoke(['callback - Success']);
}
}tsconfig.json 需开启:
{
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"useDefineForClassFields": false
}4.5 客户端发送消息
// 方式:call(推荐)
client.messenger
.call({ clientName: 'client_b', moduleName: 'CallPhone', methodName: 'callWithCallback' })
.args('0431-4610123', (response) => console.log('response:', response))
.onError((error) => console.error('ipc error:', error))
.send();4.6 EventBus(订阅与发布)
import { Subscriber } from 'moonbridge-ts';
import { Event } from 'moonbridge-ts/moonbridge-ipc/general/message/event';
const subscriber = new Subscriber('TestEvent', (event) => {
console.log('event:', event.type, event.data);
});
client.eventBus.register(subscriber);
await client.eventBus.post(new Event('TestEvent', 'client_a', { key: 'hello' }));4.7 WPS 场景唤醒(可选)
import {
MoonBridgeIpcClient,
WebSocketServerEndpoint,
WpsAppLauncher,
} from 'moonbridge-ts';
const client = MoonBridgeIpcClient.builder()
.clientName('client_a')
.useWebSocketChannel(
new WebSocketServerEndpoint({
address: '127.0.0.1',
port: 9091,
path: '/ws',
useTls: false,
}),
)
.appLauncher(
new WpsAppLauncher({
appUrl: 'server://',
fallbackMethod: 'linkClick',
}),
)
.build();4.8 RPC 风格调用(装饰器 + rpcServiceFactory)
import {
IpcCallRetry,
IpcRemoteCall,
IpcRemoteClient,
IpcRequestJob,
MoonBridgeIpcClient,
} from 'moonbridge-ts';
@IpcRemoteClient({ name: 'client_b' })
abstract class CallPhoneService {
@IpcCallRetry({ retries: 3 })
@IpcRemoteCall({ module: 'CallPhone', method: 'callPhone' })
callPhone(_number: string): IpcRequestJob {
return IpcRequestJob.stub();
}
@IpcRemoteCall({ module: 'CallPhone', method: 'callWithCallback' })
callPhoneWithCallback(_number: string, _onResponse: (response: unknown[]) => void): IpcRequestJob {
return IpcRequestJob.stub();
}
}
const client = MoonBridgeIpcClient.builder()
.clientName('client_a')
// ...省略 useWebSocketChannel(...)
.build(true);
const service = client.rpcServiceFactory.createService(CallPhoneService);
service?.callPhone('11111').onIpcError((error) => {
console.error('IPC error:', error);
}).send();
service?.callPhoneWithCallback('176****0000', (response) => {
console.log('response:', response);
}).onIpcError((error) => {
console.error('IPC error:', error);
}).send();5. 与 Flutter README 的对齐点
- 角色模型一致:客户端负责收发,服务端负责转发与会话构建。
- Builder 使用方式一致:链式配置后
build(...)。 - 协议语义一致:握手、注册、请求、响应、错误、心跳、事件。
- 模块能力一致:
@MoonBridgeModule+@MoonBridgeMethod。 - 客户端身份机制一致:服务端白名单控制可接入客户端。
6. 重要差异与注意事项
MoonBridgeIpcServer只能在 Node.js 环境使用(浏览器无法监听端口)。MoonBridgeIpcClient可在 Node.js 和浏览器环境使用(仅需主动连接,不需监听端口)。- TS 端当前只支持 WebSocket,不支持 TCP Socket 客户端。
useTls: true(wss)当前未实现,需使用ws。- 服务端如果不配置
clientIdentityProviders,客户端会因白名单校验失败而无法完成注册。 - 模块通过装饰器运行时注册,模块文件必须被加载(import)后才能生效。
- RPC 服务代理依赖装饰器元数据:服务类型需使用
@IpcRemoteClient和@IpcRemoteCall标注后再通过client.rpcServiceFactory.createService(...)创建。
7. 开发命令
npm run build
npm run test
npm run lint