@x-oasis/async-call-rpc 0.1.38
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 +48 -0
- package/dist/async-call-rpc.cjs.development.js +1275 -0
- package/dist/async-call-rpc.cjs.development.js.map +1 -0
- package/dist/async-call-rpc.cjs.production.min.js +2 -0
- package/dist/async-call-rpc.cjs.production.min.js.map +1 -0
- package/dist/async-call-rpc.esm.js +1559 -0
- package/dist/async-call-rpc.esm.js.map +1 -0
- package/dist/buffer/BufferFactory.d.ts +12 -0
- package/dist/buffer/DataBuffer.d.ts +2 -0
- package/dist/buffer/MessagePackBuffer.d.ts +10 -0
- package/dist/buffer/ReadBaseBuffer.d.ts +5 -0
- package/dist/buffer/ReadBuffer.d.ts +14 -0
- package/dist/buffer/SerializationFormat.d.ts +16 -0
- package/dist/buffer/WriteBaseBuffer.d.ts +5 -0
- package/dist/buffer/WriteBuffer.d.ts +5 -0
- package/dist/buffer/examples.d.ts +10 -0
- package/dist/buffer/index.d.ts +8 -0
- package/dist/common.d.ts +4 -0
- package/dist/endpoint/ProxyRPCClient.d.ts +12 -0
- package/dist/endpoint/RPCClientHost.d.ts +12 -0
- package/dist/endpoint/RPCService.d.ts +20 -0
- package/dist/endpoint/RPCServiceHost.d.ts +10 -0
- package/dist/error.d.ts +21 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/middlewares/buffer.d.ts +18 -0
- package/dist/middlewares/handleDisconnectedRequest.d.ts +7 -0
- package/dist/middlewares/handlePortRequest.d.ts +3 -0
- package/dist/middlewares/handleRequest.d.ts +3 -0
- package/dist/middlewares/handleRequestUtils.d.ts +10 -0
- package/dist/middlewares/handleResponse.d.ts +3 -0
- package/dist/middlewares/index.d.ts +7 -0
- package/dist/middlewares/logger.d.ts +4 -0
- package/dist/middlewares/normalize.d.ts +14 -0
- package/dist/middlewares/prepareRequestData.d.ts +28 -0
- package/dist/middlewares/sendRequest.d.ts +6 -0
- package/dist/middlewares/updateSeqInfo.d.ts +6 -0
- package/dist/middlewares/utils.d.ts +3 -0
- package/dist/protocol/AbstractChannelProtocol.d.ts +55 -0
- package/dist/protocol/MessageChannel.d.ts +18 -0
- package/dist/protocol/WebSocketChannel.d.ts +23 -0
- package/dist/protocol/WorkerChannel.d.ts +11 -0
- package/dist/types/buffer.d.ts +4 -0
- package/dist/types/channel.d.ts +27 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/middleware.d.ts +44 -0
- package/dist/types/proxyChannel.d.ts +3 -0
- package/dist/types/proxyService.d.ts +11 -0
- package/dist/types/rpc.d.ts +25 -0
- package/dist/types/rpcProtocol.d.ts +22 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/jsonrpc.d.ts +36 -0
- package/package.json +36 -0
- package/src/buffer/ARCHITECTURE.md +298 -0
- package/src/buffer/BufferFactory.ts +124 -0
- package/src/buffer/CHANGELOG.md +207 -0
- package/src/buffer/DataBuffer.ts +1 -0
- package/src/buffer/MessagePackBuffer.ts +79 -0
- package/src/buffer/OPTIMIZATION.md +258 -0
- package/src/buffer/README.md +147 -0
- package/src/buffer/ReadBaseBuffer.ts +20 -0
- package/src/buffer/ReadBuffer.ts +58 -0
- package/src/buffer/SerializationFormat.ts +81 -0
- package/src/buffer/WriteBaseBuffer.ts +20 -0
- package/src/buffer/WriteBuffer.ts +15 -0
- package/src/buffer/examples.ts +242 -0
- package/src/buffer/index.ts +15 -0
- package/src/common.ts +20 -0
- package/src/endpoint/ProxyRPCClient.ts +64 -0
- package/src/endpoint/RPCClientHost.ts +45 -0
- package/src/endpoint/RPCService.ts +54 -0
- package/src/endpoint/RPCServiceHost.ts +18 -0
- package/src/error.ts +98 -0
- package/src/index.ts +16 -0
- package/src/middlewares/buffer.ts +33 -0
- package/src/middlewares/handleDisconnectedRequest.ts +30 -0
- package/src/middlewares/handlePortRequest.ts +141 -0
- package/src/middlewares/handleRequest.ts +128 -0
- package/src/middlewares/handleRequestUtils.ts +43 -0
- package/src/middlewares/handleResponse.ts +36 -0
- package/src/middlewares/index.ts +11 -0
- package/src/middlewares/logger.ts +22 -0
- package/src/middlewares/normalize.ts +167 -0
- package/src/middlewares/prepareRequestData.ts +137 -0
- package/src/middlewares/sendRequest.ts +15 -0
- package/src/middlewares/updateSeqInfo.ts +34 -0
- package/src/middlewares/utils.ts +67 -0
- package/src/protocol/AbstractChannelProtocol.ts +343 -0
- package/src/protocol/MessageChannel.ts +80 -0
- package/src/protocol/WebSocketChannel.ts +179 -0
- package/src/protocol/WorkerChannel.ts +36 -0
- package/src/types/buffer.ts +5 -0
- package/src/types/channel.ts +50 -0
- package/src/types/index.ts +9 -0
- package/src/types/messageChannel.ts +133 -0
- package/src/types/middleware.ts +54 -0
- package/src/types/proxyChannel.ts +3 -0
- package/src/types/proxyService.ts +18 -0
- package/src/types/rpc.ts +61 -0
- package/src/types/rpcProtocol.ts +24 -0
- package/src/utils/constants.ts +17 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/jsonrpc.ts +242 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import ReadBaseBuffer from './ReadBaseBuffer';
|
|
2
|
+
import WriteBaseBuffer from './WriteBaseBuffer';
|
|
3
|
+
import ReadBuffer from './ReadBuffer';
|
|
4
|
+
import WriteBuffer from './WriteBuffer';
|
|
5
|
+
import { SerializationFormat } from './SerializationFormat';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Factory for creating buffer instances based on serialization format
|
|
9
|
+
*
|
|
10
|
+
* This factory allows easy switching between different serialization formats
|
|
11
|
+
* and supports custom implementations.
|
|
12
|
+
*/
|
|
13
|
+
export class BufferFactory {
|
|
14
|
+
private static readBufferRegistry = new Map<string, () => ReadBaseBuffer>();
|
|
15
|
+
private static writeBufferRegistry = new Map<string, () => WriteBaseBuffer>();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Register a custom read buffer implementation
|
|
19
|
+
*/
|
|
20
|
+
static registerReadBuffer(
|
|
21
|
+
format: string,
|
|
22
|
+
factory: () => ReadBaseBuffer
|
|
23
|
+
): void {
|
|
24
|
+
this.readBufferRegistry.set(format, factory);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Register a custom write buffer implementation
|
|
29
|
+
*/
|
|
30
|
+
static registerWriteBuffer(
|
|
31
|
+
format: string,
|
|
32
|
+
factory: () => WriteBaseBuffer
|
|
33
|
+
): void {
|
|
34
|
+
this.writeBufferRegistry.set(format, factory);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Create a read buffer for the specified format
|
|
39
|
+
*/
|
|
40
|
+
static createReadBuffer(
|
|
41
|
+
format: SerializationFormat | string = SerializationFormat.JSON
|
|
42
|
+
): ReadBaseBuffer {
|
|
43
|
+
const factory = this.readBufferRegistry.get(format);
|
|
44
|
+
if (factory) {
|
|
45
|
+
return factory();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Default to JSON
|
|
49
|
+
switch (format) {
|
|
50
|
+
case SerializationFormat.JSON:
|
|
51
|
+
return new ReadBuffer();
|
|
52
|
+
case SerializationFormat.MESSAGEPACK:
|
|
53
|
+
// Try to load MessagePack if available
|
|
54
|
+
try {
|
|
55
|
+
// Dynamic import example (would need actual implementation)
|
|
56
|
+
// const { MessagePackReadBuffer } = require('./MessagePackBuffer');
|
|
57
|
+
// return new MessagePackReadBuffer();
|
|
58
|
+
throw new Error(
|
|
59
|
+
'MessagePack not available. Install @msgpack/msgpack and register it.'
|
|
60
|
+
);
|
|
61
|
+
} catch (e) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Unsupported read buffer format: ${format}. Register a custom implementation.`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
default:
|
|
67
|
+
throw new Error(`Unsupported read buffer format: ${format}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create a write buffer for the specified format
|
|
73
|
+
*/
|
|
74
|
+
static createWriteBuffer(
|
|
75
|
+
format: SerializationFormat | string = SerializationFormat.JSON
|
|
76
|
+
): WriteBaseBuffer {
|
|
77
|
+
const factory = this.writeBufferRegistry.get(format);
|
|
78
|
+
if (factory) {
|
|
79
|
+
return factory();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Default to JSON
|
|
83
|
+
switch (format) {
|
|
84
|
+
case SerializationFormat.JSON:
|
|
85
|
+
return new WriteBuffer();
|
|
86
|
+
case SerializationFormat.MESSAGEPACK:
|
|
87
|
+
// Try to load MessagePack if available
|
|
88
|
+
try {
|
|
89
|
+
// Dynamic import example (would need actual implementation)
|
|
90
|
+
// const { MessagePackWriteBuffer } = require('./MessagePackBuffer');
|
|
91
|
+
// return new MessagePackWriteBuffer();
|
|
92
|
+
throw new Error(
|
|
93
|
+
'MessagePack not available. Install @msgpack/msgpack and register it.'
|
|
94
|
+
);
|
|
95
|
+
} catch (e) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Unsupported write buffer format: ${format}. Register a custom implementation.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
default:
|
|
101
|
+
throw new Error(`Unsupported write buffer format: ${format}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get list of registered formats
|
|
107
|
+
*/
|
|
108
|
+
static getRegisteredFormats(): string[] {
|
|
109
|
+
const formats = new Set<string>();
|
|
110
|
+
this.readBufferRegistry.forEach((_, format) => formats.add(format));
|
|
111
|
+
this.writeBufferRegistry.forEach((_, format) => formats.add(format));
|
|
112
|
+
return Array.from(formats);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Register default JSON format
|
|
117
|
+
BufferFactory.registerReadBuffer(
|
|
118
|
+
SerializationFormat.JSON,
|
|
119
|
+
() => new ReadBuffer()
|
|
120
|
+
);
|
|
121
|
+
BufferFactory.registerWriteBuffer(
|
|
122
|
+
SerializationFormat.JSON,
|
|
123
|
+
() => new WriteBuffer()
|
|
124
|
+
);
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Buffer 优化变更日志
|
|
2
|
+
|
|
3
|
+
## 优化完成时间
|
|
4
|
+
2024年(当前)
|
|
5
|
+
|
|
6
|
+
## 概述
|
|
7
|
+
|
|
8
|
+
本次优化对 `async-call-rpc` 的 buffer 序列化系统进行了全面改进,实现了统一管理、配置化和高性能的序列化方案。
|
|
9
|
+
|
|
10
|
+
## 主要变更
|
|
11
|
+
|
|
12
|
+
### 1. 类型定义增强
|
|
13
|
+
|
|
14
|
+
**文件**: `src/types/channel.ts`
|
|
15
|
+
|
|
16
|
+
**新增**:
|
|
17
|
+
- `AbstractChannelProtocolProps` 类型,包含序列化配置选项:
|
|
18
|
+
- `serializationFormat?: string` - 序列化格式配置
|
|
19
|
+
- `readBuffer?: ReadBaseBuffer` - 自定义读 buffer
|
|
20
|
+
- `writeBuffer?: WriteBaseBuffer` - 自定义写 buffer
|
|
21
|
+
|
|
22
|
+
**影响**: 所有 Channel 构造函数现在都支持序列化配置
|
|
23
|
+
|
|
24
|
+
### 2. AbstractChannelProtocol 优化
|
|
25
|
+
|
|
26
|
+
**文件**: `src/protocol/AbstractChannelProtocol.ts`
|
|
27
|
+
|
|
28
|
+
**改进**:
|
|
29
|
+
- ✅ 使用 `BufferFactory` 统一创建 buffer 实例
|
|
30
|
+
- ✅ 支持通过构造函数配置序列化格式
|
|
31
|
+
- ✅ 实现智能缓存机制(首次创建,后续复用)
|
|
32
|
+
- ✅ 添加格式验证和自动回退机制(不支持时回退到 JSON)
|
|
33
|
+
- ✅ 新增 `setSerializationFormat()` 方法支持运行时切换
|
|
34
|
+
- ✅ 新增 `serializationFormat` getter 获取当前格式
|
|
35
|
+
|
|
36
|
+
**之前**:
|
|
37
|
+
```typescript
|
|
38
|
+
get readBuffer() {
|
|
39
|
+
if (this._readBuffer) return this._readBuffer;
|
|
40
|
+
this._readBuffer = new ReadBuffer(); // 硬编码 JSON
|
|
41
|
+
return this._readBuffer;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**现在**:
|
|
46
|
+
```typescript
|
|
47
|
+
get readBuffer(): ReadBaseBuffer {
|
|
48
|
+
if (this._readBuffer) return this._readBuffer;
|
|
49
|
+
// 使用工厂创建,支持配置格式
|
|
50
|
+
this._readBuffer = BufferFactory.createReadBuffer(this._serializationFormat);
|
|
51
|
+
return this._readBuffer;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 3. 子类 Channel 优化
|
|
56
|
+
|
|
57
|
+
**文件**:
|
|
58
|
+
- `src/protocol/MessageChannel.ts`
|
|
59
|
+
- `src/protocol/WebSocketChannel.ts`
|
|
60
|
+
- `src/protocol/WorkerChannel.ts`
|
|
61
|
+
|
|
62
|
+
**改进**:
|
|
63
|
+
- ✅ 移除直接创建 buffer 实例的代码
|
|
64
|
+
- ✅ 继承父类的 buffer getter(使用工厂和缓存)
|
|
65
|
+
- ✅ 构造函数支持 `AbstractChannelProtocolProps` 配置
|
|
66
|
+
- ✅ 统一使用父类的缓存机制
|
|
67
|
+
|
|
68
|
+
**之前**:
|
|
69
|
+
```typescript
|
|
70
|
+
get readBuffer() {
|
|
71
|
+
return new ReadBuffer(); // 每次都创建新实例
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**现在**:
|
|
76
|
+
```typescript
|
|
77
|
+
// 继承父类实现,使用工厂和缓存
|
|
78
|
+
// 可通过构造函数配置格式
|
|
79
|
+
constructor(options: { port: MessagePort } & AbstractChannelProtocolProps) {
|
|
80
|
+
super(options); // 传递配置给父类
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 4. 类型定义合并
|
|
85
|
+
|
|
86
|
+
**文件**: `src/types/messageChannel.ts`
|
|
87
|
+
|
|
88
|
+
**改进**:
|
|
89
|
+
- ✅ `AbstractChannelProtocolProps` 现在扩展自 `channel.ts` 中的基础定义
|
|
90
|
+
- ✅ 保持向后兼容,添加了序列化相关字段
|
|
91
|
+
|
|
92
|
+
## 使用方式变更
|
|
93
|
+
|
|
94
|
+
### 之前的使用方式
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// 只能使用默认的 JSON
|
|
98
|
+
const channel = new WebSocketChannel(socket);
|
|
99
|
+
|
|
100
|
+
// 要使用其他格式,需要重写 getter
|
|
101
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
102
|
+
get readBuffer() {
|
|
103
|
+
return new MessagePackReadBuffer(); // 需要手动实现
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### 现在的使用方式
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// 方式 1: 通过配置指定格式(推荐)
|
|
112
|
+
const channel = new WebSocketChannel(socket, {
|
|
113
|
+
serializationFormat: 'msgpack'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// 方式 2: 使用自定义 buffer
|
|
117
|
+
const channel = new MessageChannel({
|
|
118
|
+
port,
|
|
119
|
+
readBuffer: new MyCustomBuffer(),
|
|
120
|
+
writeBuffer: new MyCustomBuffer()
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 方式 3: 运行时切换
|
|
124
|
+
channel.setSerializationFormat('cbor');
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 性能改进
|
|
128
|
+
|
|
129
|
+
1. **缓存机制**: 所有 Channel 现在都使用缓存,避免重复创建 buffer 实例
|
|
130
|
+
2. **延迟初始化**: Buffer 实例在首次访问时才创建
|
|
131
|
+
3. **工厂模式**: 统一通过工厂创建,便于管理和优化
|
|
132
|
+
|
|
133
|
+
## 向后兼容性
|
|
134
|
+
|
|
135
|
+
✅ **完全向后兼容**
|
|
136
|
+
|
|
137
|
+
- 默认行为保持不变(使用 JSON)
|
|
138
|
+
- 不传配置时,行为与之前完全一致
|
|
139
|
+
- 现有的重写 getter 的代码仍然有效
|
|
140
|
+
|
|
141
|
+
## 迁移建议
|
|
142
|
+
|
|
143
|
+
### 如果之前重写了 buffer getter
|
|
144
|
+
|
|
145
|
+
**之前**:
|
|
146
|
+
```typescript
|
|
147
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
148
|
+
get readBuffer() {
|
|
149
|
+
return new ReadBuffer();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**现在(推荐)**:
|
|
155
|
+
```typescript
|
|
156
|
+
// 方式 1: 使用配置(推荐)
|
|
157
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
158
|
+
constructor(options?: AbstractChannelProtocolProps) {
|
|
159
|
+
super({ serializationFormat: 'msgpack', ...options });
|
|
160
|
+
}
|
|
161
|
+
// 不需要重写 getter
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 方式 2: 继续重写(如果需要特殊逻辑)
|
|
165
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
166
|
+
get readBuffer() {
|
|
167
|
+
if (this._readBuffer) return this._readBuffer;
|
|
168
|
+
this._readBuffer = BufferFactory.createReadBuffer('msgpack');
|
|
169
|
+
return this._readBuffer;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 新增功能
|
|
175
|
+
|
|
176
|
+
1. **格式配置**: 通过构造函数配置序列化格式
|
|
177
|
+
2. **运行时切换**: `setSerializationFormat()` 方法
|
|
178
|
+
3. **格式查询**: `serializationFormat` getter
|
|
179
|
+
4. **自动回退**: 格式不支持时自动回退到 JSON
|
|
180
|
+
5. **自定义 buffer**: 支持直接传入自定义 buffer 实例
|
|
181
|
+
|
|
182
|
+
## 测试建议
|
|
183
|
+
|
|
184
|
+
1. **基础功能**: 验证默认 JSON 行为不变
|
|
185
|
+
2. **格式配置**: 测试不同格式的配置和使用
|
|
186
|
+
3. **缓存机制**: 验证 buffer 实例被正确缓存
|
|
187
|
+
4. **格式切换**: 测试运行时格式切换
|
|
188
|
+
5. **错误处理**: 测试不支持的格式时的回退机制
|
|
189
|
+
|
|
190
|
+
## 相关文件
|
|
191
|
+
|
|
192
|
+
- `src/buffer/BufferFactory.ts` - 工厂实现
|
|
193
|
+
- `src/buffer/SerializationFormat.ts` - 格式定义
|
|
194
|
+
- `src/buffer/README.md` - 使用文档
|
|
195
|
+
- `src/buffer/ARCHITECTURE.md` - 架构说明
|
|
196
|
+
- `src/buffer/OPTIMIZATION.md` - 优化说明
|
|
197
|
+
|
|
198
|
+
## 总结
|
|
199
|
+
|
|
200
|
+
本次优化实现了:
|
|
201
|
+
- ✅ 统一的 buffer 管理机制
|
|
202
|
+
- ✅ 灵活的配置方式
|
|
203
|
+
- ✅ 性能优化(缓存)
|
|
204
|
+
- ✅ 易于扩展(工厂模式)
|
|
205
|
+
- ✅ 完全向后兼容
|
|
206
|
+
|
|
207
|
+
这些改进让序列化系统更加健壮、灵活和高效,同时保持了良好的向后兼容性。
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default class DataBuffer {}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import ReadBaseBuffer from './ReadBaseBuffer';
|
|
2
|
+
import WriteBaseBuffer from './WriteBaseBuffer';
|
|
3
|
+
import { SerializationFormat } from './SerializationFormat';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* MessagePack Read Buffer Implementation
|
|
7
|
+
*
|
|
8
|
+
* Note: This is a reference implementation. To use it, you need to install:
|
|
9
|
+
* npm install @msgpack/msgpack
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { encode, decode } from '@msgpack/msgpack';
|
|
14
|
+
*
|
|
15
|
+
* class MessagePackReadBuffer extends ReadBaseBuffer {
|
|
16
|
+
* decode(data: string | ArrayBuffer | Uint8Array): any {
|
|
17
|
+
* if (typeof data === 'string') {
|
|
18
|
+
* // Convert string to Uint8Array if needed
|
|
19
|
+
* const encoder = new TextEncoder();
|
|
20
|
+
* const uint8Array = encoder.encode(data);
|
|
21
|
+
* return decode(uint8Array);
|
|
22
|
+
* }
|
|
23
|
+
* return decode(data as Uint8Array);
|
|
24
|
+
* }
|
|
25
|
+
*
|
|
26
|
+
* getFormat(): string {
|
|
27
|
+
* return SerializationFormat.MESSAGEPACK;
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export class MessagePackReadBuffer extends ReadBaseBuffer {
|
|
33
|
+
decode(_data: string | ArrayBuffer | Uint8Array): any {
|
|
34
|
+
// This is a placeholder implementation
|
|
35
|
+
// In production, use: import { decode } from '@msgpack/msgpack';
|
|
36
|
+
throw new Error(
|
|
37
|
+
'MessagePack decoder not implemented. Please install @msgpack/msgpack and implement decode logic.'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getFormat(): string {
|
|
42
|
+
return SerializationFormat.MESSAGEPACK;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* MessagePack Write Buffer Implementation
|
|
48
|
+
*
|
|
49
|
+
* Note: This is a reference implementation. To use it, you need to install:
|
|
50
|
+
* npm install @msgpack/msgpack
|
|
51
|
+
*
|
|
52
|
+
* Usage:
|
|
53
|
+
* ```typescript
|
|
54
|
+
* import { encode } from '@msgpack/msgpack';
|
|
55
|
+
*
|
|
56
|
+
* class MessagePackWriteBuffer extends WriteBaseBuffer {
|
|
57
|
+
* encode(data: any): Uint8Array {
|
|
58
|
+
* return encode(data);
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* getFormat(): string {
|
|
62
|
+
* return SerializationFormat.MESSAGEPACK;
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export class MessagePackWriteBuffer extends WriteBaseBuffer {
|
|
68
|
+
encode(_data: any): Uint8Array {
|
|
69
|
+
// This is a placeholder implementation
|
|
70
|
+
// In production, use: import { encode } from '@msgpack/msgpack';
|
|
71
|
+
throw new Error(
|
|
72
|
+
'MessagePack encoder not implemented. Please install @msgpack/msgpack and implement encode logic.'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getFormat(): string {
|
|
77
|
+
return SerializationFormat.MESSAGEPACK;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Buffer 优化说明
|
|
2
|
+
|
|
3
|
+
## 优化内容
|
|
4
|
+
|
|
5
|
+
本次优化对 `async-call-rpc` 的 buffer 序列化机制进行了全面改进,实现了统一、可配置、高性能的序列化方案。
|
|
6
|
+
|
|
7
|
+
## 主要改进
|
|
8
|
+
|
|
9
|
+
### 1. ✅ 统一使用 BufferFactory
|
|
10
|
+
|
|
11
|
+
**之前的问题:**
|
|
12
|
+
- 每个 Channel 子类都直接创建 `new ReadBuffer()` / `new WriteBuffer()`
|
|
13
|
+
- 无法统一管理序列化格式
|
|
14
|
+
- 每次访问 getter 都创建新实例(性能问题)
|
|
15
|
+
|
|
16
|
+
**优化后:**
|
|
17
|
+
- 所有 Channel 统一使用 `BufferFactory` 创建 buffer
|
|
18
|
+
- 支持通过配置指定序列化格式
|
|
19
|
+
- 实现了实例缓存,避免重复创建
|
|
20
|
+
|
|
21
|
+
### 2. ✅ 支持配置化序列化格式
|
|
22
|
+
|
|
23
|
+
**新增功能:**
|
|
24
|
+
- 在构造函数中通过 `serializationFormat` 参数指定格式
|
|
25
|
+
- 支持运行时动态切换格式(`setSerializationFormat()`)
|
|
26
|
+
- 支持自定义 buffer 实例(`readBuffer` / `writeBuffer` 参数)
|
|
27
|
+
|
|
28
|
+
**使用示例:**
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// 方式 1: 通过配置指定格式
|
|
32
|
+
const channel = new WebSocketChannel(socket, {
|
|
33
|
+
serializationFormat: 'msgpack' // 使用 MessagePack
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 方式 2: 使用自定义 buffer
|
|
37
|
+
const customBuffer = new MyCustomBuffer();
|
|
38
|
+
const channel = new MessageChannel({
|
|
39
|
+
port,
|
|
40
|
+
readBuffer: customBuffer,
|
|
41
|
+
writeBuffer: customBuffer
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// 方式 3: 运行时切换格式
|
|
45
|
+
channel.setSerializationFormat('cbor');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 3. ✅ 优化缓存机制
|
|
49
|
+
|
|
50
|
+
**之前的问题:**
|
|
51
|
+
- `MessageChannel` 和 `WebSocketChannel` 每次访问都创建新实例
|
|
52
|
+
- `AbstractChannelProtocol` 有缓存,但子类重写后失效
|
|
53
|
+
|
|
54
|
+
**优化后:**
|
|
55
|
+
- 所有 Channel 都使用父类的缓存机制
|
|
56
|
+
- 首次访问时创建,后续访问复用实例
|
|
57
|
+
- 格式切换时自动清理缓存
|
|
58
|
+
|
|
59
|
+
### 4. ✅ 增强错误处理
|
|
60
|
+
|
|
61
|
+
**新增功能:**
|
|
62
|
+
- 格式不支持时自动回退到 JSON
|
|
63
|
+
- 提供清晰的错误提示和警告
|
|
64
|
+
- 支持自定义 buffer 的验证
|
|
65
|
+
|
|
66
|
+
### 5. ✅ 改进类型定义
|
|
67
|
+
|
|
68
|
+
**新增类型:**
|
|
69
|
+
- `AbstractChannelProtocolProps` - 统一的配置接口
|
|
70
|
+
- 所有 Channel 构造函数都支持序列化配置
|
|
71
|
+
|
|
72
|
+
## 使用指南
|
|
73
|
+
|
|
74
|
+
### 基础使用(默认 JSON)
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// 无需配置,默认使用 JSON
|
|
78
|
+
const channel = new WebSocketChannel(socket);
|
|
79
|
+
// 或者
|
|
80
|
+
const channel = new MessageChannel({ port });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 使用 MessagePack(高性能)
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// 1. 先注册 MessagePack(如果还没注册)
|
|
87
|
+
import { registerMessagePack } from '@x-oasis/async-call-rpc/buffer/examples';
|
|
88
|
+
registerMessagePack();
|
|
89
|
+
|
|
90
|
+
// 2. 创建 Channel 时指定格式
|
|
91
|
+
const channel = new WebSocketChannel(socket, {
|
|
92
|
+
serializationFormat: 'msgpack'
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### 使用自定义格式
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// 1. 实现自定义 buffer
|
|
100
|
+
class MyCustomBuffer extends ReadBaseBuffer {
|
|
101
|
+
decode(data: any): any {
|
|
102
|
+
// 自定义解码逻辑
|
|
103
|
+
}
|
|
104
|
+
getFormat(): string {
|
|
105
|
+
return 'my-format';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 2. 注册到工厂
|
|
110
|
+
import { BufferFactory } from '@x-oasis/async-call-rpc/buffer';
|
|
111
|
+
BufferFactory.registerReadBuffer('my-format', () => new MyCustomBuffer());
|
|
112
|
+
|
|
113
|
+
// 3. 使用
|
|
114
|
+
const channel = new MessageChannel({
|
|
115
|
+
port,
|
|
116
|
+
serializationFormat: 'my-format'
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### 运行时切换格式
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
const channel = new WebSocketChannel(socket);
|
|
124
|
+
|
|
125
|
+
// 初始使用 JSON
|
|
126
|
+
console.log(channel.serializationFormat); // 'json'
|
|
127
|
+
|
|
128
|
+
// 切换到 MessagePack
|
|
129
|
+
channel.setSerializationFormat('msgpack');
|
|
130
|
+
console.log(channel.serializationFormat); // 'msgpack'
|
|
131
|
+
|
|
132
|
+
// 下次访问 buffer 时会使用新格式
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 性能优化
|
|
136
|
+
|
|
137
|
+
### 缓存机制
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// 第一次访问:创建实例
|
|
141
|
+
const buffer1 = channel.readBuffer; // 创建新实例
|
|
142
|
+
|
|
143
|
+
// 后续访问:复用缓存
|
|
144
|
+
const buffer2 = channel.readBuffer; // 返回缓存的实例
|
|
145
|
+
console.log(buffer1 === buffer2); // true
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 格式切换
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
// 切换格式时,缓存会被清理
|
|
152
|
+
channel.setSerializationFormat('msgpack');
|
|
153
|
+
|
|
154
|
+
// 下次访问时会创建新实例
|
|
155
|
+
const buffer3 = channel.readBuffer; // 创建新的 MessagePack 实例
|
|
156
|
+
console.log(buffer1 === buffer3); // false
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## 迁移指南
|
|
160
|
+
|
|
161
|
+
### 从旧版本迁移
|
|
162
|
+
|
|
163
|
+
**之前:**
|
|
164
|
+
```typescript
|
|
165
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
166
|
+
get readBuffer() {
|
|
167
|
+
return new ReadBuffer(); // 每次都创建新实例
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get writeBuffer() {
|
|
171
|
+
return new WriteBuffer();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**现在(推荐):**
|
|
177
|
+
```typescript
|
|
178
|
+
// 方式 1: 使用配置(推荐)
|
|
179
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
180
|
+
constructor(options?: AbstractChannelProtocolProps) {
|
|
181
|
+
super({ serializationFormat: 'msgpack', ...options });
|
|
182
|
+
}
|
|
183
|
+
// 不需要重写 getter,使用父类的实现
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// 方式 2: 继续重写(如果需要特殊逻辑)
|
|
187
|
+
class MyChannel extends AbstractChannelProtocol {
|
|
188
|
+
get readBuffer() {
|
|
189
|
+
// 使用工厂创建,支持缓存
|
|
190
|
+
if (this._readBuffer) return this._readBuffer;
|
|
191
|
+
this._readBuffer = BufferFactory.createReadBuffer('msgpack');
|
|
192
|
+
return this._readBuffer;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## 配置选项
|
|
198
|
+
|
|
199
|
+
### AbstractChannelProtocolProps
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
interface AbstractChannelProtocolProps {
|
|
203
|
+
description?: string;
|
|
204
|
+
masterProcessName?: string;
|
|
205
|
+
connected?: boolean;
|
|
206
|
+
serializationFormat?: string; // 序列化格式:'json' | 'msgpack' | 'cbor' | ...
|
|
207
|
+
readBuffer?: ReadBaseBuffer; // 自定义读 buffer(覆盖 serializationFormat)
|
|
208
|
+
writeBuffer?: WriteBaseBuffer; // 自定义写 buffer(覆盖 serializationFormat)
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 最佳实践
|
|
213
|
+
|
|
214
|
+
1. **开发环境使用 JSON**:便于调试和查看数据
|
|
215
|
+
```typescript
|
|
216
|
+
const format = process.env.NODE_ENV === 'production' ? 'msgpack' : 'json';
|
|
217
|
+
const channel = new WebSocketChannel(socket, { serializationFormat: format });
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
2. **生产环境使用 MessagePack**:提升性能
|
|
221
|
+
```typescript
|
|
222
|
+
const channel = new WebSocketChannel(socket, {
|
|
223
|
+
serializationFormat: 'msgpack'
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
3. **统一配置**:在应用入口统一配置序列化格式
|
|
228
|
+
```typescript
|
|
229
|
+
const RPC_CONFIG = {
|
|
230
|
+
serializationFormat: process.env.RPC_FORMAT || 'json'
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const channel = new WebSocketChannel(socket, RPC_CONFIG);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
4. **错误处理**:监听格式不支持的情况
|
|
237
|
+
```typescript
|
|
238
|
+
try {
|
|
239
|
+
const channel = new WebSocketChannel(socket, {
|
|
240
|
+
serializationFormat: 'msgpack'
|
|
241
|
+
});
|
|
242
|
+
} catch (error) {
|
|
243
|
+
// 会自动回退到 JSON,但会输出警告
|
|
244
|
+
console.warn('MessagePack not available, using JSON');
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## 总结
|
|
249
|
+
|
|
250
|
+
通过本次优化,`async-call-rpc` 的 buffer 系统现在具备:
|
|
251
|
+
|
|
252
|
+
- ✅ **统一管理**:通过 BufferFactory 统一创建和管理
|
|
253
|
+
- ✅ **配置灵活**:支持多种配置方式
|
|
254
|
+
- ✅ **性能优化**:实例缓存,避免重复创建
|
|
255
|
+
- ✅ **易于扩展**:支持自定义格式和实现
|
|
256
|
+
- ✅ **向后兼容**:默认行为保持不变(使用 JSON)
|
|
257
|
+
|
|
258
|
+
这些改进让序列化系统更加健壮、灵活和高效。
|