@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,6 @@
1
+ import { SenderMiddlewareOutput, SendMiddlewareLifecycle } from '../types';
2
+ import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
3
+ export declare const updateSeqInfo: (channelProtocol: AbstractChannelProtocol) => {
4
+ (value: SenderMiddlewareOutput): SenderMiddlewareOutput;
5
+ lifecycle: SendMiddlewareLifecycle;
6
+ };
@@ -0,0 +1,3 @@
1
+ import { MiddlewareContext, PendingSendEntry } from '../types';
2
+ export declare const resumeMiddlewares: (middlewares: any, entry: PendingSendEntry) => any;
3
+ export declare const runMiddlewares: (middlewares: any, args: any[], _context?: MiddlewareContext) => any;
@@ -0,0 +1,55 @@
1
+ import { Disposable } from '@x-oasis/disposable';
2
+ import { Deferred } from '@x-oasis/deferred';
3
+ import { SendingProps, IMessageChannel, ClientMiddleware, SenderMiddleware, PendingSendEntry, AbstractChannelProtocolProps } from '../types';
4
+ import ReadBaseBuffer from '../buffer/ReadBaseBuffer';
5
+ import WriteBaseBuffer from '../buffer/WriteBaseBuffer';
6
+ import RPCService from '../endpoint/RPCService';
7
+ declare abstract class AbstractChannelProtocol extends Disposable implements IMessageChannel {
8
+ private readonly _masterProcessName;
9
+ private _key;
10
+ private _service;
11
+ private readonly _description;
12
+ private _seqId;
13
+ protected _onMessageMiddleware: ClientMiddleware[];
14
+ private _senderMiddleware;
15
+ private _readBuffer;
16
+ private _writeBuffer;
17
+ private _serializationFormat;
18
+ private _isConnected;
19
+ ongoingRequests: Map<string, Deferred>;
20
+ pendingSendEntries: Set<PendingSendEntry>;
21
+ requestEvents: Map<string, any>;
22
+ private onDidConnectedEvent;
23
+ onDidConnected: (listener: Function) => import("@x-oasis/disposable").IDisposable;
24
+ private onDidDisconnectedEvent;
25
+ onDidDisconnected: (listener: Function) => import("@x-oasis/disposable").IDisposable;
26
+ constructor(props?: AbstractChannelProtocolProps);
27
+ get service(): RPCService;
28
+ setService(service: RPCService): void;
29
+ get senderMiddleware(): any[];
30
+ get readBuffer(): ReadBaseBuffer;
31
+ get writeBuffer(): WriteBaseBuffer;
32
+ get serializationFormat(): string;
33
+ setSerializationFormat(format: string): void;
34
+ get seqId(): string;
35
+ get description(): string;
36
+ get masterProcessName(): string;
37
+ addPendingSendEntry(entry: PendingSendEntry): void;
38
+ decorateSendMiddleware(middlewares: SenderMiddleware[]): any[];
39
+ decorateOnMessageMiddleware(middlewares: ClientMiddleware[]): any[];
40
+ applyOnMessageMiddleware(fns: Function | Function[]): void;
41
+ applySendMiddleware(fns: Function | Function[]): void;
42
+ isConnected(): boolean;
43
+ send(..._args: any[]): void;
44
+ on(..._args: any[]): void;
45
+ resumePendingEntry(): void;
46
+ didConnected(): void;
47
+ connect(): void;
48
+ activate(): void;
49
+ disconnect(): void;
50
+ makeRequest(props: SendingProps, transfer?: MessagePort[]): Deferred | void;
51
+ makeRequest(requestPath: string, fnName: string, ...args: any[]): Deferred | void;
52
+ sendReply(...args: any[]): void;
53
+ onMessage(...args: any[]): void;
54
+ }
55
+ export default AbstractChannelProtocol;
@@ -0,0 +1,18 @@
1
+ import { IMessageChannel, AbstractChannelProtocolProps } from '../types/channel';
2
+ import AbstractChannelProtocol from './AbstractChannelProtocol';
3
+ import { SenderMiddleware, ClientMiddleware } from '../types';
4
+ export default class RPCMessageChannel extends AbstractChannelProtocol implements IMessageChannel {
5
+ private readonly port;
6
+ private sender;
7
+ private targetOrigin;
8
+ constructor(options: {
9
+ port: MessagePort;
10
+ sender?: any;
11
+ targetOrigin?: string;
12
+ } & AbstractChannelProtocolProps);
13
+ on(listener: (event: MessageEvent) => void): void | (() => void);
14
+ send(message: any, transfer?: Transferable[]): void;
15
+ decorateSendMiddleware(middlewares: SenderMiddleware[]): any[];
16
+ decorateOnMessageMiddleware(middlewares: ClientMiddleware[]): any[];
17
+ disconnect(): void;
18
+ }
@@ -0,0 +1,23 @@
1
+ import AbstractChannelProtocol from './AbstractChannelProtocol';
2
+ import { SenderMiddleware, ClientMiddleware, AbstractChannelProtocolProps } from '../types';
3
+ export default class WebSocketChannel extends AbstractChannelProtocol {
4
+ private socket;
5
+ readonly name: string;
6
+ private reconnectAttempts;
7
+ private maxReconnectAttempts;
8
+ private reconnectDelay;
9
+ constructor(socket: WebSocket, options?: {
10
+ name?: string;
11
+ maxReconnectAttempts?: number;
12
+ reconnectDelay?: number;
13
+ connected?: boolean;
14
+ } & AbstractChannelProtocolProps);
15
+ private setupSocketHandlers;
16
+ on(listener: (data: unknown) => void): void | (() => void);
17
+ send(data: unknown): void;
18
+ decorateSendMiddleware(middlewares: SenderMiddleware[]): any[];
19
+ decorateOnMessageMiddleware(middlewares: ClientMiddleware[]): any[];
20
+ disconnect(): void;
21
+ get readyState(): number;
22
+ isOpen(): boolean;
23
+ }
@@ -0,0 +1,11 @@
1
+ import AbstractChannelProtocol from './AbstractChannelProtocol';
2
+ import { AbstractChannelProtocolProps } from '../types/channel';
3
+ export default class WorkerChannel extends AbstractChannelProtocol {
4
+ private worker;
5
+ readonly name: string;
6
+ constructor(worker: any, options?: {
7
+ name?: string;
8
+ } & AbstractChannelProtocolProps);
9
+ on(listener: (data: unknown) => void): void | (() => void);
10
+ send(data: unknown): void;
11
+ }
@@ -0,0 +1,4 @@
1
+ export declare type DataBuffer = {
2
+ flush: () => void;
3
+ drain: () => void;
4
+ };
@@ -0,0 +1,27 @@
1
+ export declare type IMessageChannelOnClose = () => void;
2
+ export declare type IMessageChannelOnError = () => void;
3
+ export declare type IMessageChannelOnMessage = (message: any) => void;
4
+ export declare type IMessageChannelSend = (options: any) => void;
5
+ export declare type IMessageChannelDisconnect = () => void;
6
+ export declare type IMessageChannel = {
7
+ onClose?: IMessageChannelOnClose;
8
+ onError?: IMessageChannelOnError;
9
+ onMessage: IMessageChannelOnMessage;
10
+ send: IMessageChannelSend;
11
+ disconnect: IMessageChannelDisconnect;
12
+ };
13
+ export declare type SendingProps = {
14
+ requestPath: string;
15
+ methodName: string;
16
+ args?: any[];
17
+ isOptionsRequest?: boolean;
18
+ transfer?: MessagePort[];
19
+ };
20
+ export declare type AbstractChannelProtocolProps = {
21
+ description?: string;
22
+ masterProcessName?: string;
23
+ connected?: boolean;
24
+ serializationFormat?: string;
25
+ readBuffer?: any;
26
+ writeBuffer?: any;
27
+ };
@@ -0,0 +1,7 @@
1
+ export * from './channel';
2
+ export * from './rpc';
3
+ export * from './proxyChannel';
4
+ export * from './proxyService';
5
+ export * from './middleware';
6
+ export declare type ClientMiddleware = any;
7
+ export declare type SenderMiddleware = any;
@@ -0,0 +1,44 @@
1
+ import { Deferred } from '@x-oasis/deferred';
2
+ import { HostRequestEntry, RequestEntry } from './rpc';
3
+ export declare type MiddlewareFunction = {
4
+ (...args: any[]): any;
5
+ displayName?: string;
6
+ lifecycle?: SendMiddlewareLifecycle;
7
+ };
8
+ export declare type MessageOutput = {
9
+ event: any;
10
+ ports: any;
11
+ };
12
+ export declare type NormalizedRawMessageOutput = MessageOutput & {
13
+ data: string;
14
+ };
15
+ export declare type DeserializedMessageOutput = MessageOutput & {
16
+ data: HostRequestEntry | RequestEntry;
17
+ };
18
+ export declare type SenderMiddlewareOutput = {
19
+ data: any;
20
+ transfer: any;
21
+ seqId: number;
22
+ returnValue: Deferred;
23
+ isOptionsRequest: boolean;
24
+ middlewareContext: MiddlewareContext;
25
+ };
26
+ export declare type PendingSendEntry = SenderMiddlewareOutput & {
27
+ methodName: string;
28
+ lifecycle: SendMiddlewareLifecycle;
29
+ middlewareContext: MiddlewareContext;
30
+ };
31
+ export declare type MiddlewareContext = {
32
+ isResumed?: boolean;
33
+ startLifecycle: SendMiddlewareLifecycle;
34
+ minLifecycle: SendMiddlewareLifecycle;
35
+ reserved: PendingSendEntry;
36
+ };
37
+ export declare enum SendMiddlewareLifecycle {
38
+ Initial = 0,
39
+ Prepare = 10,
40
+ Transform = 20,
41
+ DataOperation = 30,
42
+ Send = 40,
43
+ Aborted = 100
44
+ }
@@ -0,0 +1,3 @@
1
+ export declare type ProxyChannelProps = {
2
+ name: string;
3
+ };
@@ -0,0 +1,11 @@
1
+ import AbstractChannelProtocol from '../protocol/AbstractChannelProtocol';
2
+ export declare type IService = any;
3
+ export declare type ServiceHandlerPath = string;
4
+ export declare type ProxyRPCClientChannel = AbstractChannelProtocol | {
5
+ (): AbstractChannelProtocol;
6
+ };
7
+ export declare type ProxyRPCClientProps = {
8
+ requestPath: string;
9
+ channel: ProxyRPCClientChannel;
10
+ };
11
+ export declare type ServiceHandlers = Record<string, (...args: any[]) => any>;
@@ -0,0 +1,25 @@
1
+ export declare enum RequestType {
2
+ PromiseRequest = "pr",
3
+ PromiseAbort = "pa",
4
+ SignalRequest = "sr",
5
+ SignalAbort = "sa"
6
+ }
7
+ export declare type RequestRawSequenceId = number;
8
+ export declare type RequestSequenceId = string;
9
+ export declare type RequestServicePath = string;
10
+ export declare type RequestFnName = string;
11
+ export declare type RequestEntryHeader = [RequestType, RequestSequenceId, RequestServicePath, RequestFnName];
12
+ export declare type RequestEntryBody = any;
13
+ export declare type RequestEntry = [RequestEntryHeader, RequestEntryBody];
14
+ export declare enum ResponseType {
15
+ ReturnSuccess = "rs",
16
+ ReturnFail = "rf",
17
+ PortSuccess = "ps",
18
+ PortFail = "pf"
19
+ }
20
+ export declare type ResponseEntryHeader = [ResponseType, RequestSequenceId];
21
+ export declare type ResponseEntryBody = any;
22
+ export declare type HostName = string;
23
+ export declare type HostRequestEntryHeader = [RequestType, RequestSequenceId, RequestServicePath, RequestFnName, HostName];
24
+ export declare type HostRequestEntryBody = any;
25
+ export declare type HostRequestEntry = [HostRequestEntryHeader, HostRequestEntryBody];
@@ -0,0 +1,22 @@
1
+ export declare type IRPCProtocolServer = {
2
+ source: any;
3
+ encoder: null;
4
+ decoder: null;
5
+ onRequest: () => {};
6
+ handleRequest: () => {};
7
+ sendReply: () => {};
8
+ };
9
+ export declare type IRPCProtocolClient = {
10
+ source: any;
11
+ encode: () => {};
12
+ decode: () => {};
13
+ sendRequest: () => {};
14
+ onReply: () => {};
15
+ handleReply: () => {};
16
+ };
17
+ export declare type IRPCProtocol = {
18
+ encode: Function;
19
+ decode: Function;
20
+ onMessage: Function;
21
+ send: Function;
22
+ };
@@ -0,0 +1,5 @@
1
+ export declare const ERROR = "Error";
2
+ export declare const isArray: (arg: any) => arg is any[];
3
+ export declare const isObject: (val: unknown) => val is object;
4
+ export declare const isFunction: (val: unknown) => val is Function;
5
+ export declare const UNDEFINED: any;
@@ -0,0 +1,2 @@
1
+ export * from './jsonrpc';
2
+ export * from './constants';
@@ -0,0 +1,36 @@
1
+ import { ID, ErrorResponse } from '../error';
2
+ export declare const jsonrpc: "2.0";
3
+ export interface Request {
4
+ readonly jsonrpc: typeof jsonrpc;
5
+ readonly id?: ID;
6
+ readonly method: string;
7
+ readonly params: readonly unknown[] | object;
8
+ readonly remoteStack?: string;
9
+ }
10
+ export interface SuccessResponse {
11
+ readonly jsonrpc: typeof jsonrpc;
12
+ readonly id?: ID;
13
+ readonly result: unknown;
14
+ readonly undef?: boolean;
15
+ }
16
+ export declare type Response = SuccessResponse | ErrorResponse<unknown>;
17
+ export declare type ErrorMapFunction<T = unknown> = (error: unknown, request: Request) => {
18
+ code: number;
19
+ message: string;
20
+ data?: T;
21
+ };
22
+ export interface AsyncCallErrorDetail {
23
+ readonly stack?: string;
24
+ readonly type?: string;
25
+ }
26
+ export declare const makeRequest: (id: ID, method: string, params: readonly unknown[] | object, remoteStack?: string) => Request;
27
+ export declare const makeSuccessResponse: (id: ID, result: unknown) => SuccessResponse;
28
+ export declare const makeErrorResponse: <T>(id: ID, code: number, message: string, data?: T) => ErrorResponse<T>;
29
+ export declare const ErrorResponseParseError: <T>(e: unknown, mapper: ErrorMapFunction<T>) => ErrorResponse<T>;
30
+ export declare const ErrorResponseInvalidRequest: (id: ID) => ErrorResponse;
31
+ export declare const ErrorResponseMethodNotFound: (id: ID) => ErrorResponse;
32
+ export declare const ErrorResponseInvalidParams: (id: ID) => ErrorResponse;
33
+ export declare const ErrorResponseInternalError: (id: ID) => ErrorResponse;
34
+ export declare const ErrorResponseMapped: <T>(request: Request, e: unknown, mapper: ErrorMapFunction<T>) => ErrorResponse<T>;
35
+ export declare const defaultErrorMapper: (stack?: string, code?: number) => ErrorMapFunction<AsyncCallErrorDetail>;
36
+ export declare const isJSONRPCObject: (data: any) => data is Request | SuccessResponse | ErrorResponse<unknown>;
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@x-oasis/async-call-rpc",
3
+ "version": "0.1.38",
4
+ "description": "async-call-rpc function",
5
+ "main": "dist/index.js",
6
+ "typings": "dist/index.d.ts",
7
+ "module": "dist/async-call-rpc.esm.js",
8
+ "files": [
9
+ "dist",
10
+ "index.ts",
11
+ "src"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "author": "",
17
+ "license": "ISC",
18
+ "devDependencies": {
19
+ "tsdx": "^0.14.1",
20
+ "ws": "^8.19.0"
21
+ },
22
+ "dependencies": {
23
+ "@x-oasis/deferred": "0.1.38",
24
+ "@x-oasis/disposable": "0.1.38",
25
+ "@x-oasis/emitter": "0.1.38",
26
+ "@x-oasis/id": "0.1.38",
27
+ "@x-oasis/is-ascii": "0.1.38",
28
+ "@x-oasis/is-promise": "0.1.38"
29
+ },
30
+ "scripts": {
31
+ "build": "tsdx build --tsconfig tsconfig.build.json",
32
+ "clean": "rimraf ./dist",
33
+ "test": "vitest",
34
+ "compile": "tsc -p tsconfig.build.json"
35
+ }
36
+ }
@@ -0,0 +1,298 @@
1
+ # 分层可配置设计说明
2
+
3
+ ## 什么是"分层可配置设计"?
4
+
5
+ "分层可配置设计"指的是将系统按照**职责分离**成不同的层次,每一层都可以**独立配置和替换**,而不影响其他层。
6
+
7
+ ## 架构层次图
8
+
9
+ ```
10
+ ┌─────────────────────────────────────────────────────────┐
11
+ │ 应用层 (Application) │
12
+ │ - 业务逻辑代码 │
13
+ │ - 调用 RPC 方法 │
14
+ └─────────────────────────────────────────────────────────┘
15
+
16
+ ┌─────────────────────────────────────────────────────────┐
17
+ │ RPC 协议层 (Protocol Layer) │
18
+ │ - AbstractChannelProtocol │
19
+ │ - WebSocketChannel / MessageChannel / WorkerChannel │
20
+ │ - 负责消息路由、请求管理 │
21
+ └─────────────────────────────────────────────────────────┘
22
+
23
+ ┌─────────────────────────────────────────────────────────┐
24
+ │ 中间件层 (Middleware Layer) │
25
+ │ - serialize / deserialize │
26
+ │ - handleRequest / handleResponse │
27
+ │ - 可插拔的中间件链 │
28
+ └─────────────────────────────────────────────────────────┘
29
+
30
+ ┌─────────────────────────────────────────────────────────┐
31
+ │ 序列化抽象层 (Serialization Abstraction) │
32
+ │ - ReadBaseBuffer / WriteBaseBuffer (抽象接口) │
33
+ │ - 定义统一的 encode/decode 接口 │
34
+ └─────────────────────────────────────────────────────────┘
35
+
36
+ ┌─────────────────────────────────────────────────────────┐
37
+ │ 序列化实现层 (Serialization Implementation) │
38
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
39
+ │ │ JSON │ │ MessagePack │ │ CBOR │ │
40
+ │ │ ReadBuffer │ │ ReadBuffer │ │ ReadBuffer │ │
41
+ │ │ WriteBuffer │ │ WriteBuffer │ │ WriteBuffer │ │
42
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
43
+ │ │
44
+ │ - 多种序列化格式的具体实现 │
45
+ │ - 可以随时添加新的实现 │
46
+ └─────────────────────────────────────────────────────────┘
47
+
48
+ ┌─────────────────────────────────────────────────────────┐
49
+ │ 工厂层 (Factory Layer) │
50
+ │ - BufferFactory │
51
+ │ - 格式注册表 (Registry) │
52
+ │ - 根据配置创建对应的序列化器 │
53
+ └─────────────────────────────────────────────────────────┘
54
+ ```
55
+
56
+ ## 核心概念
57
+
58
+ ### 1. **分层 (Layered)**
59
+
60
+ 每一层只关注自己的职责:
61
+
62
+ - **应用层**: 只管调用 RPC,不关心序列化细节
63
+ - **协议层**: 只管消息传输,不关心数据格式
64
+ - **中间件层**: 只管数据转换流程,不关心具体序列化算法
65
+ - **抽象层**: 定义接口契约,不关心具体实现
66
+ - **实现层**: 只管序列化算法,不关心上层如何使用
67
+ - **工厂层**: 只管创建和注册,不关心具体实现
68
+
69
+ ### 2. **可配置 (Configurable)**
70
+
71
+ 每一层都可以通过配置来改变行为:
72
+
73
+ ```typescript
74
+ // 配置方式 1: 在 Channel 中配置
75
+ class MyChannel extends AbstractChannelProtocol {
76
+ get readBuffer() {
77
+ // 可以配置为 JSON
78
+ return BufferFactory.createReadBuffer(SerializationFormat.JSON);
79
+ // 或者配置为 MessagePack
80
+ // return BufferFactory.createReadBuffer(SerializationFormat.MESSAGEPACK);
81
+ }
82
+ }
83
+
84
+ // 配置方式 2: 通过工厂注册自定义实现
85
+ BufferFactory.registerReadBuffer('my-format', () => new MyCustomBuffer());
86
+
87
+ // 配置方式 3: 运行时动态切换
88
+ const format = getFormatFromConfig(); // 从配置文件读取
89
+ const buffer = BufferFactory.createReadBuffer(format);
90
+ ```
91
+
92
+ ## 设计优势
93
+
94
+ ### ✅ 1. **解耦 (Decoupling)**
95
+
96
+ 各层之间通过接口通信,互不依赖:
97
+
98
+ ```typescript
99
+ // 中间件层不需要知道具体是 JSON 还是 MessagePack
100
+ export const serialize = (channel: AbstractChannelProtocol) => {
101
+ const fn = (value: SenderMiddlewareOutput) => ({
102
+ ...value,
103
+ // 只调用抽象接口,不关心具体实现
104
+ data: channel.writeBuffer.encode(value.data),
105
+ });
106
+ return fn;
107
+ };
108
+ ```
109
+
110
+ ### ✅ 2. **可扩展 (Extensible)**
111
+
112
+ 添加新格式不需要修改现有代码:
113
+
114
+ ```typescript
115
+ // 添加新的序列化格式,只需要:
116
+ // 1. 实现 ReadBaseBuffer 和 WriteBaseBuffer
117
+ class MyNewFormatBuffer extends ReadBaseBuffer {
118
+ decode(data: any): any { /* ... */ }
119
+ getFormat(): string { return 'my-format'; }
120
+ }
121
+
122
+ // 2. 注册到工厂
123
+ BufferFactory.registerReadBuffer('my-format', () => new MyNewFormatBuffer());
124
+
125
+ // 3. 使用
126
+ const buffer = BufferFactory.createReadBuffer('my-format');
127
+ // 完成!不需要修改任何其他代码
128
+ ```
129
+
130
+ ### ✅ 3. **可替换 (Replaceable)**
131
+
132
+ 可以轻松切换不同的实现:
133
+
134
+ ```typescript
135
+ // 开发环境使用 JSON(便于调试)
136
+ const devBuffer = BufferFactory.createReadBuffer(SerializationFormat.JSON);
137
+
138
+ // 生产环境使用 MessagePack(性能更好)
139
+ const prodBuffer = BufferFactory.createReadBuffer(SerializationFormat.MESSAGEPACK);
140
+
141
+ // 根据环境变量切换
142
+ const buffer = process.env.NODE_ENV === 'production'
143
+ ? prodBuffer
144
+ : devBuffer;
145
+ ```
146
+
147
+ ### ✅ 4. **可测试 (Testable)**
148
+
149
+ 每一层都可以独立测试:
150
+
151
+ ```typescript
152
+ // 测试序列化实现层
153
+ describe('MessagePackBuffer', () => {
154
+ it('should encode and decode correctly', () => {
155
+ const buffer = new MessagePackWriteBuffer();
156
+ const data = { name: 'test', value: 123 };
157
+ const encoded = buffer.encode(data);
158
+ const decoded = new MessagePackReadBuffer().decode(encoded);
159
+ expect(decoded).toEqual(data);
160
+ });
161
+ });
162
+
163
+ // 测试工厂层
164
+ describe('BufferFactory', () => {
165
+ it('should create correct buffer type', () => {
166
+ const buffer = BufferFactory.createReadBuffer(SerializationFormat.JSON);
167
+ expect(buffer).toBeInstanceOf(ReadBuffer);
168
+ });
169
+ });
170
+ ```
171
+
172
+ ## 实际应用场景
173
+
174
+ ### 场景 1: 开发 vs 生产环境
175
+
176
+ ```typescript
177
+ // 开发环境:使用 JSON,方便调试
178
+ if (process.env.NODE_ENV === 'development') {
179
+ channel.readBuffer = BufferFactory.createReadBuffer(SerializationFormat.JSON);
180
+ channel.writeBuffer = BufferFactory.createWriteBuffer(SerializationFormat.JSON);
181
+ } else {
182
+ // 生产环境:使用 MessagePack,提升性能
183
+ channel.readBuffer = BufferFactory.createReadBuffer(SerializationFormat.MESSAGEPACK);
184
+ channel.writeBuffer = BufferFactory.createWriteBuffer(SerializationFormat.MESSAGEPACK);
185
+ }
186
+ ```
187
+
188
+ ### 场景 2: 根据数据大小选择格式
189
+
190
+ ```typescript
191
+ function getOptimalFormat(dataSize: number): SerializationFormat {
192
+ if (dataSize < 1024) {
193
+ // 小数据:用 JSON,开销小
194
+ return SerializationFormat.JSON;
195
+ } else if (dataSize < 1024 * 1024) {
196
+ // 中等数据:用 MessagePack,平衡性能和体积
197
+ return SerializationFormat.MESSAGEPACK;
198
+ } else {
199
+ // 大数据:用 Protobuf,极致性能
200
+ return SerializationFormat.PROTOBUF;
201
+ }
202
+ }
203
+ ```
204
+
205
+ ### 场景 3: 客户端-服务端协商
206
+
207
+ ```typescript
208
+ // 客户端发送支持的格式列表
209
+ const clientFormats = [
210
+ SerializationFormat.MESSAGEPACK,
211
+ SerializationFormat.JSON
212
+ ];
213
+
214
+ // 服务端选择最佳格式
215
+ const serverFormats = [
216
+ SerializationFormat.MESSAGEPACK,
217
+ SerializationFormat.CBOR,
218
+ SerializationFormat.JSON
219
+ ];
220
+
221
+ // 协商结果
222
+ const selectedFormat = negotiateFormat(clientFormats, serverFormats);
223
+ // 返回: 'msgpack' (双方都支持的第一个格式)
224
+
225
+ // 使用协商后的格式
226
+ channel.readBuffer = BufferFactory.createReadBuffer(selectedFormat);
227
+ channel.writeBuffer = BufferFactory.createWriteBuffer(selectedFormat);
228
+ ```
229
+
230
+ ## 对比:非分层设计的问题
231
+
232
+ ### ❌ 不好的设计(紧耦合)
233
+
234
+ ```typescript
235
+ // 所有层都直接依赖 JSON
236
+ class Channel {
237
+ send(data: any) {
238
+ const json = JSON.stringify(data); // 硬编码 JSON
239
+ this.socket.send(json);
240
+ }
241
+
242
+ receive(json: string) {
243
+ const data = JSON.parse(json); // 硬编码 JSON
244
+ return data;
245
+ }
246
+ }
247
+
248
+ // 问题:
249
+ // 1. 想换成 MessagePack?需要修改所有地方
250
+ // 2. 想支持多种格式?需要大量 if-else
251
+ // 3. 无法测试序列化逻辑(和传输逻辑耦合)
252
+ ```
253
+
254
+ ### ✅ 好的设计(分层可配置)
255
+
256
+ ```typescript
257
+ // 抽象层定义接口
258
+ abstract class WriteBaseBuffer {
259
+ abstract encode(data: any): any;
260
+ }
261
+
262
+ // 实现层提供具体实现
263
+ class JSONBuffer extends WriteBaseBuffer {
264
+ encode(data: any) { return JSON.stringify(data); }
265
+ }
266
+
267
+ class MessagePackBuffer extends WriteBaseBuffer {
268
+ encode(data: any) { return msgpack.encode(data); }
269
+ }
270
+
271
+ // 协议层使用抽象接口
272
+ class Channel {
273
+ constructor(private writeBuffer: WriteBaseBuffer) {}
274
+
275
+ send(data: any) {
276
+ const encoded = this.writeBuffer.encode(data); // 使用抽象接口
277
+ this.socket.send(encoded);
278
+ }
279
+ }
280
+
281
+ // 使用:可以轻松切换
282
+ const jsonChannel = new Channel(new JSONBuffer());
283
+ const msgpackChannel = new Channel(new MessagePackBuffer());
284
+ ```
285
+
286
+ ## 总结
287
+
288
+ **分层可配置设计** = **职责分离** + **接口抽象** + **工厂模式**
289
+
290
+ - **分层**: 将复杂系统拆分成多个职责清晰的层次
291
+ - **可配置**: 每一层都可以通过配置来改变行为,而不影响其他层
292
+ - **优势**: 解耦、可扩展、可替换、可测试
293
+
294
+ 这样的设计让你可以:
295
+ - ✅ 轻松添加新的序列化格式
296
+ - ✅ 根据场景选择最合适的格式
297
+ - ✅ 在不影响其他代码的情况下切换格式
298
+ - ✅ 独立测试每一层的功能