@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.
@@ -0,0 +1,849 @@
1
+ import { A as DEFAULT_MAX_SEND_MSG_SIZE, B as checkSendSize, C as isTerminal, E as resetFor, F as Latch, G as noop, H as decompressPayload, I as Sweeper, J as reliableRxSize, K as nowMs, M as FlowReceiver, N as FlowSender, O as shapeOf, P as FrameQueue, Q as hasTransportInfo, R as abortListener, S as isReset, T as legalShape, U as getCompressor, V as compressPayload, W as nonzeroEpoch, X as unrefTimer, Y as sizeOr, Z as hasConnAttacher, _ as isData, at as validateMetadata, ct as resolveLimits, f as frame, g as isCompressed, k as DEFAULT_MAX_RECV_MSG_SIZE, lt as resolveRxConfig, m as hasUnknownFlags, p as frameStatus, q as rawPayload, x as isPing, y as isHeaderFrame, z as checkRecvSize } from "./wire-BR8KiyRg.mjs";
2
+ import { a as isMessageTooLarge, i as abortCause, o as statusError, r as StatusError, s as toStatusError } from "./status-DZwMDWIn.mjs";
3
+ //#region src/seq.ts
4
+ const W_FWD = 4096;
5
+ const K_LOUD = 3;
6
+ var TxSeq = class {
7
+ v = 0;
8
+ next() {
9
+ this.v = this.v + 1 >>> 0;
10
+ return this.v;
11
+ }
12
+ undo(seq) {
13
+ if (seq !== 0 && this.v === seq) this.v = this.v - 1 >>> 0;
14
+ }
15
+ };
16
+ let RxVerdict = /* @__PURE__ */ function(RxVerdict) {
17
+ RxVerdict[RxVerdict["Accept"] = 0] = "Accept";
18
+ RxVerdict[RxVerdict["Dup"] = 1] = "Dup";
19
+ RxVerdict[RxVerdict["Beyond"] = 2] = "Beyond";
20
+ RxVerdict[RxVerdict["DataLoss"] = 3] = "DataLoss";
21
+ RxVerdict[RxVerdict["ProtocolError"] = 4] = "ProtocolError";
22
+ return RxVerdict;
23
+ }({});
24
+ var RxWindow = class {
25
+ l = 0;
26
+ strict = false;
27
+ beyondN = 0;
28
+ beyondLast = 0;
29
+ check(seq) {
30
+ if (seq === 0) return 2;
31
+ if (this.strict) {
32
+ if (seq === this.l + 1 >>> 0) {
33
+ this.l = seq;
34
+ return 0;
35
+ }
36
+ return 4;
37
+ }
38
+ const d = seq - this.l >>> 0;
39
+ if (d === 0 || d >= 2147483648) return 1;
40
+ if (d <= 4096) {
41
+ this.l = seq;
42
+ this.beyondN = 0;
43
+ return 0;
44
+ }
45
+ if (this.beyondN > 0 && seq - this.beyondLast >>> 0 <= 4096) this.beyondN++;
46
+ else this.beyondN = 1;
47
+ this.beyondLast = seq;
48
+ if (this.beyondN >= 3) return 3;
49
+ return 2;
50
+ }
51
+ };
52
+ //#endregion
53
+ //#region src/timing.ts
54
+ function resolveTiming(t = {}) {
55
+ const callMs = t.callMs ?? 5e3;
56
+ const livenessMs = t.livenessMs ?? 15e3;
57
+ const retransmitMs = t.retransmitMs ?? 1e3;
58
+ let tombstoneMs = t.tombstoneMs ?? 3e4;
59
+ if (tombstoneMs < 2 * livenessMs) tombstoneMs = 2 * livenessMs;
60
+ const holdMs = t.holdMs ?? retransmitMs;
61
+ const tickMs = Math.max(1, Math.min(Math.min(retransmitMs, holdMs) / 2, 500));
62
+ return {
63
+ callMs,
64
+ livenessMs,
65
+ retransmitMs,
66
+ tombstoneMs,
67
+ holdMs,
68
+ probeMs: livenessMs / 3,
69
+ tickMs
70
+ };
71
+ }
72
+ //#endregion
73
+ //#region src/conn.ts
74
+ var EndOfStreamError = class extends Error {
75
+ constructor() {
76
+ super("stream ended");
77
+ this.name = "EndOfStreamError";
78
+ }
79
+ };
80
+ function statusDetails(err) {
81
+ return err instanceof StatusError ? err.details : void 0;
82
+ }
83
+ const EMPTY = /* @__PURE__ */ new Uint8Array(0);
84
+ function terminalStatus(f) {
85
+ const st = frameStatus(f);
86
+ if (f.details !== void 0 && f.details.length > 0) st.details = f.details;
87
+ return st;
88
+ }
89
+ var Conn = class {
90
+ epoch;
91
+ tx;
92
+ mode;
93
+ rxCfg;
94
+ limits;
95
+ defaults;
96
+ compressor;
97
+ compressors;
98
+ maxRecv;
99
+ maxSend;
100
+ stallMs;
101
+ ss = /* @__PURE__ */ new Map();
102
+ tombs = /* @__PURE__ */ new Map();
103
+ resetAt = /* @__PURE__ */ new Map();
104
+ sidNext = 0;
105
+ exhausted = false;
106
+ closed = false;
107
+ lastRx = 0;
108
+ lastTx = 0;
109
+ lastPing = 0;
110
+ sw = new Sweeper();
111
+ constructor(tx, opts = {}) {
112
+ this.epoch = nonzeroEpoch();
113
+ this.tx = tx;
114
+ this.mode = {
115
+ reliable: opts.reliable ?? (hasTransportInfo(tx) ? tx.reliable() : false),
116
+ timing: resolveTiming(opts.timing)
117
+ };
118
+ const rx = resolveRxConfig(opts.rxBuffer);
119
+ this.rxCfg = {
120
+ size: reliableRxSize(rx.size, this.mode.reliable),
121
+ policy: rx.policy
122
+ };
123
+ this.limits = resolveLimits(opts.limits);
124
+ this.defaults = opts.defaultCallOptions ?? {};
125
+ this.compressor = opts.compressor ?? "";
126
+ this.compressors = new Map(Object.entries(opts.compressors ?? {}));
127
+ this.maxRecv = sizeOr(opts.maxRecvMsgSize, DEFAULT_MAX_RECV_MSG_SIZE);
128
+ this.maxSend = sizeOr(opts.maxSendMsgSize, DEFAULT_MAX_SEND_MSG_SIZE);
129
+ this.stallMs = opts.timing?.stallMs ?? 3e4;
130
+ if (hasConnAttacher(tx)) tx.attachConn(this);
131
+ }
132
+ get reliable() {
133
+ return this.mode.reliable;
134
+ }
135
+ async handle(f, ctx = {}) {
136
+ const sid = f.sid;
137
+ if (isReset(f)) {
138
+ if (f.epoch !== this.epoch) return;
139
+ const s = this.ss.get(sid);
140
+ if (s !== void 0) {
141
+ s.finishReset();
142
+ return;
143
+ }
144
+ this.clearTombAbort(sid);
145
+ return;
146
+ }
147
+ if (f.peerEpoch !== this.epoch) {
148
+ if (isPing(f) && sid === 0) return;
149
+ await this.sendReset(f);
150
+ return;
151
+ }
152
+ if (shapeOf(f) === 16) {
153
+ const s = this.ss.get(sid);
154
+ if (s !== void 0) await s.handleRx(f, ctx);
155
+ return;
156
+ }
157
+ if (isPing(f)) {
158
+ this.lastRx = nowMs();
159
+ if (sid === 0) return;
160
+ if (this.ss.has(sid)) return;
161
+ await this.sendReset(f);
162
+ return;
163
+ }
164
+ const s = this.ss.get(sid);
165
+ if (s !== void 0) {
166
+ await s.handleRx(f, ctx);
167
+ return;
168
+ }
169
+ if (this.tombs.get(sid) !== void 0) {
170
+ this.lastRx = nowMs();
171
+ if (isTerminal(f)) this.clearTombAbort(sid);
172
+ return;
173
+ }
174
+ await this.sendReset(f);
175
+ }
176
+ close(err) {
177
+ const st = err === void 0 || err === null ? statusError(14, "transport closed") : statusError(14, `transport closed: ${err instanceof Error ? err.message : String(err)}`);
178
+ this.closed = true;
179
+ this.failAll(st);
180
+ this.sw.stop();
181
+ const cl = this.tx.close;
182
+ if (typeof cl === "function") cl.call(this.tx);
183
+ }
184
+ async invoke(desc, req, opts = {}) {
185
+ const merged = {
186
+ ...this.defaults,
187
+ ...opts
188
+ };
189
+ let timeoutCause;
190
+ if (!this.mode.reliable && merged.timeoutMs === void 0) {
191
+ merged.timeoutMs = this.mode.timing.callMs;
192
+ timeoutCause = statusError(4, "drpc: default call timeout");
193
+ }
194
+ const s = this.createStream(desc, merged, timeoutCause);
195
+ let err;
196
+ let out;
197
+ try {
198
+ try {
199
+ await s.sendRaw(req);
200
+ } catch (e) {
201
+ if (!(e instanceof EndOfStreamError)) err = toStatusError(e);
202
+ }
203
+ if (err === void 0) try {
204
+ out = await s.recv();
205
+ if (out === void 0) err = statusError(13, "unary call ended without a response");
206
+ } catch (e) {
207
+ err = toStatusError(e);
208
+ }
209
+ } finally {
210
+ s.abandon();
211
+ }
212
+ if (merged.onHeader !== void 0) merged.onHeader(await s.header());
213
+ if (merged.onTrailer !== void 0) merged.onTrailer(s.trailer());
214
+ if (err !== void 0) throw err;
215
+ return out;
216
+ }
217
+ newStream(desc, opts = {}) {
218
+ const merged = {
219
+ ...this.defaults,
220
+ ...opts
221
+ };
222
+ const s = this.createStream(desc, merged, void 0);
223
+ if (desc.clientStreams) s.sendOpen();
224
+ return s;
225
+ }
226
+ resolveCall(opts) {
227
+ const name = opts.compressor ?? this.compressor;
228
+ let compressor;
229
+ if (name !== "") {
230
+ compressor = this.compressors.get(name) ?? getCompressor(name);
231
+ if (compressor === void 0) throw statusError(13, `drpc: no compressor registered for ${JSON.stringify(name)}`);
232
+ }
233
+ return {
234
+ compressorName: name,
235
+ compressor,
236
+ maxRecv: sizeOr(opts.maxRecvMsgSize, this.maxRecv),
237
+ maxSend: sizeOr(opts.maxSendMsgSize, this.maxSend),
238
+ stallMs: this.stallMs
239
+ };
240
+ }
241
+ createStream(desc, opts, timeoutCause) {
242
+ const ci = this.resolveCall(opts);
243
+ validateMetadata(opts.metadata);
244
+ if (this.closed) throw statusError(14, "drpc: the connection is closed");
245
+ if (this.exhausted) throw statusError(8, "sid space exhausted; create a new Conn");
246
+ this.sidNext = this.sidNext + 1 >>> 0;
247
+ if (this.sidNext === 0) {
248
+ this.exhausted = true;
249
+ throw statusError(8, "sid space exhausted; create a new Conn");
250
+ }
251
+ if (!this.mode.reliable && this.ss.size === 0) {
252
+ const n = nowMs();
253
+ this.lastRx = n;
254
+ this.lastTx = n;
255
+ }
256
+ const s = new ClientStream(this, desc, this.sidNext, opts, ci, timeoutCause);
257
+ this.ss.set(s.sid, s);
258
+ s.arm(opts);
259
+ this.kickSweep();
260
+ return s;
261
+ }
262
+ /** @internal */
263
+ get timing() {
264
+ return this.mode.timing;
265
+ }
266
+ /** @internal */
267
+ get isReliable() {
268
+ return this.mode.reliable;
269
+ }
270
+ /** @internal */
271
+ get streamRxCfg() {
272
+ return this.rxCfg;
273
+ }
274
+ /** @internal */
275
+ transmit(f) {
276
+ this.lastTx = nowMs();
277
+ return Promise.resolve(this.tx.handle(f));
278
+ }
279
+ /** @internal */
280
+ noteRx() {
281
+ this.lastRx = nowMs();
282
+ }
283
+ /** @internal */
284
+ retire(s) {
285
+ this.ss.delete(s.sid);
286
+ if (!this.mode.reliable) {
287
+ const now = nowMs();
288
+ let ttl = this.mode.timing.tombstoneMs;
289
+ if (s.deadlineAt !== void 0) ttl = Math.max(ttl, s.deadlineAt - now);
290
+ const tb = {
291
+ expireAt: now + ttl,
292
+ abort: s.abortFrame,
293
+ retxAt: 0,
294
+ ivalMs: 0
295
+ };
296
+ if (tb.abort !== void 0) {
297
+ tb.ivalMs = this.mode.timing.retransmitMs;
298
+ tb.retxAt = now + tb.ivalMs;
299
+ }
300
+ this.tombs.set(s.sid, tb);
301
+ }
302
+ this.kickSweep();
303
+ }
304
+ clearTombAbort(sid) {
305
+ const tb = this.tombs.get(sid);
306
+ if (tb !== void 0) {
307
+ tb.abort = void 0;
308
+ tb.retxAt = 0;
309
+ }
310
+ }
311
+ async sendReset(f) {
312
+ if (!this.mode.reliable) {
313
+ const sid = f.sid;
314
+ const n = nowMs();
315
+ const last = this.resetAt.get(sid);
316
+ if (last !== void 0) {
317
+ if (n - last < this.mode.timing.retransmitMs) return;
318
+ } else if (this.resetAt.size >= this.limits.maxPendingResets) return;
319
+ this.resetAt.set(sid, n);
320
+ this.kickSweep();
321
+ }
322
+ try {
323
+ await this.tx.handle(resetFor(f));
324
+ } catch {}
325
+ }
326
+ failAll(err) {
327
+ const ss = [...this.ss.values()];
328
+ for (const tb of this.tombs.values()) {
329
+ tb.abort = void 0;
330
+ tb.retxAt = 0;
331
+ }
332
+ for (const s of ss) s.finishLocal(err);
333
+ }
334
+ /** @internal */
335
+ kickSweep() {
336
+ if (this.mode.reliable) return;
337
+ this.sw.kick(this.mode.timing.tickMs, () => this.sweep(nowMs()), () => this.hasWork());
338
+ }
339
+ hasWork() {
340
+ return this.ss.size > 0 || this.tombs.size > 0 || this.resetAt.size > 0;
341
+ }
342
+ sweep(now) {
343
+ const t = this.mode.timing;
344
+ const streams = [...this.ss.values()];
345
+ const tombRetx = [];
346
+ for (const [sid, tb] of this.tombs) {
347
+ if (now > tb.expireAt) {
348
+ this.tombs.delete(sid);
349
+ continue;
350
+ }
351
+ if (tb.abort !== void 0 && tb.retxAt !== 0 && now > tb.retxAt) {
352
+ tombRetx.push(tb.abort);
353
+ tb.ivalMs = Math.min(tb.ivalMs * 2, t.probeMs);
354
+ tb.retxAt = now + tb.ivalMs;
355
+ }
356
+ }
357
+ for (const [sid, at] of this.resetAt) if (now - at > t.tombstoneMs) this.resetAt.delete(sid);
358
+ if (this.ss.size > 0) {
359
+ if (now - this.lastRx >= t.livenessMs) {
360
+ this.failAll(statusError(14, "peer lost"));
361
+ return;
362
+ }
363
+ if (now - this.lastTx >= t.probeMs && now - this.lastPing >= t.probeMs) {
364
+ this.lastPing = now;
365
+ this.lastTx = now;
366
+ Promise.resolve(this.tx.handle(frame({
367
+ epoch: this.epoch,
368
+ flags: 8
369
+ }))).catch(noop);
370
+ }
371
+ }
372
+ for (const s of streams) {
373
+ for (const f of s.sweepRetx(now, t.probeMs)) s.transmit(f).catch(noop);
374
+ const p = s.probeDue(now, t.probeMs);
375
+ if (p !== void 0) {
376
+ this.lastTx = now;
377
+ Promise.resolve(this.tx.handle(p)).catch(noop);
378
+ }
379
+ }
380
+ for (const f of tombRetx) {
381
+ this.lastTx = now;
382
+ Promise.resolve(this.tx.handle(f)).catch(noop);
383
+ }
384
+ }
385
+ };
386
+ var ClientStream = class {
387
+ sid;
388
+ conn;
389
+ desc;
390
+ reqCodec;
391
+ resCodec;
392
+ codecName;
393
+ openHdr;
394
+ ci;
395
+ flowTx = new FlowSender();
396
+ flowRx = new FlowReceiver();
397
+ rxSize;
398
+ callerSignal;
399
+ signalDispose = noop;
400
+ deadlineTimer;
401
+ deadlineFired = false;
402
+ timeoutCause;
403
+ /** @internal */
404
+ deadlineAt;
405
+ txSeq = new TxSeq();
406
+ txOpened = false;
407
+ txClosed = false;
408
+ /** @internal */
409
+ abortFrame;
410
+ retxOpen;
411
+ retxClose;
412
+ retxAt = 0;
413
+ retxIval = 0;
414
+ lastRx;
415
+ lastTx;
416
+ lastProbe = 0;
417
+ rxWin = new RxWindow();
418
+ srvEpoch = 0;
419
+ srvEpochSet = false;
420
+ rxq;
421
+ rxPolicy;
422
+ rxDropped = 0;
423
+ rxHeader;
424
+ trailerMd;
425
+ hdrLatch = new Latch();
426
+ done = new Latch();
427
+ term;
428
+ termErr;
429
+ termPayloadDelivered = false;
430
+ /** @internal */
431
+ constructor(conn, desc, sid, opts, ci, timeoutCause) {
432
+ this.conn = conn;
433
+ this.desc = desc;
434
+ this.sid = sid;
435
+ this.ci = ci;
436
+ const forced = opts.codec;
437
+ this.reqCodec = forced?.request ?? desc.request;
438
+ this.resCodec = forced?.response ?? desc.response;
439
+ this.codecName = forced?.name ?? "";
440
+ this.openHdr = opts.metadata;
441
+ this.callerSignal = opts.signal;
442
+ this.timeoutCause = timeoutCause;
443
+ if (opts.timeoutMs !== void 0) this.deadlineAt = nowMs() + opts.timeoutMs;
444
+ const cfg = conn.streamRxCfg;
445
+ this.rxSize = cfg.size;
446
+ this.rxq = new FrameQueue(cfg.size);
447
+ this.rxPolicy = cfg.policy;
448
+ this.rxWin.strict = conn.isReliable;
449
+ if (conn.isReliable) {
450
+ this.flowRx.enable(cfg.size);
451
+ this.flowTx.assume(32);
452
+ }
453
+ const n = nowMs();
454
+ this.lastRx = n;
455
+ this.lastTx = n;
456
+ }
457
+ /** @internal */
458
+ arm(opts) {
459
+ if (opts.timeoutMs !== void 0) {
460
+ if (opts.timeoutMs <= 0) {
461
+ this.deadlineFired = true;
462
+ this.abortFromCtx();
463
+ return;
464
+ }
465
+ const t = setTimeout(() => {
466
+ this.deadlineFired = true;
467
+ this.abortFromCtx();
468
+ }, opts.timeoutMs);
469
+ unrefTimer(t);
470
+ this.deadlineTimer = t;
471
+ }
472
+ if (this.callerSignal !== void 0) {
473
+ if (this.callerSignal.aborted) {
474
+ this.abortFromCtx();
475
+ return;
476
+ }
477
+ this.signalDispose = abortListener(this.callerSignal, () => this.abortFromCtx());
478
+ }
479
+ }
480
+ /** @internal */
481
+ async handleRx(f, ctx) {
482
+ if (this.done.tripped) return;
483
+ if (hasUnknownFlags(f) || !legalShape(shapeOf(f))) {
484
+ const err = statusError(13, `drpc: frame carries unsupported flags 0x${(f.flags >>> 0).toString(16)}`);
485
+ this.sendAbort(13);
486
+ this.finishLocal(err);
487
+ return;
488
+ }
489
+ if (this.srvEpochSet && f.epoch !== this.srvEpoch) {
490
+ this.rxDropped++;
491
+ return;
492
+ }
493
+ if (shapeOf(f) === 16) {
494
+ if (this.conn.isReliable) this.flowTx.grant(f.window);
495
+ return;
496
+ }
497
+ const v = this.rxWin.check(f.seq);
498
+ if (v === 0 && !this.srvEpochSet) {
499
+ this.srvEpoch = f.epoch;
500
+ this.srvEpochSet = true;
501
+ }
502
+ switch (v) {
503
+ case 1:
504
+ this.noteValidatedRx();
505
+ return;
506
+ case 2: return;
507
+ case 3: {
508
+ const err = statusError(15, "seq window overrun: >W_fwd consecutive frames lost");
509
+ this.sendAbort(15);
510
+ this.finishLocal(err);
511
+ return;
512
+ }
513
+ case 4: {
514
+ const err = statusError(13, "reliable transport lost or reordered a frame");
515
+ this.sendAbort(13);
516
+ this.finishLocal(err);
517
+ return;
518
+ }
519
+ case 0: break;
520
+ }
521
+ this.noteValidatedRx();
522
+ if (this.conn.isReliable) this.flowTx.observe(f.window);
523
+ if (isTerminal(f)) {
524
+ this.latchHeader(f);
525
+ if (f.trailer !== void 0) this.trailerMd = f.trailer;
526
+ this.finishTerm(f);
527
+ } else if (isHeaderFrame(f)) this.latchHeader(f);
528
+ else if (isData(f)) {
529
+ if (!this.desc.serverStreams) {
530
+ this.rxDropped++;
531
+ return;
532
+ }
533
+ this.latchHeader(f);
534
+ if (this.conn.isReliable) {
535
+ if (this.flowRx.active) {
536
+ if (!this.rxq.tryPut(f)) {
537
+ const err = statusError(13, "drpc: peer exceeded the advertised flow-control window");
538
+ this.sendAbort(13);
539
+ this.finishLocal(err);
540
+ }
541
+ } else if (!await this.rxq.putBlocking(f, this.done, ctx.signal)) {
542
+ this.rxDropped++;
543
+ this.finishLocal(statusError(14, "transport closed during delivery"));
544
+ }
545
+ } else this.rxq.putDrop(f, this.rxPolicy);
546
+ } else this.rxDropped++;
547
+ }
548
+ grantWindow(n) {
549
+ if (this.done.tripped) return;
550
+ const g = this.flowRx.consumed(n);
551
+ if (g === 0) return;
552
+ const f = frame({
553
+ epoch: this.conn.epoch,
554
+ sid: this.sid,
555
+ flags: 16,
556
+ window: g
557
+ });
558
+ this.transmit(f).catch(noop);
559
+ }
560
+ async recvInto(f) {
561
+ let payload;
562
+ try {
563
+ payload = f.payload ?? EMPTY;
564
+ if (isCompressed(f)) payload = await decompressPayload(this.ci.compressor, payload, this.ci.maxRecv);
565
+ checkRecvSize(payload.length, this.ci.maxRecv);
566
+ } catch (e) {
567
+ const err = toStatusError(e);
568
+ this.sendAbort(8);
569
+ this.finishLocal(err);
570
+ throw err;
571
+ }
572
+ return this.resCodec.unmarshal(payload);
573
+ }
574
+ latchHeader(f) {
575
+ if (f.header === void 0) return;
576
+ if (this.rxHeader === void 0) this.rxHeader = f.header;
577
+ this.hdrLatch.trip();
578
+ }
579
+ noteValidatedRx() {
580
+ this.lastRx = nowMs();
581
+ this.conn.noteRx();
582
+ this.retxOpen = void 0;
583
+ }
584
+ openFrame() {
585
+ this.txOpened = true;
586
+ const f = frame({
587
+ epoch: this.conn.epoch,
588
+ sid: this.sid,
589
+ seq: this.txSeq.next(),
590
+ flags: 1,
591
+ method: this.desc.path
592
+ });
593
+ if (this.codecName !== "") f.codec = this.codecName;
594
+ if (this.ci.compressorName !== "") f.compressor = this.ci.compressorName;
595
+ if (this.conn.isReliable) f.window = this.rxSize;
596
+ if (this.openHdr !== void 0) f.header = this.openHdr;
597
+ if (this.deadlineAt !== void 0) f.timeoutMs = this.deadlineAt - nowMs();
598
+ if (!this.conn.isReliable) {
599
+ this.retxOpen = f;
600
+ this.scheduleRetx();
601
+ }
602
+ return f;
603
+ }
604
+ nextFrame() {
605
+ return frame({
606
+ epoch: this.conn.epoch,
607
+ sid: this.sid,
608
+ seq: this.txSeq.next()
609
+ });
610
+ }
611
+ /** @internal */
612
+ async sendOpen() {
613
+ if (this.txOpened || this.txClosed) return;
614
+ const f = this.openFrame();
615
+ try {
616
+ await this.transmit(f);
617
+ } catch (e) {
618
+ this.finishLocal(toStatusError(e));
619
+ }
620
+ }
621
+ /** @internal */
622
+ async sendRaw(m) {
623
+ if (this.done.tripped) throw new EndOfStreamError();
624
+ if (this.txClosed) {
625
+ if (this.abortFrame !== void 0) throw new EndOfStreamError();
626
+ throw statusError(13, "send called after closeSend");
627
+ }
628
+ const raw = this.reqCodec.marshal(m);
629
+ const opening = !this.txOpened;
630
+ if (!opening && !this.flowTx.tryAcquire()) switch (await this.flowTx.acquire(this.done, this.ci.stallMs, this.callerSignal)) {
631
+ case "ok": break;
632
+ case "ended": throw new EndOfStreamError();
633
+ case "aborted": throw this.callerSignal === void 0 ? statusError(1, "call cancelled") : abortCause(this.callerSignal);
634
+ case "stalled": throw statusError(14, `drpc: flow-control stall: the peer granted no credit for ${this.ci.stallMs}ms`);
635
+ }
636
+ let enc = rawPayload(raw);
637
+ if (this.ci.compressor !== void 0) try {
638
+ enc = await compressPayload(this.ci.compressor, raw);
639
+ } catch (e) {
640
+ if (!opening) this.flowTx.undo();
641
+ throw e;
642
+ }
643
+ try {
644
+ checkSendSize(enc.bytes.length, this.ci.maxSend);
645
+ } catch (e) {
646
+ if (!opening) this.flowTx.undo();
647
+ throw e;
648
+ }
649
+ if (this.done.tripped) throw new EndOfStreamError();
650
+ if (!opening && this.txClosed) throw new EndOfStreamError();
651
+ let f;
652
+ if (!this.txOpened) {
653
+ f = this.openFrame();
654
+ if (!this.desc.clientStreams) {
655
+ f.flags |= 2;
656
+ this.txClosed = true;
657
+ }
658
+ } else f = this.nextFrame();
659
+ f.payload = enc.bytes;
660
+ if (enc.compressed) f.flags |= 32;
661
+ try {
662
+ await this.transmit(f);
663
+ } catch (e) {
664
+ this.undoRefused(f, e);
665
+ throw e;
666
+ }
667
+ }
668
+ undoRefused(f, err) {
669
+ if (!isMessageTooLarge(err)) return;
670
+ this.txSeq.undo(f.seq);
671
+ if ((f.flags & 1) !== 0) {
672
+ this.txOpened = false;
673
+ this.txClosed = false;
674
+ this.retxOpen = void 0;
675
+ this.retxAt = 0;
676
+ }
677
+ if (isData(f)) this.flowTx.undo();
678
+ }
679
+ async send(m) {
680
+ let err;
681
+ try {
682
+ await this.sendRaw(m);
683
+ } catch (e) {
684
+ err = e;
685
+ if (!(e instanceof EndOfStreamError)) {
686
+ err = toStatusError(e);
687
+ this.sendAbort(1);
688
+ this.finishLocal(err);
689
+ }
690
+ }
691
+ if (!this.desc.clientStreams) return;
692
+ if (err !== void 0) throw err;
693
+ }
694
+ closeSend() {
695
+ if (!this.desc.clientStreams) return;
696
+ if (this.txClosed || this.done.tripped) return;
697
+ this.txClosed = true;
698
+ const f = this.nextFrame();
699
+ f.flags = 2;
700
+ if (!this.conn.isReliable) {
701
+ this.retxClose = f;
702
+ this.scheduleRetx();
703
+ }
704
+ this.transmit(f).catch(noop);
705
+ }
706
+ async recv() {
707
+ for (;;) {
708
+ const f = this.rxq.tryTake();
709
+ if (f !== void 0) return this.recvBuffered(f);
710
+ if (this.done.tripped) return this.terminalRecv();
711
+ await Promise.race([this.rxq.readable(), this.done.wait()]);
712
+ }
713
+ }
714
+ async recvBuffered(f) {
715
+ const m = await this.recvInto(f);
716
+ this.grantWindow(1);
717
+ return m;
718
+ }
719
+ async terminalRecv() {
720
+ if (this.termErr !== void 0) throw this.termErr;
721
+ const f = this.term;
722
+ if ((f.code ?? 0) !== 0) throw terminalStatus(f);
723
+ if (f.payload !== void 0 && !this.termPayloadDelivered) {
724
+ this.termPayloadDelivered = true;
725
+ return this.recvInto(f);
726
+ }
727
+ }
728
+ async *[Symbol.asyncIterator]() {
729
+ for (;;) {
730
+ const m = await this.recv();
731
+ if (m === void 0) return;
732
+ yield m;
733
+ }
734
+ }
735
+ async header() {
736
+ await Promise.race([this.hdrLatch.wait(), this.done.wait()]);
737
+ return this.rxHeader;
738
+ }
739
+ trailer() {
740
+ return this.trailerMd;
741
+ }
742
+ latchedHeader() {
743
+ return this.rxHeader;
744
+ }
745
+ cancel() {
746
+ if (this.done.tripped) return;
747
+ this.sendAbort(1);
748
+ this.finishLocal(statusError(1, "call cancelled"));
749
+ }
750
+ abortFromCtx() {
751
+ if (this.done.tripped) return;
752
+ let cause;
753
+ if (this.deadlineFired) cause = this.timeoutCause ?? statusError(4, "deadline exceeded");
754
+ else if (this.callerSignal !== void 0 && this.callerSignal.aborted) cause = abortCause(this.callerSignal);
755
+ else cause = statusError(1, "call cancelled");
756
+ const code = cause.code === 4 ? 4 : 1;
757
+ this.sendAbort(code);
758
+ this.finishLocal(cause);
759
+ }
760
+ sendAbort(code) {
761
+ if (!this.txOpened) {
762
+ this.txClosed = true;
763
+ return;
764
+ }
765
+ if (this.abortFrame !== void 0) return;
766
+ this.txClosed = true;
767
+ const f = this.nextFrame();
768
+ f.flags = 2;
769
+ f.code = code;
770
+ this.abortFrame = f;
771
+ this.transmit(f).catch(noop);
772
+ }
773
+ finishTerm(f) {
774
+ if (this.done.tripped) return;
775
+ this.term = f;
776
+ this.done.trip();
777
+ this.release();
778
+ }
779
+ /** @internal */
780
+ finishLocal(err) {
781
+ if (this.done.tripped) return;
782
+ this.termErr = err;
783
+ this.done.trip();
784
+ this.release();
785
+ }
786
+ /** @internal */
787
+ abandon() {
788
+ if (this.done.tripped) return;
789
+ if (this.deadlineFired || this.callerSignal !== void 0 && this.callerSignal.aborted) {
790
+ this.abortFromCtx();
791
+ return;
792
+ }
793
+ this.sendAbort(1);
794
+ this.finishLocal(statusError(1, "call abandoned"));
795
+ }
796
+ /** @internal */
797
+ finishReset() {
798
+ if (this.done.tripped) return;
799
+ this.sendAbort(1);
800
+ this.finishLocal(statusError(14, "call reset by peer"));
801
+ }
802
+ release() {
803
+ this.flowTx.release();
804
+ if (this.deadlineTimer !== void 0) {
805
+ clearTimeout(this.deadlineTimer);
806
+ this.deadlineTimer = void 0;
807
+ }
808
+ this.signalDispose();
809
+ this.conn.retire(this);
810
+ this.hdrLatch.trip();
811
+ }
812
+ /** @internal */
813
+ transmit(f) {
814
+ this.lastTx = nowMs();
815
+ return this.conn.transmit(f);
816
+ }
817
+ scheduleRetx() {
818
+ if (this.conn.isReliable) return;
819
+ this.retxIval = this.conn.timing.retransmitMs;
820
+ this.retxAt = nowMs() + this.retxIval;
821
+ this.conn.kickSweep();
822
+ }
823
+ /** @internal */
824
+ sweepRetx(now, capMs) {
825
+ if (this.retxAt === 0 || now < this.retxAt) return [];
826
+ const out = [];
827
+ if (this.retxOpen !== void 0) out.push(this.retxOpen);
828
+ if (this.retxClose !== void 0) out.push(this.retxClose);
829
+ if (out.length === 0) {
830
+ this.retxAt = 0;
831
+ return [];
832
+ }
833
+ this.retxIval = Math.min(this.retxIval * 2, capMs);
834
+ this.retxAt = now + this.retxIval;
835
+ return out;
836
+ }
837
+ /** @internal */
838
+ probeDue(now, probeMs) {
839
+ if (now - this.lastRx < probeMs || now - this.lastTx < probeMs || now - this.lastProbe < probeMs) return;
840
+ this.lastProbe = now;
841
+ return frame({
842
+ epoch: this.conn.epoch,
843
+ sid: this.sid,
844
+ flags: 8
845
+ });
846
+ }
847
+ };
848
+ //#endregion
849
+ export { resolveTiming as a, RxWindow as c, statusDetails as i, TxSeq as l, Conn as n, K_LOUD as o, EndOfStreamError as r, RxVerdict as s, ClientStream as t, W_FWD as u };