@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.
Files changed (104) hide show
  1. package/README.md +48 -0
  2. package/dist/async-call-rpc.cjs.development.js +1275 -0
  3. package/dist/async-call-rpc.cjs.development.js.map +1 -0
  4. package/dist/async-call-rpc.cjs.production.min.js +2 -0
  5. package/dist/async-call-rpc.cjs.production.min.js.map +1 -0
  6. package/dist/async-call-rpc.esm.js +1559 -0
  7. package/dist/async-call-rpc.esm.js.map +1 -0
  8. package/dist/buffer/BufferFactory.d.ts +12 -0
  9. package/dist/buffer/DataBuffer.d.ts +2 -0
  10. package/dist/buffer/MessagePackBuffer.d.ts +10 -0
  11. package/dist/buffer/ReadBaseBuffer.d.ts +5 -0
  12. package/dist/buffer/ReadBuffer.d.ts +14 -0
  13. package/dist/buffer/SerializationFormat.d.ts +16 -0
  14. package/dist/buffer/WriteBaseBuffer.d.ts +5 -0
  15. package/dist/buffer/WriteBuffer.d.ts +5 -0
  16. package/dist/buffer/examples.d.ts +10 -0
  17. package/dist/buffer/index.d.ts +8 -0
  18. package/dist/common.d.ts +4 -0
  19. package/dist/endpoint/ProxyRPCClient.d.ts +12 -0
  20. package/dist/endpoint/RPCClientHost.d.ts +12 -0
  21. package/dist/endpoint/RPCService.d.ts +20 -0
  22. package/dist/endpoint/RPCServiceHost.d.ts +10 -0
  23. package/dist/error.d.ts +21 -0
  24. package/dist/index.d.ts +11 -0
  25. package/dist/index.js +8 -0
  26. package/dist/middlewares/buffer.d.ts +18 -0
  27. package/dist/middlewares/handleDisconnectedRequest.d.ts +7 -0
  28. package/dist/middlewares/handlePortRequest.d.ts +3 -0
  29. package/dist/middlewares/handleRequest.d.ts +3 -0
  30. package/dist/middlewares/handleRequestUtils.d.ts +10 -0
  31. package/dist/middlewares/handleResponse.d.ts +3 -0
  32. package/dist/middlewares/index.d.ts +7 -0
  33. package/dist/middlewares/logger.d.ts +4 -0
  34. package/dist/middlewares/normalize.d.ts +14 -0
  35. package/dist/middlewares/prepareRequestData.d.ts +28 -0
  36. package/dist/middlewares/sendRequest.d.ts +6 -0
  37. package/dist/middlewares/updateSeqInfo.d.ts +6 -0
  38. package/dist/middlewares/utils.d.ts +3 -0
  39. package/dist/protocol/AbstractChannelProtocol.d.ts +55 -0
  40. package/dist/protocol/MessageChannel.d.ts +18 -0
  41. package/dist/protocol/WebSocketChannel.d.ts +23 -0
  42. package/dist/protocol/WorkerChannel.d.ts +11 -0
  43. package/dist/types/buffer.d.ts +4 -0
  44. package/dist/types/channel.d.ts +27 -0
  45. package/dist/types/index.d.ts +7 -0
  46. package/dist/types/middleware.d.ts +44 -0
  47. package/dist/types/proxyChannel.d.ts +3 -0
  48. package/dist/types/proxyService.d.ts +11 -0
  49. package/dist/types/rpc.d.ts +25 -0
  50. package/dist/types/rpcProtocol.d.ts +22 -0
  51. package/dist/utils/constants.d.ts +5 -0
  52. package/dist/utils/index.d.ts +2 -0
  53. package/dist/utils/jsonrpc.d.ts +36 -0
  54. package/package.json +36 -0
  55. package/src/buffer/ARCHITECTURE.md +298 -0
  56. package/src/buffer/BufferFactory.ts +124 -0
  57. package/src/buffer/CHANGELOG.md +207 -0
  58. package/src/buffer/DataBuffer.ts +1 -0
  59. package/src/buffer/MessagePackBuffer.ts +79 -0
  60. package/src/buffer/OPTIMIZATION.md +258 -0
  61. package/src/buffer/README.md +147 -0
  62. package/src/buffer/ReadBaseBuffer.ts +20 -0
  63. package/src/buffer/ReadBuffer.ts +58 -0
  64. package/src/buffer/SerializationFormat.ts +81 -0
  65. package/src/buffer/WriteBaseBuffer.ts +20 -0
  66. package/src/buffer/WriteBuffer.ts +15 -0
  67. package/src/buffer/examples.ts +242 -0
  68. package/src/buffer/index.ts +15 -0
  69. package/src/common.ts +20 -0
  70. package/src/endpoint/ProxyRPCClient.ts +64 -0
  71. package/src/endpoint/RPCClientHost.ts +45 -0
  72. package/src/endpoint/RPCService.ts +54 -0
  73. package/src/endpoint/RPCServiceHost.ts +18 -0
  74. package/src/error.ts +98 -0
  75. package/src/index.ts +16 -0
  76. package/src/middlewares/buffer.ts +33 -0
  77. package/src/middlewares/handleDisconnectedRequest.ts +30 -0
  78. package/src/middlewares/handlePortRequest.ts +141 -0
  79. package/src/middlewares/handleRequest.ts +128 -0
  80. package/src/middlewares/handleRequestUtils.ts +43 -0
  81. package/src/middlewares/handleResponse.ts +36 -0
  82. package/src/middlewares/index.ts +11 -0
  83. package/src/middlewares/logger.ts +22 -0
  84. package/src/middlewares/normalize.ts +167 -0
  85. package/src/middlewares/prepareRequestData.ts +137 -0
  86. package/src/middlewares/sendRequest.ts +15 -0
  87. package/src/middlewares/updateSeqInfo.ts +34 -0
  88. package/src/middlewares/utils.ts +67 -0
  89. package/src/protocol/AbstractChannelProtocol.ts +343 -0
  90. package/src/protocol/MessageChannel.ts +80 -0
  91. package/src/protocol/WebSocketChannel.ts +179 -0
  92. package/src/protocol/WorkerChannel.ts +36 -0
  93. package/src/types/buffer.ts +5 -0
  94. package/src/types/channel.ts +50 -0
  95. package/src/types/index.ts +9 -0
  96. package/src/types/messageChannel.ts +133 -0
  97. package/src/types/middleware.ts +54 -0
  98. package/src/types/proxyChannel.ts +3 -0
  99. package/src/types/proxyService.ts +18 -0
  100. package/src/types/rpc.ts +61 -0
  101. package/src/types/rpcProtocol.ts +24 -0
  102. package/src/utils/constants.ts +17 -0
  103. package/src/utils/index.ts +5 -0
  104. package/src/utils/jsonrpc.ts +242 -0
