Skip to content

Commit a83d2d6

Browse files
committed
create @mercuryworkshop/rpc package
1 parent bf9b586 commit a83d2d6

File tree

4 files changed

+120
-0
lines changed

4 files changed

+120
-0
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
type Serverbound = {
2+
method1: [{ paramA: string; paramB: number }, boolean];
3+
method2: [string, number];
4+
};
5+
6+
type Clientbound = {
7+
method1: [number];
8+
method2: [boolean, string];
9+
};
10+
11+
export type RpcDescription = {
12+
[method: string]: [args: any, returnType: any] | [args: any] | [];
13+
};
14+
15+
export type MethodsDefinition<Description extends RpcDescription, Meta> = {
16+
[Method in keyof Description]: (
17+
...args: Description[Method] extends [infer A, ...any[]]
18+
? [Meta, A]
19+
: [Meta]
20+
) => Description[Method] extends [...any[], infer R]
21+
? Promise<[R, Transferable[]]>
22+
: Promise<void>;
23+
};
24+
25+
class RpcHelper<
26+
Local extends RpcDescription,
27+
Remote extends RpcDescription,
28+
Meta,
29+
> {
30+
counter: number = 0;
31+
promiseCallbacks: Map<
32+
number,
33+
{ resolve: (value: any) => void; reject: (reason?: any) => void }
34+
> = new Map();
35+
constructor(
36+
private methods: MethodsDefinition<Local, Meta>,
37+
private id: string,
38+
private sendRaw: (data: any, transfer: Transferable[]) => void
39+
) {}
40+
41+
recieve(data: any, meta: Meta) {
42+
if (data === undefined || data === null || typeof data !== "object") return;
43+
const dt = data[this.id];
44+
if (dt === undefined || dt === null || typeof dt !== "object") return;
45+
46+
const type = dt.$type;
47+
48+
if (type === "response") {
49+
const token = dt.$token;
50+
const data = dt.$data;
51+
const error = dt.$error;
52+
const cb = this.promiseCallbacks.get(token);
53+
if (!cb) return;
54+
this.promiseCallbacks.delete(token);
55+
if (error !== undefined) {
56+
cb.reject(new Error(error));
57+
} else {
58+
cb.resolve(data);
59+
}
60+
} else if (type === "request") {
61+
const method = dt.$method as keyof Local;
62+
const args = dt.$args as Local[typeof method][0];
63+
(this.methods[method] as any)(meta, args)
64+
.then(([res, transfer]) => {
65+
this.sendRaw(
66+
{
67+
[this.id]: {
68+
$type: "response",
69+
$token: dt.$token,
70+
$data: res,
71+
},
72+
},
73+
transfer
74+
);
75+
})
76+
.catch((err: any) => {
77+
this.sendRaw(
78+
{
79+
[this.id]: {
80+
$type: "response",
81+
$token: dt.$token,
82+
$error: err?.toString() || "Unknown error",
83+
},
84+
},
85+
[]
86+
);
87+
});
88+
}
89+
}
90+
91+
call<Method extends keyof Remote>(
92+
method: Method,
93+
args: Remote[Method][0],
94+
transfer: Transferable[]
95+
): Promise<Remote[Method][1]> {
96+
let token = this.counter++;
97+
return new Promise((resolve, reject) => {
98+
this.promiseCallbacks.set(token, { resolve, reject });
99+
this.sendRaw(
100+
{
101+
[this.id]: {
102+
$type: "request",
103+
$method: method,
104+
$args: args,
105+
$token: token,
106+
},
107+
},
108+
transfer
109+
);
110+
});
111+
}
112+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "@mercuryworkshop/rpc",
3+
"version": "0.0.1",
4+
"type": "module",
5+
"packageManager": "[email protected]"
6+
}

packages/scramjet/pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ packages:
88
- "packages/libcurl-transport"
99
- "packages/demo"
1010
- "packages/rewriter_demo"
11+
- "packages/rpc"

pnpm-workspace.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ packages:
1818
- "packages/scramjet/packages/libcurl-transport"
1919
- "packages/scramjet/packages/demo"
2020
- "packages/scramjet/packages/rewriter_demo"
21+
- "packages/scramjet/packages/rpc"

0 commit comments

Comments
 (0)