forked from anomalyco/opencode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrpc.ts
More file actions
66 lines (63 loc) · 2.03 KB
/
rpc.ts
File metadata and controls
66 lines (63 loc) · 2.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
export namespace Rpc {
type Definition = {
[method: string]: (input: any) => any
}
export function listen(rpc: Definition) {
onmessage = async (evt) => {
const parsed = JSON.parse(evt.data)
if (parsed.type === "rpc.request") {
const result = await rpc[parsed.method](parsed.input)
postMessage(JSON.stringify({ type: "rpc.result", result, id: parsed.id }))
}
}
}
export function emit(event: string, data: unknown) {
postMessage(JSON.stringify({ type: "rpc.event", event, data }))
}
export function client<T extends Definition>(target: {
postMessage: (data: string) => void | null
onmessage: ((this: Worker, ev: MessageEvent<any>) => any) | null
}) {
const pending = new Map<number, (result: any) => void>()
const listeners = new Map<string, Set<(data: any) => void>>()
let id = 0
target.onmessage = async (evt) => {
const parsed = JSON.parse(evt.data)
if (parsed.type === "rpc.result") {
const resolve = pending.get(parsed.id)
if (resolve) {
resolve(parsed.result)
pending.delete(parsed.id)
}
}
if (parsed.type === "rpc.event") {
const handlers = listeners.get(parsed.event)
if (handlers) {
for (const handler of handlers) {
handler(parsed.data)
}
}
}
}
return {
call<Method extends keyof T>(method: Method, input: Parameters<T[Method]>[0]): Promise<ReturnType<T[Method]>> {
const requestId = id++
return new Promise((resolve) => {
pending.set(requestId, resolve)
target.postMessage(JSON.stringify({ type: "rpc.request", method, input, id: requestId }))
})
},
on<Data>(event: string, handler: (data: Data) => void) {
let handlers = listeners.get(event)
if (!handlers) {
handlers = new Set()
listeners.set(event, handlers)
}
handlers.add(handler)
return () => {
handlers!.delete(handler)
}
},
}
}
}