@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,240 @@
|
|
|
1
|
+
import { $ as unpack, F as Latch, G as noop, R as abortListener, c as decodeEnvelop, u as encodeEnvelop } from "../wire-BR8KiyRg.mjs";
|
|
2
|
+
import { n as MessageTooLargeError, r as StatusError } from "../status-DZwMDWIn.mjs";
|
|
3
|
+
import { n as Conn } from "../conn-DOmx4nbt.mjs";
|
|
4
|
+
//#region src/transport/port/index.ts
|
|
5
|
+
const DefaultMaxMessageSize = 0;
|
|
6
|
+
const GOODBYE = /* @__PURE__ */ new Uint8Array(0);
|
|
7
|
+
function wire(port, type, fn) {
|
|
8
|
+
if (typeof port.addEventListener === "function") {
|
|
9
|
+
port.addEventListener(type, fn);
|
|
10
|
+
return () => port.removeEventListener?.(type, fn);
|
|
11
|
+
}
|
|
12
|
+
if (type === "message") {
|
|
13
|
+
port.onmessage = fn;
|
|
14
|
+
return () => {
|
|
15
|
+
port.onmessage = null;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (type === "messageerror") {
|
|
19
|
+
port.onmessageerror = fn;
|
|
20
|
+
return () => {
|
|
21
|
+
port.onmessageerror = null;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return noop;
|
|
25
|
+
}
|
|
26
|
+
function wakeAll(waiters) {
|
|
27
|
+
if (waiters.length === 0) return;
|
|
28
|
+
const ws = waiters.splice(0);
|
|
29
|
+
for (const w of ws) w();
|
|
30
|
+
}
|
|
31
|
+
var Port = class {
|
|
32
|
+
port;
|
|
33
|
+
max;
|
|
34
|
+
transferable;
|
|
35
|
+
dead = new Latch();
|
|
36
|
+
err;
|
|
37
|
+
closed = false;
|
|
38
|
+
rx = [];
|
|
39
|
+
rxWaiters = [];
|
|
40
|
+
detach = [];
|
|
41
|
+
constructor(port, o) {
|
|
42
|
+
this.port = port;
|
|
43
|
+
this.max = o.maxMessageSize ?? 0;
|
|
44
|
+
this.transferable = o.transfer ?? true;
|
|
45
|
+
this.detach.push(wire(port, "message", (ev) => this.onMessage(ev)));
|
|
46
|
+
this.detach.push(wire(port, "messageerror", noop));
|
|
47
|
+
this.detach.push(wire(port, "close", () => this.fail(void 0)));
|
|
48
|
+
port.start?.();
|
|
49
|
+
}
|
|
50
|
+
fail(err) {
|
|
51
|
+
if (!this.dead.tripped && this.err === void 0) this.err = err;
|
|
52
|
+
this.dead.trip();
|
|
53
|
+
wakeAll(this.rxWaiters);
|
|
54
|
+
}
|
|
55
|
+
closedErr() {
|
|
56
|
+
const e = new StatusError(14, `port: endpoint closed${causeDetail(this.err)}`);
|
|
57
|
+
if (this.err !== void 0) e.cause = this.err;
|
|
58
|
+
return e;
|
|
59
|
+
}
|
|
60
|
+
onMessage(ev) {
|
|
61
|
+
if (this.dead.tripped) return;
|
|
62
|
+
const data = ev.data;
|
|
63
|
+
if (data instanceof ArrayBuffer) this.rx.push(new Uint8Array(data));
|
|
64
|
+
else if (ArrayBuffer.isView(data)) this.rx.push(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
65
|
+
else return;
|
|
66
|
+
wakeAll(this.rxWaiters);
|
|
67
|
+
}
|
|
68
|
+
async send(frames) {
|
|
69
|
+
const data = encodeEnvelop(frames);
|
|
70
|
+
if (this.max > 0 && data.length > this.max) throw new MessageTooLargeError(`port: ${data.length}-byte envelop over the ${this.max}-byte limit`);
|
|
71
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
72
|
+
try {
|
|
73
|
+
this.post(data);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
this.fail(e);
|
|
76
|
+
throw this.closedErr();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
post(data) {
|
|
80
|
+
if (this.transferable && data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) try {
|
|
81
|
+
this.port.postMessage(data, [data.buffer]);
|
|
82
|
+
return;
|
|
83
|
+
} catch (e) {
|
|
84
|
+
if (data.byteLength === 0) throw e;
|
|
85
|
+
}
|
|
86
|
+
this.port.postMessage(data);
|
|
87
|
+
}
|
|
88
|
+
async pump(h, ctx) {
|
|
89
|
+
const dctl = new AbortController();
|
|
90
|
+
this.dead.wait().then(() => dctl.abort(this.closedErr()));
|
|
91
|
+
const dctx = {
|
|
92
|
+
...ctx,
|
|
93
|
+
signal: dctl.signal
|
|
94
|
+
};
|
|
95
|
+
for (;;) {
|
|
96
|
+
const data = this.rx.shift();
|
|
97
|
+
if (data !== void 0) {
|
|
98
|
+
if (data.length === 0) {
|
|
99
|
+
this.fail(void 0);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let frames;
|
|
103
|
+
try {
|
|
104
|
+
frames = decodeEnvelop(data);
|
|
105
|
+
} catch {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
await unpack(frames, h, dctx);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (this.dead.tripped) return this.err;
|
|
112
|
+
await Promise.race([this.rxReadable(), this.dead.wait()]);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
rxReadable() {
|
|
116
|
+
if (this.rx.length > 0) return Promise.resolve();
|
|
117
|
+
return new Promise((res) => this.rxWaiters.push(res));
|
|
118
|
+
}
|
|
119
|
+
close(cause) {
|
|
120
|
+
if (this.closed) return;
|
|
121
|
+
this.closed = true;
|
|
122
|
+
if (!this.dead.tripped) try {
|
|
123
|
+
this.port.postMessage(GOODBYE);
|
|
124
|
+
} catch {}
|
|
125
|
+
this.fail(cause);
|
|
126
|
+
if (this.port !== globalThis) try {
|
|
127
|
+
this.port.close?.();
|
|
128
|
+
} catch {}
|
|
129
|
+
for (const off of this.detach.splice(0)) off();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
function causeDetail(err) {
|
|
133
|
+
if (err === void 0) return "";
|
|
134
|
+
if (err instanceof Error) return `: ${err.message}`;
|
|
135
|
+
return `: ${String(err)}`;
|
|
136
|
+
}
|
|
137
|
+
var PortTransport = class {
|
|
138
|
+
pt;
|
|
139
|
+
attached = false;
|
|
140
|
+
constructor(port, opts = {}) {
|
|
141
|
+
this.pt = new Port(port, opts);
|
|
142
|
+
}
|
|
143
|
+
reliable() {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
attachConn(conn) {
|
|
147
|
+
if (this.attached) throw new Error("port: transport already attached to a Conn");
|
|
148
|
+
this.attached = true;
|
|
149
|
+
(async () => {
|
|
150
|
+
const err = await this.pt.pump(conn, {});
|
|
151
|
+
conn.close(err);
|
|
152
|
+
this.close();
|
|
153
|
+
})();
|
|
154
|
+
}
|
|
155
|
+
handle(f) {
|
|
156
|
+
return this.pt.send([f]);
|
|
157
|
+
}
|
|
158
|
+
close(cause) {
|
|
159
|
+
this.pt.close(cause);
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
function dialWorker(worker, opts = {}) {
|
|
163
|
+
const ch = new MessageChannel();
|
|
164
|
+
let tx;
|
|
165
|
+
try {
|
|
166
|
+
tx = new PortTransport(ch.port1, opts);
|
|
167
|
+
const conn = new Conn(tx, opts);
|
|
168
|
+
worker.postMessage(opts.message ?? { drpc: "serve" }, [ch.port2]);
|
|
169
|
+
return conn;
|
|
170
|
+
} catch (e) {
|
|
171
|
+
tx?.close(e);
|
|
172
|
+
ch.port1.close();
|
|
173
|
+
ch.port2.close();
|
|
174
|
+
throw e;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
var PortGateway = class {
|
|
178
|
+
o;
|
|
179
|
+
next = 0;
|
|
180
|
+
ports = /* @__PURE__ */ new Map();
|
|
181
|
+
peers = /* @__PURE__ */ new Map();
|
|
182
|
+
constructor(opts = {}) {
|
|
183
|
+
this.o = opts;
|
|
184
|
+
}
|
|
185
|
+
reliable() {
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
bind(port) {
|
|
189
|
+
this.bindPort(port);
|
|
190
|
+
}
|
|
191
|
+
bindPort(port) {
|
|
192
|
+
let b = this.ports.get(port);
|
|
193
|
+
if (b === void 0) {
|
|
194
|
+
b = {
|
|
195
|
+
pt: new Port(port, this.o),
|
|
196
|
+
key: ++this.next,
|
|
197
|
+
served: false
|
|
198
|
+
};
|
|
199
|
+
this.ports.set(port, b);
|
|
200
|
+
this.peers.set(b.key, b.pt);
|
|
201
|
+
}
|
|
202
|
+
return b;
|
|
203
|
+
}
|
|
204
|
+
drop(port, b) {
|
|
205
|
+
b.pt.close();
|
|
206
|
+
this.ports.delete(port);
|
|
207
|
+
this.peers.delete(b.key);
|
|
208
|
+
}
|
|
209
|
+
async servePeer(server, port, opts = {}) {
|
|
210
|
+
const b = this.bindPort(port);
|
|
211
|
+
if (b.served) throw new Error("port: port already served");
|
|
212
|
+
b.served = true;
|
|
213
|
+
let disposeAbort = noop;
|
|
214
|
+
if (opts.signal !== void 0) if (opts.signal.aborted) b.pt.close();
|
|
215
|
+
else disposeAbort = abortListener(opts.signal, () => b.pt.close());
|
|
216
|
+
try {
|
|
217
|
+
const err = await b.pt.pump(server, {
|
|
218
|
+
peer: b.key,
|
|
219
|
+
reliable: true
|
|
220
|
+
});
|
|
221
|
+
server.disconnectPeer(b.key, err);
|
|
222
|
+
return err;
|
|
223
|
+
} finally {
|
|
224
|
+
disposeAbort();
|
|
225
|
+
this.drop(port, b);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
handle(f, ctx = {}) {
|
|
229
|
+
const key = ctx.peer;
|
|
230
|
+
if (typeof key !== "number") return Promise.reject(/* @__PURE__ */ new Error(`port: no gateway peer in context (got ${String(key)})`));
|
|
231
|
+
const pt = this.peers.get(key);
|
|
232
|
+
if (pt === void 0) return Promise.reject(/* @__PURE__ */ new Error(`port: peer ${key} is disconnected`));
|
|
233
|
+
return pt.send([f]);
|
|
234
|
+
}
|
|
235
|
+
close() {
|
|
236
|
+
for (const b of [...this.ports.values()]) b.pt.close();
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
export { DefaultMaxMessageSize, PortGateway, PortTransport, dialWorker };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { c as ServerStreamingDesc, l as UnaryDesc, r as ClientStreamingDesc, t as BidiDesc } from "../desc-BMF2FBqk.mjs";
|
|
2
|
+
import { DescMessage, DescMethod, MessageShape } from "@bufbuild/protobuf";
|
|
3
|
+
import { GenService, GenServiceMethods } from "@bufbuild/protobuf/codegenv2";
|
|
4
|
+
//#region src/transport/protobuf-es/index.d.ts
|
|
5
|
+
type MethodLike<K extends DescMethod['methodKind'], I extends DescMessage, O extends DescMessage> = {
|
|
6
|
+
readonly methodKind: K;
|
|
7
|
+
readonly input: I;
|
|
8
|
+
readonly output: O;
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly parent: {
|
|
11
|
+
readonly typeName: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
type MethodDescFor<M> = M extends MethodLike<infer K, infer I, infer O> ? K extends 'unary' ? UnaryDesc<MessageShape<I>, MessageShape<O>> : K extends 'server_streaming' ? ServerStreamingDesc<MessageShape<I>, MessageShape<O>> : K extends 'client_streaming' ? ClientStreamingDesc<MessageShape<I>, MessageShape<O>> : BidiDesc<MessageShape<I>, MessageShape<O>> : never;
|
|
15
|
+
declare function fromMethod<K extends DescMethod['methodKind'], I extends DescMessage, O extends DescMessage>(method: MethodLike<K, I, O>): MethodDescFor<MethodLike<K, I, O>>;
|
|
16
|
+
type ServiceDescs<S extends GenService<GenServiceMethods>> = { [K in keyof S['method']]: MethodDescFor<S['method'][K]>; };
|
|
17
|
+
declare function fromService<S extends GenService<GenServiceMethods>>(service: S): ServiceDescs<S>;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { ServiceDescs, fromMethod, fromService };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { fromBinary, toBinary } from "@bufbuild/protobuf";
|
|
2
|
+
//#region src/transport/protobuf-es/index.ts
|
|
3
|
+
function codecFor(schema) {
|
|
4
|
+
return {
|
|
5
|
+
marshal: (v) => toBinary(schema, v),
|
|
6
|
+
unmarshal: (b) => fromBinary(schema, b)
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function fromMethod(method) {
|
|
10
|
+
const kind = method.methodKind;
|
|
11
|
+
return {
|
|
12
|
+
path: `/${method.parent.typeName}/${method.name}`,
|
|
13
|
+
clientStreams: kind === "client_streaming" || kind === "bidi_streaming",
|
|
14
|
+
serverStreams: kind === "server_streaming" || kind === "bidi_streaming",
|
|
15
|
+
request: codecFor(method.input),
|
|
16
|
+
response: codecFor(method.output),
|
|
17
|
+
requestSchema: method.input,
|
|
18
|
+
responseSchema: method.output
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function fromService(service) {
|
|
22
|
+
const out = {};
|
|
23
|
+
for (const key of Object.keys(service.method)) out[key] = fromMethod(service.method[key]);
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { fromMethod, fromService };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { O as Frame, h as FrameContext, n as Conn } from "../conn-DTWG9vIx.mjs";
|
|
2
|
+
import { r as Server } from "../server-xIr1mwqq.mjs";
|
|
3
|
+
//#region src/transport/webrtc/index.d.ts
|
|
4
|
+
declare const DefaultMaxMessageSizeUnreliable = 1200;
|
|
5
|
+
declare const DefaultMaxMessageSizeReliable: number;
|
|
6
|
+
declare const DefaultMaxBufferedAmount: number;
|
|
7
|
+
declare const DefaultSendStallTimeoutMs = 30000;
|
|
8
|
+
interface DataChannelLike {
|
|
9
|
+
readonly readyState: string;
|
|
10
|
+
readonly ordered: boolean;
|
|
11
|
+
readonly maxRetransmits?: number | null;
|
|
12
|
+
readonly maxPacketLifeTime?: number | null;
|
|
13
|
+
readonly bufferedAmount: number;
|
|
14
|
+
bufferedAmountLowThreshold: number;
|
|
15
|
+
binaryType: string;
|
|
16
|
+
send(data: Uint8Array): void;
|
|
17
|
+
close(): void;
|
|
18
|
+
addEventListener?(type: string, listener: (ev: never) => void): void;
|
|
19
|
+
onopen?: ((ev: unknown) => void) | null;
|
|
20
|
+
onclose?: ((ev: unknown) => void) | null;
|
|
21
|
+
onerror?: ((ev: unknown) => void) | null;
|
|
22
|
+
onmessage?: ((ev: unknown) => void) | null;
|
|
23
|
+
onbufferedamountlow?: ((ev: unknown) => void) | null;
|
|
24
|
+
}
|
|
25
|
+
interface DataChannelOptions {
|
|
26
|
+
maxMessageSize?: number;
|
|
27
|
+
maxBufferedAmount?: number;
|
|
28
|
+
sendStallTimeoutMs?: number;
|
|
29
|
+
}
|
|
30
|
+
declare function channelReliable(dc: DataChannelLike): boolean;
|
|
31
|
+
declare class DataChannelTransport {
|
|
32
|
+
private readonly ch;
|
|
33
|
+
private attached;
|
|
34
|
+
private closed;
|
|
35
|
+
constructor(dc: DataChannelLike, opts?: DataChannelOptions);
|
|
36
|
+
reliable(): boolean;
|
|
37
|
+
attachConn(conn: Conn): void;
|
|
38
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
39
|
+
close(): void;
|
|
40
|
+
}
|
|
41
|
+
declare class DataChannelGateway {
|
|
42
|
+
private readonly o;
|
|
43
|
+
private next;
|
|
44
|
+
private readonly chans;
|
|
45
|
+
private readonly peers;
|
|
46
|
+
constructor(opts?: DataChannelOptions);
|
|
47
|
+
bind(dc: DataChannelLike): void;
|
|
48
|
+
private bindChannel;
|
|
49
|
+
private drop;
|
|
50
|
+
servePeer(server: Server, dc: DataChannelLike, opts?: {
|
|
51
|
+
signal?: AbortSignal;
|
|
52
|
+
}): Promise<unknown>;
|
|
53
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { DataChannelGateway, DataChannelLike, DataChannelOptions, DataChannelTransport, DefaultMaxBufferedAmount, DefaultMaxMessageSizeReliable, DefaultMaxMessageSizeUnreliable, DefaultSendStallTimeoutMs, channelReliable };
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { $ as unpack, F as Latch, G as noop, R as abortListener, X as unrefTimer, c as decodeEnvelop, u as encodeEnvelop } from "../wire-BR8KiyRg.mjs";
|
|
2
|
+
import { n as MessageTooLargeError } from "../status-DZwMDWIn.mjs";
|
|
3
|
+
//#region src/transport/webrtc/index.ts
|
|
4
|
+
const DefaultMaxMessageSizeUnreliable = 1200;
|
|
5
|
+
const DefaultMaxMessageSizeReliable = 16 * 1024;
|
|
6
|
+
const DefaultMaxBufferedAmount = 1 << 20;
|
|
7
|
+
const DefaultSendStallTimeoutMs = 3e4;
|
|
8
|
+
function channelReliable(dc) {
|
|
9
|
+
return dc.ordered && dc.maxRetransmits == null && dc.maxPacketLifeTime == null;
|
|
10
|
+
}
|
|
11
|
+
function wire(dc, type, fn) {
|
|
12
|
+
if (typeof dc.addEventListener === "function") dc.addEventListener(type, fn);
|
|
13
|
+
else dc[`on${type}`] = fn;
|
|
14
|
+
}
|
|
15
|
+
var Channel = class {
|
|
16
|
+
dc;
|
|
17
|
+
reliable;
|
|
18
|
+
max;
|
|
19
|
+
high;
|
|
20
|
+
stallMs;
|
|
21
|
+
opened = new Latch();
|
|
22
|
+
dead = new Latch();
|
|
23
|
+
err;
|
|
24
|
+
rx = [];
|
|
25
|
+
rxWaiters = [];
|
|
26
|
+
bufLowWaiters = [];
|
|
27
|
+
constructor(dc, reliable, o) {
|
|
28
|
+
this.dc = dc;
|
|
29
|
+
this.reliable = reliable;
|
|
30
|
+
this.max = o.maxMessageSize ?? (reliable ? 16384 : 1200);
|
|
31
|
+
this.high = o.maxBufferedAmount ?? 1048576;
|
|
32
|
+
this.stallMs = o.sendStallTimeoutMs ?? 3e4;
|
|
33
|
+
dc.binaryType = "arraybuffer";
|
|
34
|
+
wire(dc, "open", () => this.opened.trip());
|
|
35
|
+
wire(dc, "error", (ev) => this.fail(ev?.error ?? ev));
|
|
36
|
+
wire(dc, "close", () => this.fail(void 0));
|
|
37
|
+
if (this.high > 0) {
|
|
38
|
+
dc.bufferedAmountLowThreshold = Math.floor(this.high / 2);
|
|
39
|
+
wire(dc, "bufferedamountlow", () => wakeAll(this.bufLowWaiters));
|
|
40
|
+
}
|
|
41
|
+
wire(dc, "message", (ev) => this.onMessage(ev));
|
|
42
|
+
if (dc.readyState === "open") this.opened.trip();
|
|
43
|
+
else if (dc.readyState === "closed" || dc.readyState === "closing") this.fail(void 0);
|
|
44
|
+
}
|
|
45
|
+
fail(err) {
|
|
46
|
+
if (!this.dead.tripped && this.err === void 0) this.err = err;
|
|
47
|
+
this.dead.trip();
|
|
48
|
+
wakeAll(this.bufLowWaiters);
|
|
49
|
+
wakeAll(this.rxWaiters);
|
|
50
|
+
}
|
|
51
|
+
deathErr() {
|
|
52
|
+
return this.err;
|
|
53
|
+
}
|
|
54
|
+
closedErr() {
|
|
55
|
+
const e = /* @__PURE__ */ new Error("webrtc: data channel closed");
|
|
56
|
+
if (this.err !== void 0) e.cause = this.err;
|
|
57
|
+
return e;
|
|
58
|
+
}
|
|
59
|
+
onMessage(ev) {
|
|
60
|
+
const data = ev.data;
|
|
61
|
+
if (data instanceof ArrayBuffer) this.rx.push(new Uint8Array(data));
|
|
62
|
+
else if (data instanceof Uint8Array) this.rx.push(data);
|
|
63
|
+
else return;
|
|
64
|
+
wakeAll(this.rxWaiters);
|
|
65
|
+
}
|
|
66
|
+
async send(frames, signal) {
|
|
67
|
+
const data = encodeEnvelop(frames);
|
|
68
|
+
if (this.max > 0 && data.length > this.max) throw new MessageTooLargeError(`webrtc: ${data.length}-byte envelop over the ${this.max}-byte limit`);
|
|
69
|
+
const stalled = new Latch();
|
|
70
|
+
let stallTimer;
|
|
71
|
+
if (this.stallMs > 0) {
|
|
72
|
+
stallTimer = setTimeout(() => stalled.trip(), this.stallMs);
|
|
73
|
+
unrefTimer(stallTimer);
|
|
74
|
+
}
|
|
75
|
+
let disposeAbort = noop;
|
|
76
|
+
const signalAborted = new Latch();
|
|
77
|
+
if (signal !== void 0) if (signal.aborted) signalAborted.trip();
|
|
78
|
+
else disposeAbort = abortListener(signal, () => signalAborted.trip());
|
|
79
|
+
try {
|
|
80
|
+
while (!this.opened.tripped) {
|
|
81
|
+
await Promise.race([
|
|
82
|
+
this.opened.wait(),
|
|
83
|
+
stalled.wait(),
|
|
84
|
+
this.dead.wait(),
|
|
85
|
+
signalAborted.wait()
|
|
86
|
+
]);
|
|
87
|
+
if (this.opened.tripped) break;
|
|
88
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
89
|
+
if (stalled.tripped) {
|
|
90
|
+
const err = /* @__PURE__ */ new Error(`webrtc: send stalled: channel not open within ${this.stallMs}ms`);
|
|
91
|
+
this.fail(err);
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
if (signalAborted.tripped) throw new Error("webrtc: send aborted");
|
|
95
|
+
}
|
|
96
|
+
while (this.high > 0 && this.dc.bufferedAmount >= this.high) {
|
|
97
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
98
|
+
const low = new Promise((res) => this.bufLowWaiters.push(res));
|
|
99
|
+
await Promise.race([
|
|
100
|
+
low,
|
|
101
|
+
stalled.wait(),
|
|
102
|
+
this.dead.wait(),
|
|
103
|
+
signalAborted.wait()
|
|
104
|
+
]);
|
|
105
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
106
|
+
if (stalled.tripped) {
|
|
107
|
+
const err = /* @__PURE__ */ new Error(`webrtc: send stalled at the buffered-amount mark for ${this.stallMs}ms`);
|
|
108
|
+
this.fail(err);
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
if (signalAborted.tripped) throw new Error("webrtc: send aborted");
|
|
112
|
+
}
|
|
113
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
114
|
+
this.dc.send(data);
|
|
115
|
+
} finally {
|
|
116
|
+
if (stallTimer !== void 0) clearTimeout(stallTimer);
|
|
117
|
+
disposeAbort();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async pump(h, ctx) {
|
|
121
|
+
const dctl = new AbortController();
|
|
122
|
+
this.dead.wait().then(() => dctl.abort(this.closedErr()));
|
|
123
|
+
const dctx = {
|
|
124
|
+
...ctx,
|
|
125
|
+
signal: dctl.signal
|
|
126
|
+
};
|
|
127
|
+
for (;;) {
|
|
128
|
+
const data = this.rx.shift();
|
|
129
|
+
if (data !== void 0) {
|
|
130
|
+
let frames;
|
|
131
|
+
try {
|
|
132
|
+
frames = decodeEnvelop(data);
|
|
133
|
+
} catch {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
await unpack(frames, h, dctx);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (this.dead.tripped) return this.err;
|
|
140
|
+
await Promise.race([this.rxReadable(), this.dead.wait()]);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
rxReadable() {
|
|
144
|
+
if (this.rx.length > 0) return Promise.resolve();
|
|
145
|
+
return new Promise((res) => this.rxWaiters.push(res));
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
function wakeAll(waiters) {
|
|
149
|
+
if (waiters.length === 0) return;
|
|
150
|
+
const ws = waiters.splice(0);
|
|
151
|
+
for (const w of ws) w();
|
|
152
|
+
}
|
|
153
|
+
var DataChannelTransport = class {
|
|
154
|
+
ch;
|
|
155
|
+
attached = false;
|
|
156
|
+
closed = false;
|
|
157
|
+
constructor(dc, opts = {}) {
|
|
158
|
+
this.ch = new Channel(dc, channelReliable(dc), opts);
|
|
159
|
+
}
|
|
160
|
+
reliable() {
|
|
161
|
+
return this.ch.reliable;
|
|
162
|
+
}
|
|
163
|
+
attachConn(conn) {
|
|
164
|
+
if (this.attached) throw new Error("webrtc: transport already attached to a Conn");
|
|
165
|
+
this.attached = true;
|
|
166
|
+
(async () => {
|
|
167
|
+
const err = await this.ch.pump(conn, {});
|
|
168
|
+
conn.close(err);
|
|
169
|
+
})();
|
|
170
|
+
}
|
|
171
|
+
handle(f, ctx = {}) {
|
|
172
|
+
return this.ch.send([f], ctx.signal);
|
|
173
|
+
}
|
|
174
|
+
close() {
|
|
175
|
+
if (this.closed) return;
|
|
176
|
+
this.closed = true;
|
|
177
|
+
this.ch.fail(void 0);
|
|
178
|
+
try {
|
|
179
|
+
this.ch.dc.close();
|
|
180
|
+
} catch {}
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
var DataChannelGateway = class {
|
|
184
|
+
o;
|
|
185
|
+
next = 0;
|
|
186
|
+
chans = /* @__PURE__ */ new Map();
|
|
187
|
+
peers = /* @__PURE__ */ new Map();
|
|
188
|
+
constructor(opts = {}) {
|
|
189
|
+
this.o = opts;
|
|
190
|
+
}
|
|
191
|
+
bind(dc) {
|
|
192
|
+
this.bindChannel(dc);
|
|
193
|
+
}
|
|
194
|
+
bindChannel(dc) {
|
|
195
|
+
let b = this.chans.get(dc);
|
|
196
|
+
if (b === void 0) {
|
|
197
|
+
b = {
|
|
198
|
+
ch: new Channel(dc, channelReliable(dc), this.o),
|
|
199
|
+
key: ++this.next,
|
|
200
|
+
served: false
|
|
201
|
+
};
|
|
202
|
+
this.chans.set(dc, b);
|
|
203
|
+
this.peers.set(b.key, b.ch);
|
|
204
|
+
}
|
|
205
|
+
return b;
|
|
206
|
+
}
|
|
207
|
+
drop(dc, b) {
|
|
208
|
+
b.ch.fail(void 0);
|
|
209
|
+
this.chans.delete(dc);
|
|
210
|
+
this.peers.delete(b.key);
|
|
211
|
+
}
|
|
212
|
+
async servePeer(server, dc, opts = {}) {
|
|
213
|
+
const b = this.bindChannel(dc);
|
|
214
|
+
if (b.served) throw new Error("webrtc: channel already served");
|
|
215
|
+
b.served = true;
|
|
216
|
+
let disposeAbort = noop;
|
|
217
|
+
if (opts.signal !== void 0) if (opts.signal.aborted) b.ch.fail(void 0);
|
|
218
|
+
else disposeAbort = abortListener(opts.signal, () => b.ch.fail(void 0));
|
|
219
|
+
try {
|
|
220
|
+
const err = await b.ch.pump(server, {
|
|
221
|
+
peer: b.key,
|
|
222
|
+
reliable: b.ch.reliable
|
|
223
|
+
});
|
|
224
|
+
server.disconnectPeer(b.key, err);
|
|
225
|
+
return err;
|
|
226
|
+
} finally {
|
|
227
|
+
disposeAbort();
|
|
228
|
+
this.drop(dc, b);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
handle(f, ctx = {}) {
|
|
232
|
+
const key = ctx.peer;
|
|
233
|
+
if (typeof key !== "number") return Promise.reject(/* @__PURE__ */ new Error(`webrtc: no gateway peer in context (got ${String(key)})`));
|
|
234
|
+
const ch = this.peers.get(key);
|
|
235
|
+
if (ch === void 0) return Promise.reject(/* @__PURE__ */ new Error(`webrtc: peer ${key} is gone`));
|
|
236
|
+
return ch.send([f], ctx.signal);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
//#endregion
|
|
240
|
+
export { DataChannelGateway, DataChannelTransport, DefaultMaxBufferedAmount, DefaultMaxMessageSizeReliable, DefaultMaxMessageSizeUnreliable, DefaultSendStallTimeoutMs, channelReliable };
|
|
@@ -0,0 +1,59 @@
|
|
|
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/websocket/index.d.ts
|
|
4
|
+
declare const DefaultMaxMessageSize = 0;
|
|
5
|
+
declare const DefaultMaxBufferedAmount: number;
|
|
6
|
+
declare const DefaultKeepaliveIntervalMs = 20000;
|
|
7
|
+
declare const DefaultKeepaliveTimeoutMs = 30000;
|
|
8
|
+
interface WebSocketLike {
|
|
9
|
+
readonly readyState: number;
|
|
10
|
+
readonly bufferedAmount: number;
|
|
11
|
+
binaryType: string;
|
|
12
|
+
send(data: Uint8Array): void;
|
|
13
|
+
close(code?: number, reason?: string): void;
|
|
14
|
+
addEventListener?(type: string, listener: (ev: never) => void): void;
|
|
15
|
+
onopen?: ((ev: unknown) => void) | null;
|
|
16
|
+
onclose?: ((ev: unknown) => void) | null;
|
|
17
|
+
onerror?: ((ev: unknown) => void) | null;
|
|
18
|
+
onmessage?: ((ev: unknown) => void) | null;
|
|
19
|
+
ping?(data?: unknown): void;
|
|
20
|
+
on?(type: string, listener: (...args: never[]) => void): void;
|
|
21
|
+
}
|
|
22
|
+
interface WebSocketOptions {
|
|
23
|
+
maxMessageSize?: number;
|
|
24
|
+
maxBufferedAmount?: number;
|
|
25
|
+
sendStallTimeoutMs?: number;
|
|
26
|
+
keepaliveIntervalMs?: number;
|
|
27
|
+
keepaliveTimeoutMs?: number;
|
|
28
|
+
}
|
|
29
|
+
declare class WebSocketTransport implements FrameHandler, TransportInfo, ConnAttacher {
|
|
30
|
+
private readonly sock;
|
|
31
|
+
private attached;
|
|
32
|
+
private closed;
|
|
33
|
+
constructor(ws: WebSocketLike, opts?: WebSocketOptions);
|
|
34
|
+
reliable(): boolean;
|
|
35
|
+
attachConn(conn: Conn): void;
|
|
36
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
37
|
+
close(): void;
|
|
38
|
+
}
|
|
39
|
+
declare class WebSocketGateway implements FrameHandler, TransportInfo {
|
|
40
|
+
private readonly o;
|
|
41
|
+
private next;
|
|
42
|
+
private readonly socks;
|
|
43
|
+
private readonly peers;
|
|
44
|
+
constructor(opts?: WebSocketOptions);
|
|
45
|
+
reliable(): boolean;
|
|
46
|
+
bind(ws: WebSocketLike): void;
|
|
47
|
+
private bindSocket;
|
|
48
|
+
private drop;
|
|
49
|
+
servePeer(server: Server, ws: WebSocketLike, opts?: {
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
}): Promise<unknown>;
|
|
52
|
+
handle(f: Frame, ctx?: FrameContext): Promise<void>;
|
|
53
|
+
close(): void;
|
|
54
|
+
}
|
|
55
|
+
declare function dialWebSocket(url: string, opts?: ConnOptions & WebSocketOptions & {
|
|
56
|
+
protocols?: string | string[];
|
|
57
|
+
}): Conn;
|
|
58
|
+
//#endregion
|
|
59
|
+
export { DefaultKeepaliveIntervalMs, DefaultKeepaliveTimeoutMs, DefaultMaxBufferedAmount, DefaultMaxMessageSize, WebSocketGateway, WebSocketLike, WebSocketOptions, WebSocketTransport, dialWebSocket };
|