@lesomnus/grpc-dgram 0.0.1
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.
- package/LICENSE +202 -0
- package/README.md +245 -0
- package/dist/conn-DOmx4nbt.mjs +849 -0
- package/dist/conn-DTWG9vIx.d.mts +331 -0
- package/dist/desc-BMF2FBqk.d.mts +72 -0
- package/dist/index.d.mts +27 -0
- package/dist/index.mjs +1079 -0
- package/dist/protocol-K4Zy8MuQ.mjs +156 -0
- package/dist/server-xIr1mwqq.d.mts +112 -0
- package/dist/status-DZwMDWIn.mjs +63 -0
- package/dist/transport/connect.d.mts +6 -0
- package/dist/transport/connect.mjs +122 -0
- package/dist/transport/node-udp.d.mts +42 -0
- package/dist/transport/node-udp.mjs +144 -0
- package/dist/transport/port.d.mts +52 -0
- package/dist/transport/port.mjs +240 -0
- package/dist/transport/protobuf-es.d.mts +19 -0
- package/dist/transport/protobuf-es.mjs +27 -0
- package/dist/transport/webrtc.d.mts +56 -0
- package/dist/transport/webrtc.mjs +240 -0
- package/dist/transport/websocket.d.mts +59 -0
- package/dist/transport/websocket.mjs +324 -0
- package/dist/wasm/worker.d.mts +8 -0
- package/dist/wasm/worker.mjs +73 -0
- package/dist/wasm.d.mts +36 -0
- package/dist/wasm.mjs +156 -0
- package/dist/wire-BR8KiyRg.mjs +876 -0
- package/package.json +73 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
//#region src/wasm/instance.ts
|
|
2
|
+
const noop = () => {};
|
|
3
|
+
function unrefTimer(t) {
|
|
4
|
+
t.unref?.();
|
|
5
|
+
}
|
|
6
|
+
const DefaultEntryPoint = "drpcServe";
|
|
7
|
+
const DefaultReadyTimeoutMs = 1e4;
|
|
8
|
+
const DefaultWasmExec = "/wasm_exec.js";
|
|
9
|
+
async function startInstance(app, opts = {}) {
|
|
10
|
+
const name = opts.entryPoint ?? "drpcServe";
|
|
11
|
+
const entry = claimEntryPoint(name);
|
|
12
|
+
try {
|
|
13
|
+
const go = opts.go ?? await newGo(String(opts.wasmExec ?? "/wasm_exec.js"));
|
|
14
|
+
const instance = await instantiate(app, go.importObject);
|
|
15
|
+
const run = go.run(instance);
|
|
16
|
+
return live(name, go, await awaitPublish(entry.published, run, name, opts.readyTimeoutMs ?? 1e4), run);
|
|
17
|
+
} finally {
|
|
18
|
+
entry.release();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function live(name, go, serve, run) {
|
|
22
|
+
let dead;
|
|
23
|
+
let announce;
|
|
24
|
+
const exited = new Promise((res) => {
|
|
25
|
+
announce = res;
|
|
26
|
+
});
|
|
27
|
+
const died = (cause) => {
|
|
28
|
+
if (dead !== void 0) return;
|
|
29
|
+
dead = { cause };
|
|
30
|
+
makeInert(go);
|
|
31
|
+
announce(cause);
|
|
32
|
+
};
|
|
33
|
+
run.then(() => died(/* @__PURE__ */ new Error("the wasm instance exited")), (e) => died(new Error(`the wasm instance failed: ${e instanceof Error ? e.message : String(e)}`, { cause: e })));
|
|
34
|
+
return {
|
|
35
|
+
entryPoint: name,
|
|
36
|
+
exited,
|
|
37
|
+
serve(port) {
|
|
38
|
+
if (dead !== void 0) throw new Error(`wasm: the instance behind globalThis.${name} has exited${dead.cause instanceof Error ? `: ${dead.cause.message}` : ""}`);
|
|
39
|
+
serve(port);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function makeInert(go) {
|
|
44
|
+
const inner = go;
|
|
45
|
+
if (typeof inner._resume === "function") inner._resume = noop;
|
|
46
|
+
}
|
|
47
|
+
const awaiting = /* @__PURE__ */ new Set();
|
|
48
|
+
function claimEntryPoint(name) {
|
|
49
|
+
if (awaiting.has(name)) throw new Error(`wasm: another instance is already waiting for globalThis.${name}; give one of them its own entryPoint`);
|
|
50
|
+
const g = globalThis;
|
|
51
|
+
const prev = Object.getOwnPropertyDescriptor(g, name);
|
|
52
|
+
let value;
|
|
53
|
+
let publish;
|
|
54
|
+
const published = new Promise((res) => {
|
|
55
|
+
publish = res;
|
|
56
|
+
});
|
|
57
|
+
Object.defineProperty(g, name, {
|
|
58
|
+
configurable: true,
|
|
59
|
+
get: () => value,
|
|
60
|
+
set: (v) => {
|
|
61
|
+
value = v;
|
|
62
|
+
publish(v);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
awaiting.add(name);
|
|
66
|
+
let released = false;
|
|
67
|
+
return {
|
|
68
|
+
published,
|
|
69
|
+
release() {
|
|
70
|
+
if (released) return;
|
|
71
|
+
released = true;
|
|
72
|
+
awaiting.delete(name);
|
|
73
|
+
if (prev === void 0) Reflect.deleteProperty(g, name);
|
|
74
|
+
else Object.defineProperty(g, name, prev);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
async function awaitPublish(published, run, name, timeoutMs) {
|
|
79
|
+
let timer;
|
|
80
|
+
const arms = [published, run.then(() => {
|
|
81
|
+
throw new Error(`wasm: the instance exited before publishing globalThis.${name} — see the console for what it printed`);
|
|
82
|
+
}, (e) => {
|
|
83
|
+
throw new Error(`wasm: the instance failed before publishing globalThis.${name}`, { cause: e });
|
|
84
|
+
})];
|
|
85
|
+
if (timeoutMs > 0) arms.push(new Promise((_, rej) => {
|
|
86
|
+
timer = setTimeout(() => rej(/* @__PURE__ */ new Error(`wasm: no globalThis.${name} after ${timeoutMs} ms — is that the name the server serves under?`)), timeoutMs);
|
|
87
|
+
unrefTimer(timer);
|
|
88
|
+
}));
|
|
89
|
+
try {
|
|
90
|
+
const serve = await Promise.race(arms);
|
|
91
|
+
if (typeof serve !== "function") throw new Error(`wasm: globalThis.${name} was set to a ${typeof serve}, not a function taking one port`);
|
|
92
|
+
return serve;
|
|
93
|
+
} finally {
|
|
94
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async function newGo(wasmExec) {
|
|
98
|
+
let ctor = goCtor();
|
|
99
|
+
if (ctor === void 0) {
|
|
100
|
+
await loadWasmExec(wasmExec);
|
|
101
|
+
ctor = goCtor();
|
|
102
|
+
if (ctor === void 0) throw new Error(`wasm: ${wasmExec} loaded but defined no globalThis.Go — is that the toolchain's wasm_exec.js?`);
|
|
103
|
+
}
|
|
104
|
+
return new ctor();
|
|
105
|
+
}
|
|
106
|
+
function goCtor() {
|
|
107
|
+
const ctor = globalThis.Go;
|
|
108
|
+
return typeof ctor === "function" ? ctor : void 0;
|
|
109
|
+
}
|
|
110
|
+
async function loadWasmExec(url) {
|
|
111
|
+
let res;
|
|
112
|
+
try {
|
|
113
|
+
res = await fetch(url);
|
|
114
|
+
} catch (e) {
|
|
115
|
+
throw new Error(missingWasmExec(url, String(e)), { cause: e });
|
|
116
|
+
}
|
|
117
|
+
if (!res.ok) throw new Error(missingWasmExec(url, `${res.status} ${res.statusText}`));
|
|
118
|
+
new Function(await res.text())();
|
|
119
|
+
}
|
|
120
|
+
function missingWasmExec(url, why) {
|
|
121
|
+
return `wasm: GET ${url} failed (${why}) — wasm_exec.js is the JS half of the Go runtime, and this package does not ship it: it is version-coupled to the compiler that built your module, so a vendored copy would pin the wrong one. Serve your toolchain's:
|
|
122
|
+
cp "\$(go env GOROOT)/lib/wasm/wasm_exec.js" ./public/
|
|
123
|
+
or load it yourself before starting — a realm that already has globalThis.Go fetches nothing.`;
|
|
124
|
+
}
|
|
125
|
+
async function instantiate(app, imports) {
|
|
126
|
+
if (app instanceof WebAssembly.Module) return WebAssembly.instantiate(app, imports);
|
|
127
|
+
if (typeof app === "string" || app instanceof URL) return fromResponse(fetch(String(app)), String(app), imports);
|
|
128
|
+
return (await WebAssembly.instantiate(app, imports)).instance;
|
|
129
|
+
}
|
|
130
|
+
async function fromResponse(src, url, imports) {
|
|
131
|
+
const res = await src;
|
|
132
|
+
if (!res.ok) {
|
|
133
|
+
const body = await res.text().catch(() => "");
|
|
134
|
+
throw new Error(`wasm: GET ${url} failed: ${res.status} ${res.statusText}${body === "" ? "" : `\n${body}`}`);
|
|
135
|
+
}
|
|
136
|
+
if (typeof WebAssembly.instantiateStreaming === "function" && mimeOf(res) === "application/wasm") return (await WebAssembly.instantiateStreaming(res, imports)).instance;
|
|
137
|
+
return (await WebAssembly.instantiate(await res.arrayBuffer(), imports)).instance;
|
|
138
|
+
}
|
|
139
|
+
function mimeOf(res) {
|
|
140
|
+
return ((res.headers.get("content-type") ?? "").split(";")[0] ?? "").trim().toLowerCase();
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/wasm/protocol.ts
|
|
144
|
+
function isPageMessage(v) {
|
|
145
|
+
const tag = tagOf(v);
|
|
146
|
+
return tag === "start" || tag === "serve";
|
|
147
|
+
}
|
|
148
|
+
function isWorkerMessage(v) {
|
|
149
|
+
const tag = tagOf(v);
|
|
150
|
+
return tag === "ready" || tag === "error" || tag === "exited";
|
|
151
|
+
}
|
|
152
|
+
function tagOf(v) {
|
|
153
|
+
return typeof v === "object" && v !== null ? v.drpc : void 0;
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
export { DefaultWasmExec as a, DefaultReadyTimeoutMs as i, isWorkerMessage as n, startInstance as o, DefaultEntryPoint as r, isPageMessage as t };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { O as Frame, at as Limits, c as Compressor, g as FrameHandler, h as FrameContext, o as FlowTiming, ot as RxBufferConfig, st as ResolvedTiming } from "./conn-DTWG9vIx.mjs";
|
|
2
|
+
import { a as MethodDesc, h as Metadata, o as NamedCodec } from "./desc-BMF2FBqk.mjs";
|
|
3
|
+
//#region src/server.d.ts
|
|
4
|
+
interface ServerOptions {
|
|
5
|
+
reliable?: boolean;
|
|
6
|
+
timing?: FlowTiming;
|
|
7
|
+
maxHandlerTimeoutMs?: number;
|
|
8
|
+
rxBuffer?: RxBufferConfig;
|
|
9
|
+
methodRxBuffer?: Record<string, RxBufferConfig>;
|
|
10
|
+
limits?: Limits;
|
|
11
|
+
codecs?: Record<string, NamedCodec>;
|
|
12
|
+
compressors?: Record<string, Compressor>;
|
|
13
|
+
maxRecvMsgSize?: number;
|
|
14
|
+
maxSendMsgSize?: number;
|
|
15
|
+
}
|
|
16
|
+
interface ServerContext {
|
|
17
|
+
readonly signal: AbortSignal;
|
|
18
|
+
readonly metadata: Metadata | undefined;
|
|
19
|
+
readonly peer: unknown;
|
|
20
|
+
readonly method: string;
|
|
21
|
+
readonly deadline: number | undefined;
|
|
22
|
+
setHeader(md: Metadata): void;
|
|
23
|
+
sendHeader(md?: Metadata): Promise<void>;
|
|
24
|
+
setTrailer(md: Metadata): void;
|
|
25
|
+
}
|
|
26
|
+
interface ServerReader<Req> {
|
|
27
|
+
recv(): Promise<Req | undefined>;
|
|
28
|
+
[Symbol.asyncIterator](): AsyncIterator<Req>;
|
|
29
|
+
}
|
|
30
|
+
interface ServerWriter<Res> {
|
|
31
|
+
send(msg: Res): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
type UnaryHandler<Req, Res> = (req: Req, ctx: ServerContext) => Res | Promise<Res>;
|
|
34
|
+
type ServerStreamingHandler<Req, Res> = (req: Req, stream: ServerWriter<Res>, ctx: ServerContext) => void | Promise<void>;
|
|
35
|
+
type ClientStreamingHandler<Req, Res> = (stream: ServerReader<Req>, ctx: ServerContext) => Res | Promise<Res>;
|
|
36
|
+
type BidiHandler<Req, Res> = (stream: ServerReader<Req> & ServerWriter<Res>, ctx: ServerContext) => void | Promise<void>;
|
|
37
|
+
declare class Server {
|
|
38
|
+
readonly epoch: number;
|
|
39
|
+
private readonly tx;
|
|
40
|
+
private readonly mode;
|
|
41
|
+
private readonly maxHandlerTimeoutMs;
|
|
42
|
+
private readonly rxCfg;
|
|
43
|
+
private readonly methodRx;
|
|
44
|
+
private readonly limits;
|
|
45
|
+
private readonly codecs;
|
|
46
|
+
private readonly compressors;
|
|
47
|
+
private readonly maxRecv;
|
|
48
|
+
private readonly maxSend;
|
|
49
|
+
private readonly stallMs;
|
|
50
|
+
private readonly services;
|
|
51
|
+
private serving;
|
|
52
|
+
private readonly slots;
|
|
53
|
+
private pendingResetTotal;
|
|
54
|
+
private resetAtTotal;
|
|
55
|
+
private replyBudgetTotal;
|
|
56
|
+
private drain;
|
|
57
|
+
private closed;
|
|
58
|
+
private liveTasks;
|
|
59
|
+
private idleWaiters;
|
|
60
|
+
private sawUnreliable;
|
|
61
|
+
private readonly sw;
|
|
62
|
+
constructor(tx: FrameHandler, opts?: ServerOptions);
|
|
63
|
+
register<Req, Res>(desc: MethodDesc<Req, Res> & {
|
|
64
|
+
clientStreams: false;
|
|
65
|
+
serverStreams: false;
|
|
66
|
+
}, handler: UnaryHandler<Req, Res>): void;
|
|
67
|
+
register<Req, Res>(desc: MethodDesc<Req, Res> & {
|
|
68
|
+
clientStreams: false;
|
|
69
|
+
serverStreams: true;
|
|
70
|
+
}, handler: ServerStreamingHandler<Req, Res>): void;
|
|
71
|
+
register<Req, Res>(desc: MethodDesc<Req, Res> & {
|
|
72
|
+
clientStreams: true;
|
|
73
|
+
serverStreams: false;
|
|
74
|
+
}, handler: ClientStreamingHandler<Req, Res>): void;
|
|
75
|
+
register<Req, Res>(desc: MethodDesc<Req, Res> & {
|
|
76
|
+
clientStreams: true;
|
|
77
|
+
serverStreams: true;
|
|
78
|
+
}, handler: BidiHandler<Req, Res>): void;
|
|
79
|
+
private rxReliable;
|
|
80
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
81
|
+
private open;
|
|
82
|
+
private rejectOpen;
|
|
83
|
+
private runUnary;
|
|
84
|
+
private runStream;
|
|
85
|
+
private finish;
|
|
86
|
+
private resetByPeerSid;
|
|
87
|
+
private sendReset;
|
|
88
|
+
private allowReply;
|
|
89
|
+
gracefulStop(): Promise<void>;
|
|
90
|
+
stop(): Promise<void>;
|
|
91
|
+
disconnectPeer(peer: unknown, err?: unknown): void;
|
|
92
|
+
private waitIdle;
|
|
93
|
+
private taskDone;
|
|
94
|
+
/** @internal */
|
|
95
|
+
get timing(): ResolvedTiming;
|
|
96
|
+
/** @internal */
|
|
97
|
+
send(f: Frame, ctx: FrameContext): Promise<void>;
|
|
98
|
+
/** @internal */
|
|
99
|
+
sendOrThrow(f: Frame, ctx: FrameContext): Promise<void>;
|
|
100
|
+
/** @internal */
|
|
101
|
+
txFor(peer: unknown): FrameContext;
|
|
102
|
+
/** @internal */
|
|
103
|
+
allowReplyFor(peer: unknown, now: number): boolean;
|
|
104
|
+
private ensureSlot;
|
|
105
|
+
private ensurePeer;
|
|
106
|
+
/** @internal */
|
|
107
|
+
kickSweep(): void;
|
|
108
|
+
private hasWork;
|
|
109
|
+
private sweep;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { ServerOptions as a, ServerWriter as c, ServerContext as i, UnaryHandler as l, ClientStreamingHandler as n, ServerReader as o, Server as r, ServerStreamingHandler as s, BidiHandler as t };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
//#region src/status.ts
|
|
2
|
+
let Code = /* @__PURE__ */ function(Code) {
|
|
3
|
+
Code[Code["OK"] = 0] = "OK";
|
|
4
|
+
Code[Code["CANCELLED"] = 1] = "CANCELLED";
|
|
5
|
+
Code[Code["UNKNOWN"] = 2] = "UNKNOWN";
|
|
6
|
+
Code[Code["INVALID_ARGUMENT"] = 3] = "INVALID_ARGUMENT";
|
|
7
|
+
Code[Code["DEADLINE_EXCEEDED"] = 4] = "DEADLINE_EXCEEDED";
|
|
8
|
+
Code[Code["NOT_FOUND"] = 5] = "NOT_FOUND";
|
|
9
|
+
Code[Code["ALREADY_EXISTS"] = 6] = "ALREADY_EXISTS";
|
|
10
|
+
Code[Code["PERMISSION_DENIED"] = 7] = "PERMISSION_DENIED";
|
|
11
|
+
Code[Code["RESOURCE_EXHAUSTED"] = 8] = "RESOURCE_EXHAUSTED";
|
|
12
|
+
Code[Code["FAILED_PRECONDITION"] = 9] = "FAILED_PRECONDITION";
|
|
13
|
+
Code[Code["ABORTED"] = 10] = "ABORTED";
|
|
14
|
+
Code[Code["OUT_OF_RANGE"] = 11] = "OUT_OF_RANGE";
|
|
15
|
+
Code[Code["UNIMPLEMENTED"] = 12] = "UNIMPLEMENTED";
|
|
16
|
+
Code[Code["INTERNAL"] = 13] = "INTERNAL";
|
|
17
|
+
Code[Code["UNAVAILABLE"] = 14] = "UNAVAILABLE";
|
|
18
|
+
Code[Code["DATA_LOSS"] = 15] = "DATA_LOSS";
|
|
19
|
+
Code[Code["UNAUTHENTICATED"] = 16] = "UNAUTHENTICATED";
|
|
20
|
+
return Code;
|
|
21
|
+
}({});
|
|
22
|
+
var StatusError = class extends Error {
|
|
23
|
+
code;
|
|
24
|
+
desc;
|
|
25
|
+
constructor(code, desc) {
|
|
26
|
+
super(`${Code[code] ?? code}: ${desc}`);
|
|
27
|
+
this.name = "StatusError";
|
|
28
|
+
this.code = code;
|
|
29
|
+
this.desc = desc;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function statusError(code, desc) {
|
|
33
|
+
return new StatusError(code, desc);
|
|
34
|
+
}
|
|
35
|
+
var MessageTooLargeError = class extends Error {
|
|
36
|
+
constructor(message = "message too large for the transport") {
|
|
37
|
+
super(message);
|
|
38
|
+
this.name = "MessageTooLargeError";
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
function isMessageTooLarge(err) {
|
|
42
|
+
for (let e = err, i = 0; i < 8; i++) {
|
|
43
|
+
if (e instanceof MessageTooLargeError) return true;
|
|
44
|
+
if (e instanceof Error && e.cause !== void 0) e = e.cause;
|
|
45
|
+
else return false;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
function toStatusError(err) {
|
|
50
|
+
if (err instanceof StatusError) return err;
|
|
51
|
+
if (isMessageTooLarge(err)) return new StatusError(8, err instanceof Error ? err.message : String(err));
|
|
52
|
+
if (err instanceof Error) {
|
|
53
|
+
if (err.name === "AbortError") return new StatusError(1, err.message || "aborted");
|
|
54
|
+
if (err.name === "TimeoutError") return new StatusError(4, err.message || "deadline exceeded");
|
|
55
|
+
return new StatusError(2, err.message);
|
|
56
|
+
}
|
|
57
|
+
return new StatusError(2, String(err));
|
|
58
|
+
}
|
|
59
|
+
function abortCause(signal) {
|
|
60
|
+
return toStatusError(signal.reason);
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { isMessageTooLarge as a, abortCause as i, MessageTooLargeError as n, statusError as o, StatusError as r, toStatusError as s, Code as t };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { r as StatusError } from "../status-DZwMDWIn.mjs";
|
|
2
|
+
import { fromMethod } from "./protobuf-es.mjs";
|
|
3
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
|
+
import { ConnectError } from "@connectrpc/connect";
|
|
5
|
+
//#region src/transport/connect/index.ts
|
|
6
|
+
function headersToMetadata(h) {
|
|
7
|
+
if (h === void 0) return void 0;
|
|
8
|
+
const headers = h instanceof Headers ? h : new Headers(h);
|
|
9
|
+
let md;
|
|
10
|
+
headers.forEach((value, key) => {
|
|
11
|
+
(md ??= {})[key] = [value];
|
|
12
|
+
});
|
|
13
|
+
return md;
|
|
14
|
+
}
|
|
15
|
+
function safeAppend(headers, key, value) {
|
|
16
|
+
try {
|
|
17
|
+
headers.append(key, value);
|
|
18
|
+
} catch {}
|
|
19
|
+
}
|
|
20
|
+
function appendMetadata(headers, md) {
|
|
21
|
+
if (md === void 0) return;
|
|
22
|
+
for (const [key, values] of Object.entries(md)) for (const v of values) safeAppend(headers, key, v);
|
|
23
|
+
}
|
|
24
|
+
function metadataToHeaders(md) {
|
|
25
|
+
const headers = new Headers();
|
|
26
|
+
appendMetadata(headers, md);
|
|
27
|
+
return headers;
|
|
28
|
+
}
|
|
29
|
+
function toConnectError(err, header, trailer) {
|
|
30
|
+
const meta = metadataToHeaders(header);
|
|
31
|
+
appendMetadata(meta, trailer);
|
|
32
|
+
if (err instanceof StatusError) return new ConnectError(err.desc, err.code, meta, void 0, err);
|
|
33
|
+
const ce = ConnectError.from(err);
|
|
34
|
+
meta.forEach((v, k) => safeAppend(ce.metadata, k, v));
|
|
35
|
+
return ce;
|
|
36
|
+
}
|
|
37
|
+
function callOptions(signal, timeoutMs, header) {
|
|
38
|
+
const opts = {};
|
|
39
|
+
if (signal !== void 0) opts.signal = signal;
|
|
40
|
+
if (timeoutMs !== void 0) opts.timeoutMs = timeoutMs;
|
|
41
|
+
const md = headersToMetadata(header);
|
|
42
|
+
if (md !== void 0) opts.metadata = md;
|
|
43
|
+
return opts;
|
|
44
|
+
}
|
|
45
|
+
function createDrpcTransport(conn) {
|
|
46
|
+
return {
|
|
47
|
+
async unary(method, signal, timeoutMs, header, input) {
|
|
48
|
+
const desc = fromMethod(method);
|
|
49
|
+
const opts = callOptions(signal, timeoutMs, header);
|
|
50
|
+
let respHeader;
|
|
51
|
+
let respTrailer;
|
|
52
|
+
opts.onHeader = (md) => {
|
|
53
|
+
respHeader = md;
|
|
54
|
+
};
|
|
55
|
+
opts.onTrailer = (md) => {
|
|
56
|
+
respTrailer = md;
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
const message = await conn.invoke(desc, create(method.input, input), opts);
|
|
60
|
+
return {
|
|
61
|
+
stream: false,
|
|
62
|
+
service: method.parent,
|
|
63
|
+
method,
|
|
64
|
+
header: metadataToHeaders(respHeader),
|
|
65
|
+
message,
|
|
66
|
+
trailer: metadataToHeaders(respTrailer)
|
|
67
|
+
};
|
|
68
|
+
} catch (err) {
|
|
69
|
+
throw toConnectError(err, respHeader, respTrailer);
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
async stream(method, signal, timeoutMs, header, input) {
|
|
73
|
+
const desc = fromMethod(method);
|
|
74
|
+
const s = conn.newStream(desc, callOptions(signal, timeoutMs, header));
|
|
75
|
+
(async () => {
|
|
76
|
+
try {
|
|
77
|
+
for await (const raw of input) await s.send(create(method.input, raw));
|
|
78
|
+
} catch {
|
|
79
|
+
s.cancel();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
s.closeSend();
|
|
83
|
+
})().catch(() => {});
|
|
84
|
+
let first;
|
|
85
|
+
let firstIsEnd = false;
|
|
86
|
+
try {
|
|
87
|
+
const r = await s.recv();
|
|
88
|
+
if (r === void 0) firstIsEnd = true;
|
|
89
|
+
else first = r;
|
|
90
|
+
} catch (err) {
|
|
91
|
+
throw toConnectError(err, s.latchedHeader(), s.trailer());
|
|
92
|
+
}
|
|
93
|
+
const trailer = new Headers();
|
|
94
|
+
const message = (async function* () {
|
|
95
|
+
if (!firstIsEnd) {
|
|
96
|
+
yield first;
|
|
97
|
+
for (;;) {
|
|
98
|
+
let m;
|
|
99
|
+
try {
|
|
100
|
+
m = await s.recv();
|
|
101
|
+
} catch (err) {
|
|
102
|
+
throw toConnectError(err, s.latchedHeader(), s.trailer());
|
|
103
|
+
}
|
|
104
|
+
if (m === void 0) break;
|
|
105
|
+
yield m;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
appendMetadata(trailer, s.trailer());
|
|
109
|
+
})();
|
|
110
|
+
return {
|
|
111
|
+
stream: true,
|
|
112
|
+
service: method.parent,
|
|
113
|
+
method,
|
|
114
|
+
header: metadataToHeaders(s.latchedHeader()),
|
|
115
|
+
message,
|
|
116
|
+
trailer
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { createDrpcTransport };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { O as Frame, _ as TransportInfo, g as FrameHandler, h as FrameContext, m as ConnAttacher, n as Conn, r as ConnOptions } from "../conn-DTWG9vIx.mjs";
|
|
2
|
+
import { r as Server } from "../server-xIr1mwqq.mjs";
|
|
3
|
+
import { Socket } from "node:dgram";
|
|
4
|
+
//#region src/transport/node-udp/index.d.ts
|
|
5
|
+
declare const DefaultMaxMessageSize = 1200;
|
|
6
|
+
declare class UdpTransport implements FrameHandler, TransportInfo, ConnAttacher {
|
|
7
|
+
private readonly socket;
|
|
8
|
+
private readonly max;
|
|
9
|
+
private conn;
|
|
10
|
+
private closed;
|
|
11
|
+
constructor(socket: Socket, opts?: {
|
|
12
|
+
maxMessageSize?: number;
|
|
13
|
+
});
|
|
14
|
+
reliable(): boolean;
|
|
15
|
+
attachConn(conn: Conn): void;
|
|
16
|
+
handle(f: Frame): Promise<void>;
|
|
17
|
+
close(err?: unknown): void;
|
|
18
|
+
}
|
|
19
|
+
declare class UdpGateway implements FrameHandler {
|
|
20
|
+
private readonly socket;
|
|
21
|
+
private readonly max;
|
|
22
|
+
private readonly peers;
|
|
23
|
+
private server;
|
|
24
|
+
private closed;
|
|
25
|
+
constructor(socket: Socket, opts?: {
|
|
26
|
+
maxMessageSize?: number;
|
|
27
|
+
});
|
|
28
|
+
serve(server: Server): Promise<void>;
|
|
29
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
30
|
+
close(): void;
|
|
31
|
+
}
|
|
32
|
+
declare function dialUdp(port: number, host?: string, opts?: ConnOptions & {
|
|
33
|
+
maxMessageSize?: number;
|
|
34
|
+
}): Promise<Conn>;
|
|
35
|
+
declare function listenUdp(port?: number, host?: string, opts?: {
|
|
36
|
+
maxMessageSize?: number;
|
|
37
|
+
}): Promise<{
|
|
38
|
+
gateway: UdpGateway;
|
|
39
|
+
port: number;
|
|
40
|
+
}>;
|
|
41
|
+
//#endregion
|
|
42
|
+
export { DefaultMaxMessageSize, UdpGateway, UdpTransport, dialUdp, listenUdp };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { $ as unpack, c as decodeEnvelop, u as encodeEnvelop } from "../wire-BR8KiyRg.mjs";
|
|
2
|
+
import { n as MessageTooLargeError } from "../status-DZwMDWIn.mjs";
|
|
3
|
+
import { n as Conn } from "../conn-DOmx4nbt.mjs";
|
|
4
|
+
import { createSocket } from "node:dgram";
|
|
5
|
+
//#region src/transport/node-udp/index.ts
|
|
6
|
+
const DefaultMaxMessageSize = 1200;
|
|
7
|
+
function transient(err) {
|
|
8
|
+
const code = err?.code;
|
|
9
|
+
return code === "ECONNREFUSED" || code === "EHOSTUNREACH" || code === "ENETUNREACH";
|
|
10
|
+
}
|
|
11
|
+
function sendDatagram(socket, data, target) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
const cb = (err) => {
|
|
14
|
+
if (err && !transient(err)) reject(err);
|
|
15
|
+
else resolve();
|
|
16
|
+
};
|
|
17
|
+
if (target !== void 0) socket.send(data, target.port, target.address, cb);
|
|
18
|
+
else socket.send(data, cb);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
var UdpTransport = class {
|
|
22
|
+
socket;
|
|
23
|
+
max;
|
|
24
|
+
conn;
|
|
25
|
+
closed = false;
|
|
26
|
+
constructor(socket, opts = {}) {
|
|
27
|
+
this.socket = socket;
|
|
28
|
+
this.max = opts.maxMessageSize ?? 1200;
|
|
29
|
+
}
|
|
30
|
+
reliable() {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
attachConn(conn) {
|
|
34
|
+
if (this.conn !== void 0) throw new Error("node-udp: transport already attached to a Conn");
|
|
35
|
+
this.conn = conn;
|
|
36
|
+
this.socket.on("message", (data) => {
|
|
37
|
+
let frames;
|
|
38
|
+
try {
|
|
39
|
+
frames = decodeEnvelop(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
40
|
+
} catch {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
unpack(frames, conn, {});
|
|
44
|
+
});
|
|
45
|
+
this.socket.on("error", (err) => {
|
|
46
|
+
if (transient(err)) return;
|
|
47
|
+
this.close(err);
|
|
48
|
+
});
|
|
49
|
+
this.socket.on("close", () => this.conn?.close());
|
|
50
|
+
}
|
|
51
|
+
handle(f) {
|
|
52
|
+
const data = encodeEnvelop([f]);
|
|
53
|
+
if (this.max > 0 && data.length > this.max) throw new MessageTooLargeError(`node-udp: ${data.length}-byte envelop over the ${this.max}-byte limit`);
|
|
54
|
+
return sendDatagram(this.socket, data);
|
|
55
|
+
}
|
|
56
|
+
close(err) {
|
|
57
|
+
if (this.closed) return;
|
|
58
|
+
this.closed = true;
|
|
59
|
+
try {
|
|
60
|
+
this.socket.close();
|
|
61
|
+
} catch {}
|
|
62
|
+
this.conn?.close(err);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function peerKey(rinfo) {
|
|
66
|
+
return `${rinfo.address}:${rinfo.port}`;
|
|
67
|
+
}
|
|
68
|
+
var UdpGateway = class {
|
|
69
|
+
socket;
|
|
70
|
+
max;
|
|
71
|
+
peers = /* @__PURE__ */ new Map();
|
|
72
|
+
server;
|
|
73
|
+
closed = false;
|
|
74
|
+
constructor(socket, opts = {}) {
|
|
75
|
+
this.socket = socket;
|
|
76
|
+
this.max = opts.maxMessageSize ?? 1200;
|
|
77
|
+
}
|
|
78
|
+
serve(server) {
|
|
79
|
+
if (this.server !== void 0) throw new Error("node-udp: gateway already serving");
|
|
80
|
+
this.server = server;
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
this.socket.on("message", (data, rinfo) => {
|
|
83
|
+
const key = peerKey(rinfo);
|
|
84
|
+
this.peers.set(key, {
|
|
85
|
+
port: rinfo.port,
|
|
86
|
+
address: rinfo.address
|
|
87
|
+
});
|
|
88
|
+
let frames;
|
|
89
|
+
try {
|
|
90
|
+
frames = decodeEnvelop(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
unpack(frames, server, {
|
|
95
|
+
peer: key,
|
|
96
|
+
reliable: false
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
this.socket.on("close", resolve);
|
|
100
|
+
this.socket.on("error", () => this.close());
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
handle(f, ctx = {}) {
|
|
104
|
+
const key = ctx.peer;
|
|
105
|
+
if (typeof key !== "string") return Promise.reject(/* @__PURE__ */ new Error(`node-udp: no gateway peer in context (got ${String(key)})`));
|
|
106
|
+
const target = this.peers.get(key);
|
|
107
|
+
if (target === void 0) return Promise.reject(/* @__PURE__ */ new Error(`node-udp: peer ${key} is unknown`));
|
|
108
|
+
const data = encodeEnvelop([f]);
|
|
109
|
+
if (this.max > 0 && data.length > this.max) throw new MessageTooLargeError(`node-udp: ${data.length}-byte envelop over the ${this.max}-byte limit`);
|
|
110
|
+
return sendDatagram(this.socket, data, target);
|
|
111
|
+
}
|
|
112
|
+
close() {
|
|
113
|
+
if (this.closed) return;
|
|
114
|
+
this.closed = true;
|
|
115
|
+
try {
|
|
116
|
+
this.socket.close();
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function dialUdp(port, host = "127.0.0.1", opts = {}) {
|
|
121
|
+
const socket = createSocket("udp4");
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
socket.once("error", reject);
|
|
124
|
+
socket.connect(port, host, () => {
|
|
125
|
+
socket.off("error", reject);
|
|
126
|
+
resolve(new Conn(new UdpTransport(socket, opts), opts));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function listenUdp(port = 0, host = "127.0.0.1", opts) {
|
|
131
|
+
const socket = createSocket("udp4");
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
socket.once("error", reject);
|
|
134
|
+
socket.bind(port, host, () => {
|
|
135
|
+
socket.off("error", reject);
|
|
136
|
+
resolve({
|
|
137
|
+
gateway: new UdpGateway(socket, opts),
|
|
138
|
+
port: socket.address().port
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//#endregion
|
|
144
|
+
export { DefaultMaxMessageSize, UdpGateway, UdpTransport, dialUdp, listenUdp };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { O as Frame, _ as TransportInfo, g as FrameHandler, h as FrameContext, m as ConnAttacher, n as Conn, r as ConnOptions } from "../conn-DTWG9vIx.mjs";
|
|
2
|
+
import { r as Server } from "../server-xIr1mwqq.mjs";
|
|
3
|
+
//#region src/transport/port/index.d.ts
|
|
4
|
+
declare const DefaultMaxMessageSize = 0;
|
|
5
|
+
interface PortLike {
|
|
6
|
+
postMessage(data: Uint8Array, transfer?: unknown[]): void;
|
|
7
|
+
addEventListener?(type: string, fn: (ev: unknown) => void): void;
|
|
8
|
+
removeEventListener?(type: string, fn: (ev: unknown) => void): void;
|
|
9
|
+
onmessage?: ((ev: never) => void) | null;
|
|
10
|
+
onmessageerror?: ((ev: never) => void) | null;
|
|
11
|
+
start?(): void;
|
|
12
|
+
close?(): void;
|
|
13
|
+
terminate?(): void;
|
|
14
|
+
}
|
|
15
|
+
interface PortOptions {
|
|
16
|
+
maxMessageSize?: number;
|
|
17
|
+
transfer?: boolean;
|
|
18
|
+
}
|
|
19
|
+
declare class PortTransport implements FrameHandler, TransportInfo, ConnAttacher {
|
|
20
|
+
private readonly pt;
|
|
21
|
+
private attached;
|
|
22
|
+
constructor(port: PortLike, opts?: PortOptions);
|
|
23
|
+
reliable(): boolean;
|
|
24
|
+
attachConn(conn: Conn): void;
|
|
25
|
+
handle(f: Frame): Promise<void>;
|
|
26
|
+
close(cause?: unknown): void;
|
|
27
|
+
}
|
|
28
|
+
interface WorkerLike {
|
|
29
|
+
postMessage(message: unknown, transfer?: unknown[]): void;
|
|
30
|
+
}
|
|
31
|
+
interface WorkerDialOptions extends PortOptions {
|
|
32
|
+
message?: unknown;
|
|
33
|
+
}
|
|
34
|
+
declare function dialWorker(worker: WorkerLike, opts?: ConnOptions & WorkerDialOptions): Conn;
|
|
35
|
+
declare class PortGateway implements FrameHandler, TransportInfo {
|
|
36
|
+
private readonly o;
|
|
37
|
+
private next;
|
|
38
|
+
private readonly ports;
|
|
39
|
+
private readonly peers;
|
|
40
|
+
constructor(opts?: PortOptions);
|
|
41
|
+
reliable(): boolean;
|
|
42
|
+
bind(port: PortLike): void;
|
|
43
|
+
private bindPort;
|
|
44
|
+
private drop;
|
|
45
|
+
servePeer(server: Server, port: PortLike, opts?: {
|
|
46
|
+
signal?: AbortSignal;
|
|
47
|
+
}): Promise<unknown>;
|
|
48
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
49
|
+
close(): void;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { DefaultMaxMessageSize, PortGateway, PortLike, PortOptions, PortTransport, WorkerDialOptions, WorkerLike, dialWorker };
|