@@ -0,0 +1,147 @@
1
+ # Buffer Serialization Formats
2
+
3
+ 本模块提供了可插拔的序列化/反序列化机制,支持多种数据格式用于 RPC 通信。
4
+
5
+ ## 支持的序列化格式
6
+
7
+ ### 1. JSON (默认)
8
+ - **格式**: `SerializationFormat.JSON`
9
+ - **特点**: 人类可读、易于调试、跨平台兼容
10
+ - **性能**: 中等,适合大多数场景
11
+ - **使用**: 默认格式,无需额外配置
12
+
13
+ ### 2. MessagePack (推荐高性能方案)
14
+ - **格式**: `SerializationFormat.MESSAGEPACK`
15
+ - **特点**: 二进制格式、体积小、性能高(比 JSON 快 2-3 倍)
16
+ - **性能**: 高,适合性能敏感场景
17
+ - **依赖**: `@msgpack/msgpack`
18
+
19
+ ### 3. CBOR
20
+ - **格式**: `SerializationFormat.CBOR`
21
+ - **特点**: 标准二进制格式(RFC 7049)、支持更多数据类型
22
+ - **性能**: 高
23
+ - **依赖**: `cbor` 或 `cbor-web`
24
+
25
+ ### 4. Protocol Buffers
26
+ - **格式**: `SerializationFormat.PROTOBUF`
27
+ - **特点**: Google 出品、高性能、需要 schema 定义
28
+ - **性能**: 极高,适合大规模系统
29
+ - **依赖**: `protobufjs` 或 `@grpc/proto-loader`
30
+
31
+ ## 使用方法
32
+
33
+ ### 方式 1: 在 Channel 中重写 buffer getter
34
+
35
+ ```typescript
36
+ import { SerializationFormat, BufferFactory } from '@x-oasis/async-call-rpc/buffer';
37
+ import AbstractChannelProtocol from './AbstractChannelProtocol';
38
+
39
+ class MyChannel extends AbstractChannelProtocol {
40
+ get readBuffer() {
41
+ // 使用 MessagePack
42
+ return BufferFactory.createReadBuffer(SerializationFormat.MESSAGEPACK);
43
+ }
44
+
45
+ get writeBuffer() {
46
+ return BufferFactory.createWriteBuffer(SerializationFormat.MESSAGEPACK);
47
+ }
48
+ }
49
+ ```
50
+
51
+ ### 方式 2: 注册自定义序列化器
52
+
53
+ ```typescript
54
+ import { BufferFactory } from '@x-oasis/async-call-rpc/buffer';
55
+ import { encode, decode } from '@msgpack/msgpack';
56
+ import ReadBaseBuffer from '@x-oasis/async-call-rpc/buffer/ReadBaseBuffer';
57
+ import WriteBaseBuffer from '@x-oasis/async-call-rpc/buffer/WriteBaseBuffer';
58
+
59
+ // 实现 MessagePack 序列化器
60
+ class MessagePackReadBuffer extends ReadBaseBuffer {
61
+ decode(data: string | ArrayBuffer | Uint8Array): any {
62
+ if (typeof data === 'string') {
63
+ const encoder = new TextEncoder();
64
+ return decode(encoder.encode(data));
65
+ }
66
+ return decode(data as Uint8Array);
67
+ }
68
+
69
+ getFormat(): string {
70
+ return 'msgpack';
71
+ }
72
+ }
73
+
74
+ class MessagePackWriteBuffer extends WriteBaseBuffer {
75
+ encode(data: any): Uint8Array {
76
+ return encode(data);
77
+ }
78
+
79
+ getFormat(): string {
80
+ return 'msgpack';
81
+ }
82
+ }
83
+
84
+ // 注册到工厂
85
+ BufferFactory.registerReadBuffer('msgpack', () => new MessagePackReadBuffer());
86
+ BufferFactory.registerWriteBuffer('msgpack', () => new MessagePackWriteBuffer());
87
+ ```
88
+
89
+ ### 方式 3: 使用工厂创建(推荐)
90
+
91
+ ```typescript
92
+ import { BufferFactory, SerializationFormat } from '@x-oasis/async-call-rpc/buffer';
93
+
94
+ // 创建 JSON buffer(默认)
95
+ const jsonReadBuffer = BufferFactory.createReadBuffer(SerializationFormat.JSON);
96
+ const jsonWriteBuffer = BufferFactory.createWriteBuffer(SerializationFormat.JSON);
97
+
98
+ // 创建 MessagePack buffer(需要先注册)
99
+ const msgpackReadBuffer = BufferFactory.createReadBuffer(SerializationFormat.MESSAGEPACK);
100
+ const msgpackWriteBuffer = BufferFactory.createWriteBuffer(SerializationFormat.MESSAGEPACK);
101
+ ```
102
+
103
+ ## 性能对比
104
+
105
+ 根据社区实践和基准测试:
106
+
107
+ | 格式 | 序列化速度 | 体积 | 可读性 | 推荐场景 |
108
+ |------|-----------|------|--------|---------|
109
+ | JSON | 基准 | 100% | ⭐⭐⭐⭐⭐ | 开发、调试、小数据量 |
110
+ | MessagePack | 2-3x | 60-70% | ⭐ | 生产环境、性能敏感 |
111
+ | CBOR | 2-3x | 60-70% | ⭐ | 标准兼容场景 |
112
+ | Protobuf | 3-5x | 50-60% | ⭐ | 大规模系统、跨服务 |
113
+
114
+ ## 内容协商
115
+
116
+ 未来可以支持在 RPC 握手时协商序列化格式:
117
+
118
+ ```typescript
119
+ // 客户端发送支持的格式列表
120
+ const supportedFormats = [
121
+ SerializationFormat.MESSAGEPACK,
122
+ SerializationFormat.JSON
123
+ ];
124
+
125
+ // 服务端选择最佳格式并返回
126
+ const selectedFormat = negotiateFormat(supportedFormats);
127
+ ```
128
+
129
+ ## 注意事项
130
+
131
+ 1. **二进制格式传输**: MessagePack、CBOR、Protobuf 等二进制格式需要确保传输层支持二进制数据(如 WebSocket 的 binary 模式)
132
+
133
+ 2. **类型兼容性**: 不同格式对 JavaScript 类型的支持不同:
134
+ - JSON: 不支持 Date、Map、Set、undefined 等
135
+ - MessagePack: 支持更多类型,包括 Date、Binary 等
136
+ - CBOR: 支持最广泛的类型
137
+
138
+ 3. **向后兼容**: 切换序列化格式时,需要确保客户端和服务端使用相同的格式
139
+
140
+ 4. **错误处理**: 序列化/反序列化失败时,应该回退到 JSON 或抛出明确的错误
141
+
142
+ ## 参考实现
143
+
144
+ - **JSON-RPC 2.0**: https://www.jsonrpc.org/specification
145
+ - **MessagePack**: https://msgpack.org/
146
+ - **CBOR**: https://cbor.io/
147
+ - **Protocol Buffers**: https://developers.google.com/protocol-buffers
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Base class for read buffer/deserialization
3
+ * Supports both string and binary (ArrayBuffer/Uint8Array) input
4
+ */
5
+ abstract class ReadBaseBuffer {
6
+ /**
7
+ * Decode/deserialize data
8
+ * @param data - Encoded data (string or binary)
9
+ * @returns Decoded data
10
+ */
11
+ abstract decode(data: string | ArrayBuffer | Uint8Array): any;
12
+
13
+ /**
14
+ * Get the format identifier this decoder supports
15
+ * @returns Format name (e.g., 'json', 'msgpack', 'cbor')
16
+ */
17
+ abstract getFormat(): string;
18
+ }
19
+
20
+ export default ReadBaseBuffer;
@@ -0,0 +1,58 @@
1
+ import ReadBaseBuffer from './ReadBaseBuffer';
2
+
3
+ export enum DataType {
4
+ Undefined = 0,
5
+ String = 1,
6
+ Buffer = 2,
7
+ VSBuffer = 3,
8
+ Array = 4,
9
+ Object = 5,
10
+ Int = 6,
11
+ }
12
+
13
+ /**
14
+ * JSON-based read buffer implementation
15
+ * Default deserializer using JSON.parse
16
+ */
17
+ export default class ReadBuffer extends ReadBaseBuffer {
18
+ decode(data: string | ArrayBuffer | Uint8Array): any {
19
+ // Handle binary input (convert to string first)
20
+ if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
21
+ const decoder = new TextDecoder();
22
+ const text = decoder.decode(data);
23
+ return JSON.parse(text);
24
+ }
25
+ // Handle string input
26
+ return JSON.parse(data as string);
27
+ }
28
+
29
+ getFormat(): string {
30
+ return 'json';
31
+ }
32
+ }
33
+
34
+ // export class BufferReader implements IReader {
35
+
36
+ // private pos = 0;
37
+
38
+ // constructor(private buffer: VSBuffer) { }
39
+
40
+ // read(bytes: number): VSBuffer {
41
+ // const result = this.buffer.slice(this.pos, this.pos + bytes);
42
+ // this.pos += result.byteLength;
43
+ // return result;
44
+ // }
45
+ // }
46
+
47
+ // export class BufferWriter implements IWriter {
48
+
49
+ // private buffers: VSBuffer[] = [];
50
+
51
+ // get buffer(): VSBuffer {
52
+ // return VSBuffer.concat(this.buffers);
53
+ // }
54
+
55
+ // write(buffer: VSBuffer): void {
56
+ // this.buffers.push(buffer);
57
+ // }
58
+ // }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Supported serialization formats for RPC communication
3
+ *
4
+ * Based on JSON-RPC community practices:
5
+ * - JSON: Default, human-readable, good for debugging
6
+ * - MessagePack: Binary format, 2-3x faster, smaller size
7
+ * - CBOR: Standard binary format (RFC 7049)
8
+ * - Protobuf: High performance, requires schema
9
+ */
10
+ export enum SerializationFormat {
11
+ /** JSON - Default text format, human-readable */
12
+ JSON = 'json',
13
+ /** MessagePack - Binary format, high performance */
14
+ MESSAGEPACK = 'msgpack',
15
+ /** CBOR - Concise Binary Object Representation (RFC 7049) */
16
+ CBOR = 'cbor',
17
+ /** Protocol Buffers - High performance, schema-based */
18
+ PROTOBUF = 'protobuf',
19
+ /** Custom format - User-defined serialization */
20
+ CUSTOM = 'custom',
21
+ }
22
+
23
+ /**
24
+ * Serialization format metadata
25
+ */
26
+ export interface SerializationFormatInfo {
27
+ format: SerializationFormat;
28
+ name: string;
29
+ description: string;
30
+ mimeType: string;
31
+ isBinary: boolean;
32
+ isText: boolean;
33
+ }
34
+
35
+ /**
36
+ * Format metadata registry
37
+ */
38
+ export const FORMAT_INFO: Record<SerializationFormat, SerializationFormatInfo> =
39
+ {
40
+ [SerializationFormat.JSON]: {
41
+ format: SerializationFormat.JSON,
42
+ name: 'JSON',
43
+ description: 'JavaScript Object Notation - Human-readable text format',
44
+ mimeType: 'application/json',
45
+ isBinary: false,
46
+ isText: true,
47
+ },
48
+ [SerializationFormat.MESSAGEPACK]: {
49
+ format: SerializationFormat.MESSAGEPACK,
50
+ name: 'MessagePack',
51
+ description:
52
+ 'Binary serialization format - High performance, compact size',
53
+ mimeType: 'application/x-msgpack',
54
+ isBinary: true,
55
+ isText: false,
56
+ },
57
+ [SerializationFormat.CBOR]: {
58
+ format: SerializationFormat.CBOR,
59
+ name: 'CBOR',
60
+ description: 'Concise Binary Object Representation (RFC 7049)',
61
+ mimeType: 'application/cbor',
62
+ isBinary: true,
63
+ isText: false,
64
+ },
65
+ [SerializationFormat.PROTOBUF]: {
66
+ format: SerializationFormat.PROTOBUF,
67
+ name: 'Protocol Buffers',
68
+ description: 'Google Protocol Buffers - Schema-based binary format',
69
+ mimeType: 'application/x-protobuf',
70
+ isBinary: true,
71
+ isText: false,
72
+ },
73
+ [SerializationFormat.CUSTOM]: {
74
+ format: SerializationFormat.CUSTOM,
75
+ name: 'Custom',
76
+ description: 'User-defined custom serialization format',
77
+ mimeType: 'application/octet-stream',
78
+ isBinary: true,
79
+ isText: false,
80
+ },
81
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Base class for write buffer/serialization
3
+ * Supports both string and binary (ArrayBuffer/Uint8Array) output
4
+ */
5
+ abstract class WriteBaseBuffer {
6
+ /**
7
+ * Encode/serialize data
8
+ * @param data - Data to encode
9
+ * @returns Encoded data (string for text formats, ArrayBuffer/Uint8Array for binary formats)
10
+ */
11
+ abstract encode(data: any): string | ArrayBuffer | Uint8Array;
12
+
13
+ /**
14
+ * Get the format identifier for content negotiation
15
+ * @returns Format name (e.g., 'json', 'msgpack', 'cbor')
16
+ */
17
+ abstract getFormat(): string;
18
+ }
19
+
20
+ export default WriteBaseBuffer;
@@ -0,0 +1,15 @@
1
+ import WriteBaseBuffer from './WriteBaseBuffer';
2
+
3
+ /**
4
+ * JSON-based write buffer implementation
5
+ * Default serializer using JSON.stringify
6
+ */
7
+ export default class WriteBuffer extends WriteBaseBuffer {
8
+ encode(data: any): string {
9
+ return JSON.stringify(data);
10
+ }
11
+
12
+ getFormat(): string {
13
+ return 'json';
14
+ }
15
+ }
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Examples of using different serialization formats
3
+ *
4
+ * This file demonstrates how to use various serialization formats
5
+ * with the async-call-rpc buffer system.
6
+ */
7
+
8
+ import { BufferFactory, SerializationFormat } from './index';
9
+ import ReadBaseBuffer from './ReadBaseBuffer';
10
+ import WriteBaseBuffer from './WriteBaseBuffer';
11
+
12
+ // ============================================================================
13
+ // Example 1: Using MessagePack (requires @msgpack/msgpack)
14
+ // ============================================================================
15
+
16
+ /**
17
+ * To use MessagePack, first install the dependency:
18
+ * npm install @msgpack/msgpack
19
+ *
20
+ * Then implement the buffers:
21
+ */
22
+ export function registerMessagePack() {
23
+ // Dynamic import to avoid requiring the dependency if not used
24
+ // In production, you might want to use a static import
25
+ try {
26
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
27
+ const { encode, decode } = require('@msgpack/msgpack');
28
+
29
+ class MessagePackReadBuffer extends ReadBaseBuffer {
30
+ decode(data: string | ArrayBuffer | Uint8Array): any {
31
+ if (typeof data === 'string') {
32
+ // Convert string to Uint8Array
33
+ const encoder = new TextEncoder();
34
+ return decode(encoder.encode(data));
35
+ }
36
+ // Handle ArrayBuffer or Uint8Array
37
+ const uint8Array =
38
+ data instanceof ArrayBuffer ? new Uint8Array(data) : data;
39
+ return decode(uint8Array);
40
+ }
41
+
42
+ getFormat(): string {
43
+ return SerializationFormat.MESSAGEPACK;
44
+ }
45
+ }
46
+
47
+ class MessagePackWriteBuffer extends WriteBaseBuffer {
48
+ encode(data: any): Uint8Array {
49
+ return encode(data);
50
+ }
51
+
52
+ getFormat(): string {
53
+ return SerializationFormat.MESSAGEPACK;
54
+ }
55
+ }
56
+
57
+ // Register with the factory
58
+ BufferFactory.registerReadBuffer(
59
+ SerializationFormat.MESSAGEPACK,
60
+ () => new MessagePackReadBuffer()
61
+ );
62
+ BufferFactory.registerWriteBuffer(
63
+ SerializationFormat.MESSAGEPACK,
64
+ () => new MessagePackWriteBuffer()
65
+ );
66
+
67
+ return true;
68
+ } catch (e) {
69
+ console.warn(
70
+ 'MessagePack not available. Install @msgpack/msgpack to use it.'
71
+ );
72
+ return false;
73
+ }
74
+ }
75
+
76
+ // ============================================================================
77
+ // Example 2: Using CBOR (requires cbor or cbor-web)
78
+ // ============================================================================
79
+
80
+ /**
81
+ * To use CBOR, install one of:
82
+ * npm install cbor
83
+ * npm install cbor-web
84
+ */
85
+ export function registerCBOR() {
86
+ try {
87
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
88
+ const cbor = require('cbor');
89
+
90
+ class CBORReadBuffer extends ReadBaseBuffer {
91
+ decode(data: string | ArrayBuffer | Uint8Array): any {
92
+ if (typeof data === 'string') {
93
+ const encoder = new TextEncoder();
94
+ const uint8Array = encoder.encode(data);
95
+ return cbor.decode(uint8Array);
96
+ }
97
+ const uint8Array =
98
+ data instanceof ArrayBuffer ? new Uint8Array(data) : data;
99
+ return cbor.decode(uint8Array);
100
+ }
101
+
102
+ getFormat(): string {
103
+ return SerializationFormat.CBOR;
104
+ }
105
+ }
106
+
107
+ class CBORWriteBuffer extends WriteBaseBuffer {
108
+ encode(data: any): Uint8Array {
109
+ return cbor.encode(data);
110
+ }
111
+
112
+ getFormat(): string {
113
+ return SerializationFormat.CBOR;
114
+ }
115
+ }
116
+
117
+ BufferFactory.registerReadBuffer(
118
+ SerializationFormat.CBOR,
119
+ () => new CBORReadBuffer()
120
+ );
121
+ BufferFactory.registerWriteBuffer(
122
+ SerializationFormat.CBOR,
123
+ () => new CBORWriteBuffer()
124
+ );
125
+
126
+ return true;
127
+ } catch (e) {
128
+ console.warn('CBOR not available. Install cbor or cbor-web to use it.');
129
+ return false;
130
+ }
131
+ }
132
+
133
+ // ============================================================================
134
+ // Example 3: Custom serialization format
135
+ // ============================================================================
136
+
137
+ /**
138
+ * Example of a custom compression + JSON serialization
139
+ */
140
+ export function registerCompressedJSON() {
141
+ class CompressedJSONReadBuffer extends ReadBaseBuffer {
142
+ decode(data: string | ArrayBuffer | Uint8Array): any {
143
+ // In a real implementation, you would decompress first
144
+ // This is just a placeholder
145
+ if (typeof data === 'string') {
146
+ return JSON.parse(data);
147
+ }
148
+ const decoder = new TextDecoder();
149
+ const text = decoder.decode(data);
150
+ return JSON.parse(text);
151
+ }
152
+
153
+ getFormat(): string {
154
+ return 'compressed-json';
155
+ }
156
+ }
157
+
158
+ class CompressedJSONWriteBuffer extends WriteBaseBuffer {
159
+ encode(data: any): string {
160
+ // In a real implementation, you would compress the JSON
161
+ // This is just a placeholder
162
+ return JSON.stringify(data);
163
+ }
164
+
165
+ getFormat(): string {
166
+ return 'compressed-json';
167
+ }
168
+ }
169
+
170
+ BufferFactory.registerReadBuffer(
171
+ 'compressed-json',
172
+ () => new CompressedJSONReadBuffer()
173
+ );
174
+ BufferFactory.registerWriteBuffer(
175
+ 'compressed-json',
176
+ () => new CompressedJSONWriteBuffer()
177
+ );
178
+ }
179
+
180
+ // ============================================================================
181
+ // Example 4: Using in a Channel
182
+ // ============================================================================
183
+
184
+ /**
185
+ * Example of using a custom format in a channel implementation
186
+ */
187
+ export function createChannelWithMessagePack() {
188
+ // First register MessagePack
189
+ if (!registerMessagePack()) {
190
+ throw new Error('MessagePack not available');
191
+ }
192
+
193
+ // Then use it in your channel
194
+ // This would be in your channel class:
195
+ /*
196
+ class MyChannel extends AbstractChannelProtocol {
197
+ get readBuffer() {
198
+ return BufferFactory.createReadBuffer(SerializationFormat.MESSAGEPACK);
199
+ }
200
+
201
+ get writeBuffer() {
202
+ return BufferFactory.createWriteBuffer(SerializationFormat.MESSAGEPACK);
203
+ }
204
+ }
205
+ */
206
+ }
207
+
208
+ // ============================================================================
209
+ // Example 5: Format negotiation
210
+ // ============================================================================
211
+
212
+ /**
213
+ * Example of format negotiation between client and server
214
+ * This would typically happen during connection handshake
215
+ */
216
+ export interface FormatNegotiation {
217
+ clientFormats: string[];
218
+ serverFormats: string[];
219
+ selectedFormat?: string;
220
+ }
221
+
222
+ export function negotiateFormat(
223
+ clientFormats: string[],
224
+ serverFormats: string[]
225
+ ): string | null {
226
+ // Find the first format that both support
227
+ for (const format of clientFormats) {
228
+ if (serverFormats.includes(format)) {
229
+ return format;
230
+ }
231
+ }
232
+
233
+ // Fallback to JSON if available
234
+ if (
235
+ clientFormats.includes(SerializationFormat.JSON) &&
236
+ serverFormats.includes(SerializationFormat.JSON)
237
+ ) {
238
+ return SerializationFormat.JSON;
239
+ }
240
+
241
+ return null;
242
+ }
@@ -0,0 +1,15 @@
1
+ export { default as ReadBuffer } from './ReadBuffer';
2
+ export { default as WriteBuffer } from './WriteBuffer';
3
+ export { default as DataBuffer } from './DataBuffer';
4
+ export { default as ReadBaseBuffer } from './ReadBaseBuffer';
5
+ export { default as WriteBaseBuffer } from './WriteBaseBuffer';
6
+ export {
7
+ SerializationFormat,
8
+ FORMAT_INFO,
9
+ type SerializationFormatInfo,
10
+ } from './SerializationFormat';
11
+ export { BufferFactory } from './BufferFactory';
12
+ export {
13
+ MessagePackReadBuffer,
14
+ MessagePackWriteBuffer,
15
+ } from './MessagePackBuffer';
package/src/common.ts ADDED
@@ -0,0 +1,20 @@
1
+ import { isUpperAsciiLetter } from '@x-oasis/is-ascii';
2
+
3
+ export const isEventMethod = (name: string) => {
4
+ if (typeof name !== 'string') return false;
5
+ return (
6
+ name[0] === 'o' && name[1] === 'n' && isUpperAsciiLetter(name.charCodeAt(2))
7
+ );
8
+ };
9
+
10
+ export const isAssignPassingPortMethod = (name: string) => {
11
+ return /^assignPassingPort$/.test(name);
12
+ };
13
+
14
+ export const isAcquirePortMethod = (name: string) => {
15
+ return /^acquire.*Port$/.test(name);
16
+ };
17
+
18
+ export const isOptionsMethod = (name: string) => {
19
+ return /Options$/.test(name) || /OptionsRequest$/.test(name);
20
+ };
@@ -0,0 +1,64 @@
1
+ import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
2
+
3
+ class ProxyRPCClient {
4
+ readonly requestPath: string;
5
+
6
+ private channel: AbstractChannelProtocol;
7
+
8
+ constructor(
9
+ requestPath: string,
10
+ options?: {
11
+ channel?: AbstractChannelProtocol;
12
+ }
13
+ ) {
14
+ const { channel } = options || {};
15
+ this.requestPath = requestPath;
16
+ if (channel) {
17
+ this.setChannel(channel);
18
+ }
19
+ }
20
+
21
+ setChannel(channel: AbstractChannelProtocol) {
22
+ this.channel = channel;
23
+ // this.channel.on(this.handleMessage.bind(this));
24
+ }
25
+
26
+ handleMessage(...args: any[]) {
27
+ this.channel.onMessage(...args);
28
+ }
29
+
30
+ createProxy<T = object>(): T {
31
+ const getTrap =
32
+ (_: any, methodName: string) =>
33
+ (...args: any[]) => {
34
+ if (!this.channel) {
35
+ throw new Error(
36
+ `[ProxyRPCClient error] \`this.channel\` is null, when invoke function ${methodName}`
37
+ );
38
+ }
39
+ return this.channel.makeRequest({
40
+ requestPath: this.requestPath,
41
+ methodName,
42
+ args,
43
+ // @ts-ignore, 这个地方其实是跟 `updateSeqInfo` 中间件配合的
44
+ // 因为`updateSeqInfo` 中间件会在`makeRequest`之后,将返回值设置到`returnValue`中
45
+ // 所以这里需要返回`promise`,以便于在`createProxy`中能够正确地返回`promise`
46
+ // 否则的话,会出现`promise`不正确的问题
47
+ // 因为`makeRequest`会返回`promise`,但是`createProxy`会返回`proxy`
48
+ // 所以这里需要返回`promise`,以便于在`createProxy`中能够正确地返回`promise`
49
+ // 否则的话,会出现`promise`不正确的问题
50
+ // 因为`makeRequest`会返回`promise`,但是`createProxy`会返回`proxy`
51
+ // 所以这里需要返回`promise`,以便于在`createProxy`中能够正确地返回`promise`
52
+ }).promise;
53
+ };
54
+
55
+ return new Proxy(
56
+ {},
57
+ {
58
+ get: getTrap,
59
+ }
60
+ ) as any as T;
61
+ }
62
+ }
63
+
64
+ export default ProxyRPCClient;