Skip to content

Commit 1d88f5d

Browse files
committed
fix: extracting middleware to its own files
[ci skip]
1 parent 89c6c59 commit 1d88f5d

File tree

12 files changed

+562
-466
lines changed

12 files changed

+562
-466
lines changed

src/RPC/RPCClient.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
} from './types';
1616
import { CreateDestroy, ready } from '@matrixai/async-init/dist/CreateDestroy';
1717
import Logger from '@matrixai/logger';
18+
import * as middlewareUtils from './middleware';
1819
import * as rpcErrors from './errors';
1920
import * as rpcUtils from './utils';
2021
import {
@@ -30,7 +31,7 @@ class RPCClient<M extends ClientManifest> {
3031
static async createRPCClient<M extends ClientManifest>({
3132
manifest,
3233
streamPairCreateCallback,
33-
middleware = rpcUtils.defaultClientMiddlewareWrapper(),
34+
middleware = middlewareUtils.defaultClientMiddlewareWrapper(),
3435
logger = new Logger(this.name),
3536
}: {
3637
manifest: M;

src/RPC/RPCServer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
} from './handlers';
3030
import * as rpcUtils from './utils';
3131
import * as rpcErrors from './errors';
32+
import * as middlewareUtils from './middleware';
3233
import { never } from '../utils/utils';
3334
import { sysexits } from '../errors';
3435

@@ -37,7 +38,7 @@ interface RPCServer extends CreateDestroy {}
3738
class RPCServer {
3839
static async createRPCServer({
3940
manifest,
40-
middleware = rpcUtils.defaultServerMiddlewareWrapper(),
41+
middleware = middlewareUtils.defaultServerMiddlewareWrapper(),
4142
sensitive = false,
4243
logger = new Logger(this.name),
4344
}: {

src/RPC/middleware.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import type {
2+
JsonRpcMessage,
3+
JsonRpcRequest,
4+
JsonRpcResponse,
5+
JsonRpcResponseResult,
6+
MiddlewareFactory,
7+
} from './types';
8+
import { TransformStream } from 'stream/web';
9+
import * as rpcErrors from './errors';
10+
import * as rpcUtils from './utils';
11+
const jsonStreamParsers = require('@streamparser/json');
12+
13+
function binaryToJsonMessageStream<T extends JsonRpcMessage>(
14+
messageParser: (message: unknown) => T,
15+
byteLimit: number = 1024 * 1024,
16+
firstMessage?: T,
17+
) {
18+
const parser = new jsonStreamParsers.JSONParser({
19+
separator: '',
20+
paths: ['$'],
21+
});
22+
let bytesWritten: number = 0;
23+
24+
return new TransformStream<Uint8Array, T>({
25+
start: (controller) => {
26+
if (firstMessage != null) controller.enqueue(firstMessage);
27+
parser.onValue = (value) => {
28+
const jsonMessage = messageParser(value.value);
29+
controller.enqueue(jsonMessage);
30+
bytesWritten = 0;
31+
};
32+
},
33+
transform: (chunk) => {
34+
try {
35+
bytesWritten += chunk.byteLength;
36+
parser.write(chunk);
37+
} catch (e) {
38+
throw new rpcErrors.ErrorRpcParse(undefined, { cause: e });
39+
}
40+
if (bytesWritten > byteLimit) {
41+
throw new rpcErrors.ErrorRpcMessageLength();
42+
}
43+
},
44+
});
45+
}
46+
47+
function jsonMessageToBinaryStream() {
48+
return new TransformStream<JsonRpcMessage, Uint8Array>({
49+
transform: (chunk, controller) => {
50+
controller.enqueue(Buffer.from(JSON.stringify(chunk)));
51+
},
52+
});
53+
}
54+
55+
const defaultMiddleware: MiddlewareFactory<
56+
JsonRpcRequest,
57+
JsonRpcRequest,
58+
JsonRpcResponse,
59+
JsonRpcResponse
60+
> = () => {
61+
return {
62+
forward: new TransformStream(),
63+
reverse: new TransformStream(),
64+
};
65+
};
66+
67+
const defaultServerMiddlewareWrapper = (
68+
middleware: MiddlewareFactory<
69+
JsonRpcRequest,
70+
JsonRpcRequest,
71+
JsonRpcResponse,
72+
JsonRpcResponse
73+
> = defaultMiddleware,
74+
) => {
75+
return (header: JsonRpcRequest) => {
76+
const inputTransformStream = binaryToJsonMessageStream(
77+
rpcUtils.parseJsonRpcRequest,
78+
undefined,
79+
header,
80+
);
81+
const outputTransformStream = new TransformStream<
82+
JsonRpcResponseResult,
83+
JsonRpcResponseResult
84+
>();
85+
86+
const middleMiddleware = middleware(header);
87+
88+
const forwardReadable = inputTransformStream.readable.pipeThrough(
89+
middleMiddleware.forward,
90+
); // Usual middleware here
91+
const reverseReadable = outputTransformStream.readable
92+
.pipeThrough(middleMiddleware.reverse) // Usual middleware here
93+
.pipeThrough(jsonMessageToBinaryStream());
94+
95+
return {
96+
forward: {
97+
readable: forwardReadable,
98+
writable: inputTransformStream.writable,
99+
},
100+
reverse: {
101+
readable: reverseReadable,
102+
writable: outputTransformStream.writable,
103+
},
104+
};
105+
};
106+
};
107+
108+
const defaultClientMiddlewareWrapper = (
109+
middleware: MiddlewareFactory<
110+
JsonRpcRequest,
111+
JsonRpcRequest,
112+
JsonRpcResponse,
113+
JsonRpcResponse
114+
> = defaultMiddleware,
115+
): MiddlewareFactory<
116+
Uint8Array,
117+
JsonRpcRequest,
118+
JsonRpcResponse,
119+
Uint8Array
120+
> => {
121+
return () => {
122+
const outputTransformStream = binaryToJsonMessageStream(
123+
rpcUtils.parseJsonRpcResponse,
124+
undefined,
125+
);
126+
const inputTransformStream = new TransformStream<
127+
JsonRpcRequest,
128+
JsonRpcRequest
129+
>();
130+
131+
const middleMiddleware = middleware();
132+
const forwardReadable = inputTransformStream.readable
133+
.pipeThrough(middleMiddleware.forward) // Usual middleware here
134+
.pipeThrough(jsonMessageToBinaryStream());
135+
const reverseReadable = outputTransformStream.readable.pipeThrough(
136+
middleMiddleware.reverse,
137+
); // Usual middleware here
138+
139+
return {
140+
forward: {
141+
readable: forwardReadable,
142+
writable: inputTransformStream.writable,
143+
},
144+
reverse: {
145+
readable: reverseReadable,
146+
writable: outputTransformStream.writable,
147+
},
148+
};
149+
};
150+
};
151+
152+
export {
153+
binaryToJsonMessageStream,
154+
jsonMessageToBinaryStream,
155+
defaultMiddleware,
156+
defaultServerMiddlewareWrapper,
157+
defaultClientMiddlewareWrapper,
158+
};

0 commit comments

Comments
 (0)