@lesomnus/grpc-dgram 0.0.1 → 0.1.0
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/CHANGELOG.md +43 -0
- package/README.md +61 -21
- package/dist/{conn-DOmx4nbt.mjs → conn-CmYPHTPR.mjs} +327 -23
- package/dist/conn-Dc57BC-h.d.mts +775 -0
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +238 -48
- package/dist/{protocol-K4Zy8MuQ.mjs → protocol-CTxSUZQF.mjs} +60 -5
- package/dist/transport/connect.d.mts +1 -1
- package/dist/transport/node-udp.d.mts +5 -4
- package/dist/transport/node-udp.mjs +16 -10
- package/dist/transport/port.d.mts +5 -4
- package/dist/transport/port.mjs +15 -8
- package/dist/transport/webrtc.d.mts +5 -4
- package/dist/transport/webrtc.mjs +13 -7
- package/dist/transport/websocket.d.mts +5 -4
- package/dist/transport/websocket.mjs +14 -8
- package/dist/transport/webtransport.d.mts +53 -0
- package/dist/transport/webtransport.mjs +144 -0
- package/dist/wasm/worker.mjs +20 -5
- package/dist/wasm.d.mts +7 -3
- package/dist/wasm.mjs +21 -9
- package/dist/{wire-BR8KiyRg.mjs → wire-DqHx0oUs.mjs} +211 -39
- package/package.json +6 -3
- package/dist/conn-DTWG9vIx.d.mts +0 -331
- package/dist/server-xIr1mwqq.d.mts +0 -112
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as sizeOr, A as DEFAULT_MAX_SEND_MSG_SIZE, C as isTerminal, E as resetFor, F as Latch, G as compressPayload, H as acquireBoth, I as PeerFlowRx, J as nonzeroEpoch, K as decompressPayload, L as Sweeper, M as FlowReceiver, N as FlowSender, O as shapeOf, P as FrameQueue, Q as reliableRxSize, S as isReset, T as legalShape, U as checkRecvSize, V as abortListener, W as checkSendSize, X as nowMs, Y as noop, Z as rawPayload, _ as isData, et as tryAcquireBoth, f as frame, g as isCompressed, k as DEFAULT_MAX_RECV_MSG_SIZE, m as hasUnknownFlags, mt as resolveRxConfig, nt as hasConnAttacher, p as frameStatus, pt as resolveLimits, q as getCompressor, rt as hasTransportInfo, tt as unrefTimer, ut as validateMetadata, x as isPing, y as isHeaderFrame, z as W_CONN } from "./wire-DqHx0oUs.mjs";
|
|
2
2
|
import { a as isMessageTooLarge, i as abortCause, o as statusError, r as StatusError, s as toStatusError } from "./status-DZwMDWIn.mjs";
|
|
3
|
+
//#region src/interceptor.ts
|
|
4
|
+
/** @internal */
|
|
5
|
+
function chain1(is) {
|
|
6
|
+
if (is === void 0 || is.length === 0) return void 0;
|
|
7
|
+
const snapshot = [...is];
|
|
8
|
+
return (x, last) => snapshot.reduceRight((next, h) => (x2) => h(x2, next), last)(x);
|
|
9
|
+
}
|
|
10
|
+
/** @internal */
|
|
11
|
+
function chain2(is) {
|
|
12
|
+
if (is === void 0 || is.length === 0) return void 0;
|
|
13
|
+
const snapshot = [...is];
|
|
14
|
+
return (x, y, last) => snapshot.reduceRight((next, h) => (x2, y2) => h(x2, y2, next), last)(x, y);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
3
17
|
//#region src/seq.ts
|
|
4
18
|
const W_FWD = 4096;
|
|
5
19
|
const K_LOUD = 3;
|
|
@@ -26,6 +40,12 @@ var RxWindow = class {
|
|
|
26
40
|
strict = false;
|
|
27
41
|
beyondN = 0;
|
|
28
42
|
beyondLast = 0;
|
|
43
|
+
gap = 0;
|
|
44
|
+
takeGap() {
|
|
45
|
+
const g = this.gap;
|
|
46
|
+
this.gap = 0;
|
|
47
|
+
return g;
|
|
48
|
+
}
|
|
29
49
|
check(seq) {
|
|
30
50
|
if (seq === 0) return 2;
|
|
31
51
|
if (this.strict) {
|
|
@@ -38,6 +58,7 @@ var RxWindow = class {
|
|
|
38
58
|
const d = seq - this.l >>> 0;
|
|
39
59
|
if (d === 0 || d >= 2147483648) return 1;
|
|
40
60
|
if (d <= 4096) {
|
|
61
|
+
this.gap = d - 1;
|
|
41
62
|
this.l = seq;
|
|
42
63
|
this.beyondN = 0;
|
|
43
64
|
return 0;
|
|
@@ -50,6 +71,89 @@ var RxWindow = class {
|
|
|
50
71
|
}
|
|
51
72
|
};
|
|
52
73
|
//#endregion
|
|
74
|
+
//#region src/stats.ts
|
|
75
|
+
var Counters = class {
|
|
76
|
+
n = {
|
|
77
|
+
skipped: 0,
|
|
78
|
+
dropped: 0,
|
|
79
|
+
offShape: 0,
|
|
80
|
+
resetSent: 0,
|
|
81
|
+
resetReceived: 0,
|
|
82
|
+
retransmit: 0,
|
|
83
|
+
probeSent: 0,
|
|
84
|
+
keepaliveSent: 0,
|
|
85
|
+
livenessExpired: 0,
|
|
86
|
+
tombstoneReplay: 0,
|
|
87
|
+
dataLoss: 0,
|
|
88
|
+
flowStall: 0,
|
|
89
|
+
flowResume: 0,
|
|
90
|
+
peerFlowStall: 0,
|
|
91
|
+
peerFlowResume: 0
|
|
92
|
+
};
|
|
93
|
+
observe = (ev) => {
|
|
94
|
+
const n = Math.max(ev.count, 1);
|
|
95
|
+
switch (ev.kind) {
|
|
96
|
+
case "skipped":
|
|
97
|
+
this.n.skipped += n;
|
|
98
|
+
break;
|
|
99
|
+
case "dropped":
|
|
100
|
+
this.n.dropped += n;
|
|
101
|
+
break;
|
|
102
|
+
case "off-shape":
|
|
103
|
+
this.n.offShape += n;
|
|
104
|
+
break;
|
|
105
|
+
case "reset-sent":
|
|
106
|
+
this.n.resetSent++;
|
|
107
|
+
break;
|
|
108
|
+
case "reset-received":
|
|
109
|
+
this.n.resetReceived++;
|
|
110
|
+
break;
|
|
111
|
+
case "retransmit":
|
|
112
|
+
this.n.retransmit++;
|
|
113
|
+
break;
|
|
114
|
+
case "probe-sent":
|
|
115
|
+
this.n.probeSent++;
|
|
116
|
+
break;
|
|
117
|
+
case "keepalive-sent":
|
|
118
|
+
this.n.keepaliveSent++;
|
|
119
|
+
break;
|
|
120
|
+
case "liveness-expired":
|
|
121
|
+
this.n.livenessExpired++;
|
|
122
|
+
break;
|
|
123
|
+
case "tombstone-replay":
|
|
124
|
+
this.n.tombstoneReplay++;
|
|
125
|
+
break;
|
|
126
|
+
case "data-loss":
|
|
127
|
+
this.n.dataLoss++;
|
|
128
|
+
break;
|
|
129
|
+
case "flow-stall":
|
|
130
|
+
this.n.flowStall++;
|
|
131
|
+
break;
|
|
132
|
+
case "flow-resume":
|
|
133
|
+
this.n.flowResume++;
|
|
134
|
+
break;
|
|
135
|
+
case "peer-flow-stall":
|
|
136
|
+
this.n.peerFlowStall++;
|
|
137
|
+
break;
|
|
138
|
+
case "peer-flow-resume":
|
|
139
|
+
this.n.peerFlowResume++;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
snapshot() {
|
|
144
|
+
return { ...this.n };
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
function statsSink(opt) {
|
|
148
|
+
if (opt === void 0) return [];
|
|
149
|
+
return typeof opt === "function" ? [opt] : [...opt];
|
|
150
|
+
}
|
|
151
|
+
function emit(sink, ev) {
|
|
152
|
+
for (const h of sink) try {
|
|
153
|
+
h(ev);
|
|
154
|
+
} catch {}
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
53
157
|
//#region src/timing.ts
|
|
54
158
|
function resolveTiming(t = {}) {
|
|
55
159
|
const callMs = t.callMs ?? 5e3;
|
|
@@ -98,16 +202,23 @@ var Conn = class {
|
|
|
98
202
|
maxRecv;
|
|
99
203
|
maxSend;
|
|
100
204
|
stallMs;
|
|
205
|
+
/** @internal */ pstats;
|
|
101
206
|
ss = /* @__PURE__ */ new Map();
|
|
102
207
|
tombs = /* @__PURE__ */ new Map();
|
|
103
208
|
resetAt = /* @__PURE__ */ new Map();
|
|
104
209
|
sidNext = 0;
|
|
105
210
|
exhausted = false;
|
|
106
211
|
closed = false;
|
|
212
|
+
/** @internal */ connTx = new FlowSender();
|
|
213
|
+
/** @internal */ connRx = new PeerFlowRx();
|
|
214
|
+
srvEpoch = 0;
|
|
215
|
+
srvEpochSet = false;
|
|
107
216
|
lastRx = 0;
|
|
108
217
|
lastTx = 0;
|
|
109
218
|
lastPing = 0;
|
|
110
219
|
sw = new Sweeper();
|
|
220
|
+
unaryInt;
|
|
221
|
+
streamInt;
|
|
111
222
|
constructor(tx, opts = {}) {
|
|
112
223
|
this.epoch = nonzeroEpoch();
|
|
113
224
|
this.tx = tx;
|
|
@@ -121,21 +232,38 @@ var Conn = class {
|
|
|
121
232
|
policy: rx.policy
|
|
122
233
|
};
|
|
123
234
|
this.limits = resolveLimits(opts.limits);
|
|
235
|
+
if (this.mode.reliable) {
|
|
236
|
+
this.connTx.assume(W_CONN);
|
|
237
|
+
this.connRx.enable(this.limits.maxPeerWindow, 0);
|
|
238
|
+
}
|
|
124
239
|
this.defaults = opts.defaultCallOptions ?? {};
|
|
125
240
|
this.compressor = opts.compressor ?? "";
|
|
126
241
|
this.compressors = new Map(Object.entries(opts.compressors ?? {}));
|
|
127
242
|
this.maxRecv = sizeOr(opts.maxRecvMsgSize, DEFAULT_MAX_RECV_MSG_SIZE);
|
|
128
243
|
this.maxSend = sizeOr(opts.maxSendMsgSize, DEFAULT_MAX_SEND_MSG_SIZE);
|
|
129
244
|
this.stallMs = opts.timing?.stallMs ?? 3e4;
|
|
245
|
+
this.pstats = statsSink(opts.protocolStats);
|
|
246
|
+
this.unaryInt = chain2(opts.unaryInterceptors);
|
|
247
|
+
this.streamInt = chain1(opts.streamInterceptors);
|
|
130
248
|
if (hasConnAttacher(tx)) tx.attachConn(this);
|
|
131
249
|
}
|
|
132
250
|
get reliable() {
|
|
133
251
|
return this.mode.reliable;
|
|
134
252
|
}
|
|
253
|
+
protoEvent(kind, sid = 0) {
|
|
254
|
+
if (this.pstats.length === 0) return;
|
|
255
|
+
emit(this.pstats, {
|
|
256
|
+
kind,
|
|
257
|
+
sid,
|
|
258
|
+
method: "",
|
|
259
|
+
count: 0
|
|
260
|
+
});
|
|
261
|
+
}
|
|
135
262
|
async handle(f, ctx = {}) {
|
|
136
263
|
const sid = f.sid;
|
|
137
264
|
if (isReset(f)) {
|
|
138
265
|
if (f.epoch !== this.epoch) return;
|
|
266
|
+
this.protoEvent("reset-received", sid);
|
|
139
267
|
const s = this.ss.get(sid);
|
|
140
268
|
if (s !== void 0) {
|
|
141
269
|
s.finishReset();
|
|
@@ -145,10 +273,14 @@ var Conn = class {
|
|
|
145
273
|
return;
|
|
146
274
|
}
|
|
147
275
|
if (f.peerEpoch !== this.epoch) {
|
|
148
|
-
if (isPing(f)
|
|
276
|
+
if (sid === 0 && (isPing(f) || shapeOf(f) === 16)) return;
|
|
149
277
|
await this.sendReset(f);
|
|
150
278
|
return;
|
|
151
279
|
}
|
|
280
|
+
if (sid === 0 && shapeOf(f) === 16) {
|
|
281
|
+
if (this.mode.reliable && this.serverEpochIs(f.epoch)) this.connTx.grant(f.window);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
152
284
|
if (shapeOf(f) === 16) {
|
|
153
285
|
const s = this.ss.get(sid);
|
|
154
286
|
if (s !== void 0) await s.handleRx(f, ctx);
|
|
@@ -166,6 +298,9 @@ var Conn = class {
|
|
|
166
298
|
await s.handleRx(f, ctx);
|
|
167
299
|
return;
|
|
168
300
|
}
|
|
301
|
+
this.lockServerEpoch(f.epoch);
|
|
302
|
+
this.observeAdvertisement(f);
|
|
303
|
+
this.creditUnbuffered(f);
|
|
169
304
|
if (this.tombs.get(sid) !== void 0) {
|
|
170
305
|
this.lastRx = nowMs();
|
|
171
306
|
if (isTerminal(f)) this.clearTombAbort(sid);
|
|
@@ -177,6 +312,7 @@ var Conn = class {
|
|
|
177
312
|
const st = err === void 0 || err === null ? statusError(14, "transport closed") : statusError(14, `transport closed: ${err instanceof Error ? err.message : String(err)}`);
|
|
178
313
|
this.closed = true;
|
|
179
314
|
this.failAll(st);
|
|
315
|
+
this.connTx.release();
|
|
180
316
|
this.sw.stop();
|
|
181
317
|
const cl = this.tx.close;
|
|
182
318
|
if (typeof cl === "function") cl.call(this.tx);
|
|
@@ -191,6 +327,28 @@ var Conn = class {
|
|
|
191
327
|
merged.timeoutMs = this.mode.timing.callMs;
|
|
192
328
|
timeoutCause = statusError(4, "drpc: default call timeout");
|
|
193
329
|
}
|
|
330
|
+
const call = {
|
|
331
|
+
desc,
|
|
332
|
+
opts: merged
|
|
333
|
+
};
|
|
334
|
+
const budget = merged.timeoutMs;
|
|
335
|
+
const deadlineAt = budget === void 0 ? void 0 : nowMs() + budget;
|
|
336
|
+
const last = (r, c) => {
|
|
337
|
+
if (deadlineAt === void 0 || c.opts.timeoutMs !== budget) return this.doInvoke(r, c, void 0);
|
|
338
|
+
return this.doInvoke(r, {
|
|
339
|
+
desc: c.desc,
|
|
340
|
+
opts: {
|
|
341
|
+
...c.opts,
|
|
342
|
+
timeoutMs: deadlineAt - nowMs()
|
|
343
|
+
}
|
|
344
|
+
}, timeoutCause);
|
|
345
|
+
};
|
|
346
|
+
const out = this.unaryInt === void 0 ? await last(req, call) : await this.unaryInt(req, call, last);
|
|
347
|
+
if (out === void 0) throw statusError(13, "drpc: the interceptor chain resolved to no response");
|
|
348
|
+
return out;
|
|
349
|
+
}
|
|
350
|
+
async doInvoke(req, call, timeoutCause) {
|
|
351
|
+
const { desc, opts: merged } = call;
|
|
194
352
|
const s = this.createStream(desc, merged, timeoutCause);
|
|
195
353
|
let err;
|
|
196
354
|
let out;
|
|
@@ -215,12 +373,18 @@ var Conn = class {
|
|
|
215
373
|
return out;
|
|
216
374
|
}
|
|
217
375
|
newStream(desc, opts = {}) {
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
376
|
+
const call = {
|
|
377
|
+
desc,
|
|
378
|
+
opts: {
|
|
379
|
+
...this.defaults,
|
|
380
|
+
...opts
|
|
381
|
+
}
|
|
221
382
|
};
|
|
222
|
-
|
|
223
|
-
|
|
383
|
+
return this.streamInt === void 0 ? this.doNewStream(call) : this.streamInt(call, (c) => this.doNewStream(c));
|
|
384
|
+
}
|
|
385
|
+
doNewStream(call) {
|
|
386
|
+
const s = this.createStream(call.desc, call.opts, void 0);
|
|
387
|
+
if (call.desc.clientStreams) s.sendOpen();
|
|
224
388
|
return s;
|
|
225
389
|
}
|
|
226
390
|
resolveCall(opts) {
|
|
@@ -281,6 +445,55 @@ var Conn = class {
|
|
|
281
445
|
this.lastRx = nowMs();
|
|
282
446
|
}
|
|
283
447
|
/** @internal */
|
|
448
|
+
lockServerEpoch(epoch) {
|
|
449
|
+
const changed = this.srvEpochSet && this.srvEpoch !== epoch;
|
|
450
|
+
this.srvEpoch = epoch;
|
|
451
|
+
this.srvEpochSet = true;
|
|
452
|
+
if (!changed || !this.mode.reliable) return;
|
|
453
|
+
this.connTx.reassume(W_CONN);
|
|
454
|
+
this.connRx.renew();
|
|
455
|
+
}
|
|
456
|
+
/** @internal */
|
|
457
|
+
observeAdvertisement(f) {
|
|
458
|
+
if (!this.mode.reliable || !(isHeaderFrame(f) || isTerminal(f))) return;
|
|
459
|
+
this.connTx.observe(f.connWindow);
|
|
460
|
+
}
|
|
461
|
+
/** @internal */
|
|
462
|
+
get locked() {
|
|
463
|
+
return this.srvEpochSet;
|
|
464
|
+
}
|
|
465
|
+
serverEpochIs(epoch) {
|
|
466
|
+
return this.srvEpochSet && this.srvEpoch === epoch;
|
|
467
|
+
}
|
|
468
|
+
serverCurrent(epoch) {
|
|
469
|
+
return !this.srvEpochSet || this.srvEpoch === epoch;
|
|
470
|
+
}
|
|
471
|
+
/** @internal */
|
|
472
|
+
creditUnbuffered(f) {
|
|
473
|
+
if (!this.mode.reliable || !isData(f) || !this.serverCurrent(f.epoch)) return;
|
|
474
|
+
const g = this.connRx.unadmitted(f.epoch, 1);
|
|
475
|
+
if (g > 0) this.grantPeer(g);
|
|
476
|
+
}
|
|
477
|
+
/** @internal */
|
|
478
|
+
retirePeer(n, epoch) {
|
|
479
|
+
if (n === 0) return;
|
|
480
|
+
const g = this.connRx.retire(epoch, n, this.serverCurrent(epoch));
|
|
481
|
+
if (g > 0) this.grantPeer(g);
|
|
482
|
+
}
|
|
483
|
+
/** @internal */
|
|
484
|
+
get peerWindow() {
|
|
485
|
+
return this.limits.maxPeerWindow;
|
|
486
|
+
}
|
|
487
|
+
grantPeer(n) {
|
|
488
|
+
if (this.closed) return;
|
|
489
|
+
const f = frame({
|
|
490
|
+
epoch: this.epoch,
|
|
491
|
+
flags: 16,
|
|
492
|
+
window: n
|
|
493
|
+
});
|
|
494
|
+
Promise.resolve(this.tx.handle(f)).catch(noop);
|
|
495
|
+
}
|
|
496
|
+
/** @internal */
|
|
284
497
|
retire(s) {
|
|
285
498
|
this.ss.delete(s.sid);
|
|
286
499
|
if (!this.mode.reliable) {
|
|
@@ -298,6 +511,7 @@ var Conn = class {
|
|
|
298
511
|
tb.retxAt = now + tb.ivalMs;
|
|
299
512
|
}
|
|
300
513
|
this.tombs.set(s.sid, tb);
|
|
514
|
+
s.dropRetx();
|
|
301
515
|
}
|
|
302
516
|
this.kickSweep();
|
|
303
517
|
}
|
|
@@ -319,6 +533,7 @@ var Conn = class {
|
|
|
319
533
|
this.resetAt.set(sid, n);
|
|
320
534
|
this.kickSweep();
|
|
321
535
|
}
|
|
536
|
+
this.protoEvent("reset-sent", f.sid);
|
|
322
537
|
try {
|
|
323
538
|
await this.tx.handle(resetFor(f));
|
|
324
539
|
} catch {}
|
|
@@ -357,12 +572,14 @@ var Conn = class {
|
|
|
357
572
|
for (const [sid, at] of this.resetAt) if (now - at > t.tombstoneMs) this.resetAt.delete(sid);
|
|
358
573
|
if (this.ss.size > 0) {
|
|
359
574
|
if (now - this.lastRx >= t.livenessMs) {
|
|
575
|
+
this.protoEvent("liveness-expired");
|
|
360
576
|
this.failAll(statusError(14, "peer lost"));
|
|
361
577
|
return;
|
|
362
578
|
}
|
|
363
579
|
if (now - this.lastTx >= t.probeMs && now - this.lastPing >= t.probeMs) {
|
|
364
580
|
this.lastPing = now;
|
|
365
581
|
this.lastTx = now;
|
|
582
|
+
this.protoEvent("keepalive-sent");
|
|
366
583
|
Promise.resolve(this.tx.handle(frame({
|
|
367
584
|
epoch: this.epoch,
|
|
368
585
|
flags: 8
|
|
@@ -370,14 +587,19 @@ var Conn = class {
|
|
|
370
587
|
}
|
|
371
588
|
}
|
|
372
589
|
for (const s of streams) {
|
|
373
|
-
for (const f of s.sweepRetx(now, t.probeMs))
|
|
590
|
+
for (const f of s.sweepRetx(now, t.probeMs)) {
|
|
591
|
+
s.protoEvent("retransmit");
|
|
592
|
+
s.transmit(f).catch(noop);
|
|
593
|
+
}
|
|
374
594
|
const p = s.probeDue(now, t.probeMs);
|
|
375
595
|
if (p !== void 0) {
|
|
596
|
+
s.protoEvent("probe-sent");
|
|
376
597
|
this.lastTx = now;
|
|
377
598
|
Promise.resolve(this.tx.handle(p)).catch(noop);
|
|
378
599
|
}
|
|
379
600
|
}
|
|
380
601
|
for (const f of tombRetx) {
|
|
602
|
+
this.protoEvent("retransmit", f.sid);
|
|
381
603
|
this.lastTx = now;
|
|
382
604
|
Promise.resolve(this.tx.handle(f)).catch(noop);
|
|
383
605
|
}
|
|
@@ -417,6 +639,8 @@ var ClientStream = class {
|
|
|
417
639
|
rxWin = new RxWindow();
|
|
418
640
|
srvEpoch = 0;
|
|
419
641
|
srvEpochSet = false;
|
|
642
|
+
pinned = 0;
|
|
643
|
+
rxReleased = false;
|
|
420
644
|
rxq;
|
|
421
645
|
rxPolicy;
|
|
422
646
|
rxDropped = 0;
|
|
@@ -477,13 +701,43 @@ var ClientStream = class {
|
|
|
477
701
|
this.signalDispose = abortListener(this.callerSignal, () => this.abortFromCtx());
|
|
478
702
|
}
|
|
479
703
|
}
|
|
704
|
+
pin() {
|
|
705
|
+
if (this.rxReleased) return false;
|
|
706
|
+
this.pinned++;
|
|
707
|
+
return true;
|
|
708
|
+
}
|
|
709
|
+
unpin() {
|
|
710
|
+
if (this.pinned === 0) return false;
|
|
711
|
+
this.pinned--;
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
undoCredit() {
|
|
715
|
+
if (this.flowTx.undo() && this.conn.isReliable) this.conn.connTx.undo();
|
|
716
|
+
}
|
|
717
|
+
/** @internal */
|
|
718
|
+
protoEvent(kind, count = 0) {
|
|
719
|
+
const sink = this.conn.pstats;
|
|
720
|
+
if (sink.length === 0) return;
|
|
721
|
+
emit(sink, {
|
|
722
|
+
kind,
|
|
723
|
+
sid: this.sid,
|
|
724
|
+
method: this.desc.path,
|
|
725
|
+
count
|
|
726
|
+
});
|
|
727
|
+
}
|
|
480
728
|
/** @internal */
|
|
481
729
|
async handleRx(f, ctx) {
|
|
482
|
-
if (this.done.tripped)
|
|
730
|
+
if (this.done.tripped) {
|
|
731
|
+
this.conn.lockServerEpoch(f.epoch);
|
|
732
|
+
this.conn.observeAdvertisement(f);
|
|
733
|
+
this.conn.creditUnbuffered(f);
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
483
736
|
if (hasUnknownFlags(f) || !legalShape(shapeOf(f))) {
|
|
484
737
|
const err = statusError(13, `drpc: frame carries unsupported flags 0x${(f.flags >>> 0).toString(16)}`);
|
|
485
738
|
this.sendAbort(13);
|
|
486
739
|
this.finishLocal(err);
|
|
740
|
+
this.conn.creditUnbuffered(f);
|
|
487
741
|
return;
|
|
488
742
|
}
|
|
489
743
|
if (this.srvEpochSet && f.epoch !== this.srvEpoch) {
|
|
@@ -498,13 +752,16 @@ var ClientStream = class {
|
|
|
498
752
|
if (v === 0 && !this.srvEpochSet) {
|
|
499
753
|
this.srvEpoch = f.epoch;
|
|
500
754
|
this.srvEpochSet = true;
|
|
755
|
+
this.conn.lockServerEpoch(f.epoch);
|
|
501
756
|
}
|
|
757
|
+
if (v !== 0) this.conn.creditUnbuffered(f);
|
|
502
758
|
switch (v) {
|
|
503
759
|
case 1:
|
|
504
760
|
this.noteValidatedRx();
|
|
505
761
|
return;
|
|
506
762
|
case 2: return;
|
|
507
763
|
case 3: {
|
|
764
|
+
this.protoEvent("data-loss");
|
|
508
765
|
const err = statusError(15, "seq window overrun: >W_fwd consecutive frames lost");
|
|
509
766
|
this.sendAbort(15);
|
|
510
767
|
this.finishLocal(err);
|
|
@@ -518,8 +775,13 @@ var ClientStream = class {
|
|
|
518
775
|
}
|
|
519
776
|
case 0: break;
|
|
520
777
|
}
|
|
778
|
+
const gap = this.rxWin.takeGap();
|
|
779
|
+
if (gap > 0) this.protoEvent("skipped", gap);
|
|
521
780
|
this.noteValidatedRx();
|
|
522
|
-
if (this.conn.isReliable)
|
|
781
|
+
if (this.conn.isReliable) {
|
|
782
|
+
this.flowTx.observe(f.window);
|
|
783
|
+
this.conn.observeAdvertisement(f);
|
|
784
|
+
}
|
|
523
785
|
if (isTerminal(f)) {
|
|
524
786
|
this.latchHeader(f);
|
|
525
787
|
if (f.trailer !== void 0) this.trailerMd = f.trailer;
|
|
@@ -528,21 +790,36 @@ var ClientStream = class {
|
|
|
528
790
|
else if (isData(f)) {
|
|
529
791
|
if (!this.desc.serverStreams) {
|
|
530
792
|
this.rxDropped++;
|
|
793
|
+
this.protoEvent("off-shape", 1);
|
|
794
|
+
this.conn.creditUnbuffered(f);
|
|
531
795
|
return;
|
|
532
796
|
}
|
|
533
797
|
this.latchHeader(f);
|
|
534
798
|
if (this.conn.isReliable) {
|
|
799
|
+
if (!this.conn.connRx.admit()) {
|
|
800
|
+
const err = statusError(13, "drpc: peer exceeded the connection flow-control window");
|
|
801
|
+
this.sendAbort(13);
|
|
802
|
+
this.finishLocal(err);
|
|
803
|
+
this.conn.creditUnbuffered(f);
|
|
804
|
+
return;
|
|
805
|
+
}
|
|
806
|
+
if (!this.pin()) {
|
|
807
|
+
this.conn.retirePeer(1, f.epoch);
|
|
808
|
+
return;
|
|
809
|
+
}
|
|
535
810
|
if (this.flowRx.active) {
|
|
536
811
|
if (!this.rxq.tryPut(f)) {
|
|
812
|
+
if (this.unpin()) this.conn.retirePeer(1, f.epoch);
|
|
537
813
|
const err = statusError(13, "drpc: peer exceeded the advertised flow-control window");
|
|
538
814
|
this.sendAbort(13);
|
|
539
815
|
this.finishLocal(err);
|
|
540
816
|
}
|
|
541
817
|
} else if (!await this.rxq.putBlocking(f, this.done, ctx.signal)) {
|
|
818
|
+
if (this.unpin()) this.conn.retirePeer(1, f.epoch);
|
|
542
819
|
this.rxDropped++;
|
|
543
820
|
this.finishLocal(statusError(14, "transport closed during delivery"));
|
|
544
821
|
}
|
|
545
|
-
} else this.rxq.putDrop(f, this.rxPolicy);
|
|
822
|
+
} else if (this.rxq.putDrop(f, this.rxPolicy) > 0) this.protoEvent("dropped", 1);
|
|
546
823
|
} else this.rxDropped++;
|
|
547
824
|
}
|
|
548
825
|
grantWindow(n) {
|
|
@@ -592,7 +869,10 @@ var ClientStream = class {
|
|
|
592
869
|
});
|
|
593
870
|
if (this.codecName !== "") f.codec = this.codecName;
|
|
594
871
|
if (this.ci.compressorName !== "") f.compressor = this.ci.compressorName;
|
|
595
|
-
if (this.conn.isReliable)
|
|
872
|
+
if (this.conn.isReliable) {
|
|
873
|
+
f.window = this.rxSize;
|
|
874
|
+
f.connWindow = this.conn.peerWindow;
|
|
875
|
+
}
|
|
596
876
|
if (this.openHdr !== void 0) f.header = this.openHdr;
|
|
597
877
|
if (this.deadlineAt !== void 0) f.timeoutMs = this.deadlineAt - nowMs();
|
|
598
878
|
if (!this.conn.isReliable) {
|
|
@@ -627,27 +907,39 @@ var ClientStream = class {
|
|
|
627
907
|
}
|
|
628
908
|
const raw = this.reqCodec.marshal(m);
|
|
629
909
|
const opening = !this.txOpened;
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
910
|
+
const connTx = this.conn.isReliable ? this.conn.connTx : void 0;
|
|
911
|
+
if (!opening && !tryAcquireBoth(this.flowTx, connTx)) {
|
|
912
|
+
let peer = false;
|
|
913
|
+
switch (await acquireBoth(this.flowTx, connTx, this.done, this.ci.stallMs, this.callerSignal, (p) => {
|
|
914
|
+
peer = p;
|
|
915
|
+
this.protoEvent(p ? "peer-flow-stall" : "flow-stall");
|
|
916
|
+
})) {
|
|
917
|
+
case "ok":
|
|
918
|
+
this.protoEvent(peer ? "peer-flow-resume" : "flow-resume");
|
|
919
|
+
break;
|
|
920
|
+
case "ended": throw new EndOfStreamError();
|
|
921
|
+
case "aborted": throw this.callerSignal === void 0 ? statusError(1, "call cancelled") : abortCause(this.callerSignal);
|
|
922
|
+
case "stalled": throw statusError(14, `drpc: flow-control stall: the peer granted no credit for ${this.ci.stallMs}ms`);
|
|
923
|
+
case "peer-stalled": throw statusError(14, `drpc: flow-control stall: the peer granted no connection credit for ${this.ci.stallMs}ms`);
|
|
924
|
+
}
|
|
635
925
|
}
|
|
636
926
|
let enc = rawPayload(raw);
|
|
637
927
|
if (this.ci.compressor !== void 0) try {
|
|
638
928
|
enc = await compressPayload(this.ci.compressor, raw);
|
|
639
929
|
} catch (e) {
|
|
640
|
-
if (!opening) this.
|
|
930
|
+
if (!opening) this.undoCredit();
|
|
641
931
|
throw e;
|
|
642
932
|
}
|
|
643
933
|
try {
|
|
644
934
|
checkSendSize(enc.bytes.length, this.ci.maxSend);
|
|
645
935
|
} catch (e) {
|
|
646
|
-
if (!opening) this.
|
|
936
|
+
if (!opening) this.undoCredit();
|
|
647
937
|
throw e;
|
|
648
938
|
}
|
|
649
|
-
if (this.done.tripped
|
|
650
|
-
|
|
939
|
+
if (this.done.tripped || !opening && this.txClosed) {
|
|
940
|
+
if (!opening) this.undoCredit();
|
|
941
|
+
throw new EndOfStreamError();
|
|
942
|
+
}
|
|
651
943
|
let f;
|
|
652
944
|
if (!this.txOpened) {
|
|
653
945
|
f = this.openFrame();
|
|
@@ -674,7 +966,7 @@ var ClientStream = class {
|
|
|
674
966
|
this.retxOpen = void 0;
|
|
675
967
|
this.retxAt = 0;
|
|
676
968
|
}
|
|
677
|
-
if (isData(f)) this.
|
|
969
|
+
if (isData(f)) this.undoCredit();
|
|
678
970
|
}
|
|
679
971
|
async send(m) {
|
|
680
972
|
let err;
|
|
@@ -712,6 +1004,7 @@ var ClientStream = class {
|
|
|
712
1004
|
}
|
|
713
1005
|
}
|
|
714
1006
|
async recvBuffered(f) {
|
|
1007
|
+
if (this.unpin()) this.conn.retirePeer(1, f.epoch);
|
|
715
1008
|
const m = await this.recvInto(f);
|
|
716
1009
|
this.grantWindow(1);
|
|
717
1010
|
return m;
|
|
@@ -798,6 +1091,7 @@ var ClientStream = class {
|
|
|
798
1091
|
if (this.done.tripped) return;
|
|
799
1092
|
this.sendAbort(1);
|
|
800
1093
|
this.finishLocal(statusError(14, "call reset by peer"));
|
|
1094
|
+
if (this.conn.isReliable && !this.conn.locked) this.conn.connTx.refund(this.flowTx.drain());
|
|
801
1095
|
}
|
|
802
1096
|
release() {
|
|
803
1097
|
this.flowTx.release();
|
|
@@ -807,6 +1101,10 @@ var ClientStream = class {
|
|
|
807
1101
|
}
|
|
808
1102
|
this.signalDispose();
|
|
809
1103
|
this.conn.retire(this);
|
|
1104
|
+
const pinned = this.pinned;
|
|
1105
|
+
this.pinned = 0;
|
|
1106
|
+
this.rxReleased = true;
|
|
1107
|
+
this.conn.retirePeer(pinned, this.srvEpoch);
|
|
810
1108
|
this.hdrLatch.trip();
|
|
811
1109
|
}
|
|
812
1110
|
/** @internal */
|
|
@@ -821,6 +1119,12 @@ var ClientStream = class {
|
|
|
821
1119
|
this.conn.kickSweep();
|
|
822
1120
|
}
|
|
823
1121
|
/** @internal */
|
|
1122
|
+
dropRetx() {
|
|
1123
|
+
this.retxOpen = void 0;
|
|
1124
|
+
this.retxClose = void 0;
|
|
1125
|
+
this.retxAt = 0;
|
|
1126
|
+
}
|
|
1127
|
+
/** @internal */
|
|
824
1128
|
sweepRetx(now, capMs) {
|
|
825
1129
|
if (this.retxAt === 0 || now < this.retxAt) return [];
|
|
826
1130
|
const out = [];
|
|
@@ -846,4 +1150,4 @@ var ClientStream = class {
|
|
|
846
1150
|
}
|
|
847
1151
|
};
|
|
848
1152
|
//#endregion
|
|
849
|
-
export { resolveTiming as a,
|
|
1153
|
+
export { resolveTiming as a, statsSink as c, RxWindow as d, TxSeq as f, statusDetails as i, K_LOUD as l, chain2 as m, Conn as n, Counters as o, W_FWD as p, EndOfStreamError as r, emit as s, ClientStream as t, RxVerdict as u };
|