@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
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as encodeEnvelope, A as DEFAULT_STALL_MS, At as DropPolicy, B as hasTransportInfo, C as ServerReader, Ct as statusError, D as Compressor, Dt as ProtocolEvent, E as UnaryHandler, Et as Counters, F as EnvelopeSender, G as FlagOpen, H as Any, I as FrameContext, J as FlagWindow, K as FlagPing, L as FrameHandler, M as W_INIT, Mt as RxBufferConfig, N as getCompressor, Nt as Timing, O as DEFAULT_MAX_RECV_MSG_SIZE, Ot as ProtocolEventKind, P as ConnAttacher, Q as decodeFrame, R as TransportInfo, S as ServerOptions, St as isMessageTooLarge, T as ServerWriter, Tt as CounterSnapshot, U as FlagClose, V as unpack, W as FlagCompressed, X as SHAPE_MASK, Y as Frame, Z as decodeEnvelope, _ as UnaryServerInterceptor, _t as shapeOf, a as DetailedStatusError, at as isCompressed, b as Server, bt as StatusError, c as statusDetails, ct as isHeaderFrame, d as StreamServerHandler, dt as isReset, et as encodeFrame, f as StreamServerInterceptor, ft as isTerminal, g as UnaryServerHandler, gt as setFrameError, h as UnaryInvoker, ht as resetFor, i as ConnOptions, it as isClose, j as W_CONN, jt as Limits, k as DEFAULT_MAX_SEND_MSG_SIZE, kt as ProtocolStats, l as ClientCall, lt as isOpen, m as UnaryClientInterceptor, mt as legalShape, n as ClientStream, nt as frameStatus, o as EndOfStreamError, ot as isData, p as Streamer, pt as isWindow, q as FlagReset, r as Conn, rt as hasUnknownFlags, s as FlowTiming, st as isHalfClose, t as CallConfig, tt as frame, u as StreamClientInterceptor, ut as isPing, v as BidiHandler, vt as Code, w as ServerStreamingHandler, wt as toStatusError, x as ServerContext, xt as abortCause, y as ClientStreamingHandler, yt as MessageTooLargeError, z as hasConnAttacher } from "./conn-Dc57BC-h.mjs";
|
|
2
2
|
import { S as validateMetadataPair, _ as decodeBase64, a as MethodDesc, b as metadataJoin, c as ServerStreamingDesc, d as clientStreamingMethod, f as isUnary, g as cloneMetadata, h as Metadata, i as ForcedCodec, l as UnaryDesc, m as unaryMethod, n as CallOptions, o as NamedCodec, p as serverStreamingMethod, r as ClientStreamingDesc, s as PayloadCodec, t as BidiDesc, u as bidiMethod, v as encodeBase64, x as validateMetadata, y as isBinaryKey } from "./desc-BMF2FBqk.mjs";
|
|
3
|
-
import { a as ServerOptions, c as ServerWriter, i as ServerContext, l as UnaryHandler, n as ClientStreamingHandler, o as ServerReader, r as Server, s as ServerStreamingHandler, t as BidiHandler } from "./server-xIr1mwqq.mjs";
|
|
4
3
|
//#region src/seq.d.ts
|
|
5
4
|
declare const W_FWD = 4096;
|
|
6
5
|
declare const K_LOUD = 3;
|
|
@@ -21,7 +20,9 @@ declare class RxWindow {
|
|
|
21
20
|
strict: boolean;
|
|
22
21
|
private beyondN;
|
|
23
22
|
private beyondLast;
|
|
23
|
+
private gap;
|
|
24
|
+
takeGap(): number;
|
|
24
25
|
check(seq: number): RxVerdict;
|
|
25
26
|
}
|
|
26
27
|
//#endregion
|
|
27
|
-
export { type Any, type BidiDesc, type BidiHandler, type CallOptions, ClientStream, type ClientStreamingDesc, type ClientStreamingHandler, Code, type Compressor, Conn, type ConnAttacher, type ConnOptions, DEFAULT_MAX_RECV_MSG_SIZE, DEFAULT_MAX_SEND_MSG_SIZE, DEFAULT_STALL_MS, type DetailedStatusError, DropPolicy, EndOfStreamError, FlagClose, FlagCompressed, FlagOpen, FlagPing, FlagReset, FlagWindow, type FlowTiming, type ForcedCodec, type Frame, type FrameContext, type FrameHandler, K_LOUD, type Limits, MessageTooLargeError, type Metadata, type MethodDesc, type NamedCodec, type PayloadCodec, type RxBufferConfig, RxVerdict, RxWindow, SHAPE_MASK, Server, type ServerContext, type ServerOptions, type ServerReader, type ServerStreamingDesc, type ServerStreamingHandler, type ServerWriter, StatusError, type Timing, type TransportInfo, TxSeq, type UnaryDesc, type UnaryHandler, W_FWD, W_INIT, abortCause, bidiMethod, clientStreamingMethod, cloneMetadata, decodeBase64,
|
|
28
|
+
export { type Any, type BidiDesc, type BidiHandler, type CallConfig, type CallOptions, type ClientCall, ClientStream, type ClientStreamingDesc, type ClientStreamingHandler, Code, type Compressor, Conn, type ConnAttacher, type ConnOptions, type CounterSnapshot, Counters, DEFAULT_MAX_RECV_MSG_SIZE, DEFAULT_MAX_SEND_MSG_SIZE, DEFAULT_STALL_MS, type DetailedStatusError, DropPolicy, EndOfStreamError, type EnvelopeSender, FlagClose, FlagCompressed, FlagOpen, FlagPing, FlagReset, FlagWindow, type FlowTiming, type ForcedCodec, type Frame, type FrameContext, type FrameHandler, K_LOUD, type Limits, MessageTooLargeError, type Metadata, type MethodDesc, type NamedCodec, type PayloadCodec, type ProtocolEvent, type ProtocolEventKind, type ProtocolStats, type RxBufferConfig, RxVerdict, RxWindow, SHAPE_MASK, Server, type ServerContext, type ServerOptions, type ServerReader, type ServerStreamingDesc, type ServerStreamingHandler, type ServerWriter, StatusError, type StreamClientInterceptor, type StreamServerHandler, type StreamServerInterceptor, type Streamer, type Timing, type TransportInfo, TxSeq, type UnaryClientInterceptor, type UnaryDesc, type UnaryHandler, type UnaryInvoker, type UnaryServerHandler, type UnaryServerInterceptor, W_CONN, W_FWD, W_INIT, abortCause, bidiMethod, clientStreamingMethod, cloneMetadata, decodeBase64, decodeEnvelope, decodeFrame, encodeBase64, encodeEnvelope, encodeFrame, frame, frameStatus, getCompressor, hasConnAttacher, hasTransportInfo, hasUnknownFlags, isBinaryKey, isClose, isCompressed, isData, isHalfClose, isHeaderFrame, isMessageTooLarge, isOpen, isPing, isReset, isTerminal, isUnary, isWindow, legalShape, metadataJoin, resetFor, serverStreamingMethod, setFrameError, shapeOf, statusDetails, statusError, toStatusError, unaryMethod, unpack, validateMetadata, validateMetadataPair };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as resolveTiming, c as statsSink, d as RxWindow, f as TxSeq, i as statusDetails, l as K_LOUD, m as chain2, n as Conn, o as Counters, p as W_FWD, r as EndOfStreamError, s as emit, t as ClientStream, u as RxVerdict } from "./conn-CmYPHTPR.mjs";
|
|
2
|
+
import { $ as sizeOr, A as DEFAULT_MAX_SEND_MSG_SIZE, B as W_INIT, C as isTerminal, D as setFrameError, 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, R as U32_MAX, S as isReset, T as legalShape, U as checkRecvSize, W as checkSendSize, X as nowMs, Y as noop, Z as rawPayload, _ as isData, a as FlagReset, at as cloneMetadata, b as isOpen, c as decodeEnvelope, ct as isBinaryKey, d as encodeFrame, dt as validateMetadataPair, et as tryAcquireBoth, f as frame, ft as DropPolicy, g as isCompressed, h as isClose, i as FlagPing, it as unpack, j as DEFAULT_STALL_MS, k as DEFAULT_MAX_RECV_MSG_SIZE, l as decodeFrame, lt as metadataJoin, m as hasUnknownFlags, mt as resolveRxConfig, n as FlagCompressed, nt as hasConnAttacher, o as FlagWindow, ot as decodeBase64, p as frameStatus, pt as resolveLimits, q as getCompressor, r as FlagOpen, rt as hasTransportInfo, s as SHAPE_MASK, st as encodeBase64, t as FlagClose, tt as unrefTimer, u as encodeEnvelope, ut as validateMetadata, v as isHalfClose, w as isWindow, x as isPing, y as isHeaderFrame, z as W_CONN } from "./wire-DqHx0oUs.mjs";
|
|
2
3
|
import { a as isMessageTooLarge, i as abortCause, n as MessageTooLargeError, o as statusError, r as StatusError, s as toStatusError, t as Code } from "./status-DZwMDWIn.mjs";
|
|
3
|
-
import { a as resolveTiming, c as RxWindow, i as statusDetails, l as TxSeq, n as Conn, o as K_LOUD, r as EndOfStreamError, s as RxVerdict, t as ClientStream, u as W_FWD } from "./conn-DOmx4nbt.mjs";
|
|
4
4
|
//#region src/desc.ts
|
|
5
5
|
function unaryMethod(path, init) {
|
|
6
6
|
return {
|
|
@@ -60,6 +60,10 @@ function windowOf(f) {
|
|
|
60
60
|
const w = f.window;
|
|
61
61
|
return typeof w === "number" && Number.isFinite(w) && w > 0 ? Math.floor(w) : 0;
|
|
62
62
|
}
|
|
63
|
+
function connWindowOf(f) {
|
|
64
|
+
const w = f.connWindow;
|
|
65
|
+
return typeof w === "number" && Number.isFinite(w) && w > 0 ? Math.min(Math.floor(w), U32_MAX) : 0;
|
|
66
|
+
}
|
|
63
67
|
var PeerState = class {
|
|
64
68
|
peer;
|
|
65
69
|
epoch;
|
|
@@ -76,6 +80,7 @@ var PeerState = class {
|
|
|
76
80
|
tombFloor = 0;
|
|
77
81
|
calls = /* @__PURE__ */ new Map();
|
|
78
82
|
liveCalls = 0;
|
|
83
|
+
connTx = new FlowSender();
|
|
79
84
|
lastRx;
|
|
80
85
|
lastTx;
|
|
81
86
|
lastPing = 0;
|
|
@@ -156,6 +161,7 @@ var PeerSlot = class {
|
|
|
156
161
|
replyBudget;
|
|
157
162
|
resetAt = /* @__PURE__ */ new Map();
|
|
158
163
|
pendingResets = /* @__PURE__ */ new Map();
|
|
164
|
+
flow;
|
|
159
165
|
constructor(peer) {
|
|
160
166
|
this.peer = peer;
|
|
161
167
|
}
|
|
@@ -174,6 +180,7 @@ var Server = class {
|
|
|
174
180
|
maxRecv;
|
|
175
181
|
maxSend;
|
|
176
182
|
stallMs;
|
|
183
|
+
/** @internal */ pstats;
|
|
177
184
|
services = /* @__PURE__ */ new Map();
|
|
178
185
|
serving = false;
|
|
179
186
|
slots = /* @__PURE__ */ new Map();
|
|
@@ -186,6 +193,8 @@ var Server = class {
|
|
|
186
193
|
idleWaiters = [];
|
|
187
194
|
sawUnreliable = false;
|
|
188
195
|
sw = new Sweeper();
|
|
196
|
+
unaryInt;
|
|
197
|
+
streamInt;
|
|
189
198
|
constructor(tx, opts = {}) {
|
|
190
199
|
this.epoch = nonzeroEpoch();
|
|
191
200
|
this.tx = tx;
|
|
@@ -202,6 +211,19 @@ var Server = class {
|
|
|
202
211
|
this.maxRecv = sizeOr(opts.maxRecvMsgSize, DEFAULT_MAX_RECV_MSG_SIZE);
|
|
203
212
|
this.maxSend = sizeOr(opts.maxSendMsgSize, DEFAULT_MAX_SEND_MSG_SIZE);
|
|
204
213
|
this.stallMs = opts.timing?.stallMs ?? 3e4;
|
|
214
|
+
this.pstats = statsSink(opts.protocolStats);
|
|
215
|
+
this.unaryInt = chain2(opts.unaryInterceptors);
|
|
216
|
+
this.streamInt = chain2(opts.streamInterceptors);
|
|
217
|
+
}
|
|
218
|
+
protoEvent(kind, peer, sid = 0) {
|
|
219
|
+
if (this.pstats.length === 0) return;
|
|
220
|
+
emit(this.pstats, {
|
|
221
|
+
kind,
|
|
222
|
+
peer,
|
|
223
|
+
sid,
|
|
224
|
+
method: "",
|
|
225
|
+
count: 0
|
|
226
|
+
});
|
|
205
227
|
}
|
|
206
228
|
register(desc, handler) {
|
|
207
229
|
if (this.serving) throw new Error("drpc: register called after the server started serving");
|
|
@@ -217,6 +239,7 @@ var Server = class {
|
|
|
217
239
|
this.serving = true;
|
|
218
240
|
if (isReset(f)) {
|
|
219
241
|
if (f.epoch !== this.epoch) return;
|
|
242
|
+
this.protoEvent("reset-received", ctx.peer, f.sid);
|
|
220
243
|
this.resetByPeerSid(ctx.peer, f.sid, f.peerEpoch);
|
|
221
244
|
return;
|
|
222
245
|
}
|
|
@@ -235,6 +258,7 @@ var Server = class {
|
|
|
235
258
|
if (ps.replayDue(tb, now, rti) && this.allowReply(slot, now)) {
|
|
236
259
|
const replay = ps.replayTomb(tb, now, rti);
|
|
237
260
|
if (replay !== void 0) {
|
|
261
|
+
this.protoEvent("tombstone-replay", peer, sid);
|
|
238
262
|
await this.send(replay, ctx);
|
|
239
263
|
return;
|
|
240
264
|
}
|
|
@@ -244,6 +268,11 @@ var Server = class {
|
|
|
244
268
|
}
|
|
245
269
|
return this.sendReset(slot, f, ctx);
|
|
246
270
|
}
|
|
271
|
+
if (sid === 0 && shapeOf(f) === 16) {
|
|
272
|
+
if (this.rxReliable(ctx)) if (ps !== void 0) ps.connTx.grant(windowOf(f));
|
|
273
|
+
else slot?.flow?.creditEvicted(f.epoch, windowOf(f));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
247
276
|
const st = ps?.calls.get(sid);
|
|
248
277
|
if (st !== void 0) {
|
|
249
278
|
await st.handleRx(f, ctx);
|
|
@@ -257,7 +286,10 @@ var Server = class {
|
|
|
257
286
|
const rti = this.mode.timing.retransmitMs;
|
|
258
287
|
if (ps.replayDue(tb, now, rti) && this.allowReply(slot, now)) {
|
|
259
288
|
const replay = ps.replayTomb(tb, now, rti);
|
|
260
|
-
if (replay !== void 0)
|
|
289
|
+
if (replay !== void 0) {
|
|
290
|
+
this.protoEvent("tombstone-replay", peer, sid);
|
|
291
|
+
await this.send(replay, ctx);
|
|
292
|
+
}
|
|
261
293
|
}
|
|
262
294
|
return;
|
|
263
295
|
}
|
|
@@ -272,7 +304,17 @@ var Server = class {
|
|
|
272
304
|
}
|
|
273
305
|
return this.open(ctx, f);
|
|
274
306
|
}
|
|
275
|
-
if (this.rxReliable(ctx))
|
|
307
|
+
if (this.rxReliable(ctx)) {
|
|
308
|
+
const pf = slot?.flow;
|
|
309
|
+
if (pf !== void 0 && isData(f)) if (ps !== void 0) {
|
|
310
|
+
const g = pf.unadmitted(f.epoch, 1);
|
|
311
|
+
if (g > 0) this.grantPeer(ps, g);
|
|
312
|
+
} else {
|
|
313
|
+
const g = pf.unadmittedEvicted(f.epoch, 1);
|
|
314
|
+
if (g > 0) this.grantEpoch(peer, f.epoch, g);
|
|
315
|
+
}
|
|
316
|
+
return this.sendReset(slot, f, ctx);
|
|
317
|
+
}
|
|
276
318
|
const s = this.ensureSlot(peer);
|
|
277
319
|
const k = eksid(f.epoch, sid);
|
|
278
320
|
if (!s.pendingResets.has(k) && this.pendingResetTotal < this.limits.maxPendingResets) {
|
|
@@ -311,6 +353,7 @@ var Server = class {
|
|
|
311
353
|
const now = nowMs();
|
|
312
354
|
const slot = this.ensureSlot(ctx.peer);
|
|
313
355
|
const ps = this.ensurePeer(slot, f.epoch, now, rel);
|
|
356
|
+
if (rel) this.observeAdvertisement(ps, f);
|
|
314
357
|
if (slot.liveCalls >= this.limits.maxLiveCalls) return this.rejectOpen(ctx, f, 8, "too many concurrent calls");
|
|
315
358
|
const cfg = this.methodRx.get(reg.desc.path) ?? this.rxCfg;
|
|
316
359
|
const rxCfg = {
|
|
@@ -339,6 +382,7 @@ var Server = class {
|
|
|
339
382
|
if (ps.hwm < f.sid) ps.hwm = f.sid;
|
|
340
383
|
ps.dead = false;
|
|
341
384
|
ps.lastRx = now;
|
|
385
|
+
if (rel) st.pf = this.ensurePeerFlow(slot);
|
|
342
386
|
if (slot.pendingResets.delete(eksid(f.epoch, f.sid))) this.pendingResetTotal--;
|
|
343
387
|
this.liveTasks++;
|
|
344
388
|
this.kickSweep();
|
|
@@ -356,6 +400,7 @@ var Server = class {
|
|
|
356
400
|
}
|
|
357
401
|
}
|
|
358
402
|
async rejectOpen(ctx, f, code, msg) {
|
|
403
|
+
const rel = this.rxReliable(ctx);
|
|
359
404
|
const t = frame({
|
|
360
405
|
epoch: this.epoch,
|
|
361
406
|
sid: f.sid,
|
|
@@ -365,15 +410,19 @@ var Server = class {
|
|
|
365
410
|
peerEpoch: f.epoch
|
|
366
411
|
});
|
|
367
412
|
t.code = code;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
413
|
+
this.advertise(t, rel);
|
|
414
|
+
const now = nowMs();
|
|
415
|
+
const slot = this.ensureSlot(ctx.peer);
|
|
416
|
+
const ps = this.ensurePeer(slot, f.epoch, now, rel);
|
|
417
|
+
ps.lastRx = now;
|
|
418
|
+
if (rel) {
|
|
419
|
+
this.observeAdvertisement(ps, f);
|
|
420
|
+
this.ensurePeerFlow(slot);
|
|
421
|
+
} else {
|
|
373
422
|
if (ps.hwm < f.sid) ps.hwm = f.sid;
|
|
374
423
|
ps.addTomb(f.sid, t, now + this.mode.timing.tombstoneMs);
|
|
375
|
-
this.kickSweep();
|
|
376
424
|
}
|
|
425
|
+
this.kickSweep();
|
|
377
426
|
await this.send(t, ctx);
|
|
378
427
|
}
|
|
379
428
|
async runUnary(st, open) {
|
|
@@ -383,7 +432,9 @@ var Server = class {
|
|
|
383
432
|
let resp;
|
|
384
433
|
try {
|
|
385
434
|
const req = await st.decodeMessage(open);
|
|
386
|
-
|
|
435
|
+
const h = async (r, c) => await st.reg.handler(r, c);
|
|
436
|
+
resp = this.unaryInt === void 0 ? await h(req, st.context) : await this.unaryInt(req, st.context, h);
|
|
437
|
+
if (resp === void 0) throw statusError(13, "unary handler produced no response");
|
|
387
438
|
} catch (e) {
|
|
388
439
|
err = toStatusError(e);
|
|
389
440
|
}
|
|
@@ -408,14 +459,20 @@ var Server = class {
|
|
|
408
459
|
const desc = st.reg.desc;
|
|
409
460
|
let err;
|
|
410
461
|
try {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
st.
|
|
418
|
-
|
|
462
|
+
const last = async (stream, ctx) => {
|
|
463
|
+
if (!desc.clientStreams) {
|
|
464
|
+
const req = await stream.recv();
|
|
465
|
+
if (req === void 0) throw statusError(2, "missing request message");
|
|
466
|
+
return st.reg.handler(req, stream, ctx);
|
|
467
|
+
}
|
|
468
|
+
if (!desc.serverStreams) return st.reg.handler(stream, ctx);
|
|
469
|
+
return st.reg.handler(stream, ctx);
|
|
470
|
+
};
|
|
471
|
+
const out = this.streamInt === void 0 ? await last(st, st.context) : await this.streamInt(st, st.context, last);
|
|
472
|
+
if (desc.clientStreams && !desc.serverStreams) {
|
|
473
|
+
if (out === void 0) throw statusError(13, "client-streaming handler produced no response");
|
|
474
|
+
st.setResponse(out);
|
|
475
|
+
}
|
|
419
476
|
} catch (e) {
|
|
420
477
|
err = toStatusError(e);
|
|
421
478
|
}
|
|
@@ -445,6 +502,7 @@ var Server = class {
|
|
|
445
502
|
}
|
|
446
503
|
if (slot !== void 0 && slot.liveCalls > 0) slot.liveCalls--;
|
|
447
504
|
st.flowTx.release();
|
|
505
|
+
st.releasePinned();
|
|
448
506
|
st.cancel(statusError(1, "call finished"));
|
|
449
507
|
if (st.deadlineTimer !== void 0) {
|
|
450
508
|
clearTimeout(st.deadlineTimer);
|
|
@@ -482,6 +540,7 @@ var Server = class {
|
|
|
482
540
|
this.sawUnreliable = true;
|
|
483
541
|
this.kickSweep();
|
|
484
542
|
}
|
|
543
|
+
this.protoEvent("reset-sent", ctx.peer, f.sid);
|
|
485
544
|
await this.send(resetFor(f), ctx);
|
|
486
545
|
}
|
|
487
546
|
allowReply(slot, now) {
|
|
@@ -523,13 +582,18 @@ var Server = class {
|
|
|
523
582
|
const slot = this.slots.get(peer);
|
|
524
583
|
if (slot === void 0) return;
|
|
525
584
|
const targets = [];
|
|
526
|
-
|
|
585
|
+
const senders = [];
|
|
586
|
+
for (const ps of slot.epochs.values()) {
|
|
587
|
+
for (const st of ps.calls.values()) targets.push(st);
|
|
588
|
+
senders.push(ps.connTx);
|
|
589
|
+
}
|
|
527
590
|
this.pendingResetTotal -= slot.pendingResets.size;
|
|
528
591
|
this.resetAtTotal -= slot.resetAt.size;
|
|
529
592
|
if (slot.replyBudget !== void 0) this.replyBudgetTotal--;
|
|
530
593
|
this.slots.delete(peer);
|
|
531
594
|
const cause = err === void 0 || err === null ? statusError(14, "transport closed") : statusError(14, `transport closed: ${err instanceof Error ? err.message : String(err)}`);
|
|
532
595
|
for (const st of targets) st.cancel(cause);
|
|
596
|
+
for (const tx of senders) tx.release();
|
|
533
597
|
}
|
|
534
598
|
waitIdle() {
|
|
535
599
|
if (this.liveTasks === 0) return Promise.resolve();
|
|
@@ -575,18 +639,54 @@ var Server = class {
|
|
|
575
639
|
ensurePeer(slot, epoch, now, reliable) {
|
|
576
640
|
let ps = slot.epochs.get(epoch);
|
|
577
641
|
if (ps !== void 0) return ps;
|
|
642
|
+
let held;
|
|
643
|
+
if (reliable) held = slot.flow?.unstash(epoch);
|
|
578
644
|
const dead = [];
|
|
579
645
|
for (const p of slot.epochs.values()) if (p.liveCalls === 0) dead.push(p);
|
|
580
646
|
if (dead.length >= this.limits.maxDeadPeers) {
|
|
581
647
|
let oldest = dead[0];
|
|
582
648
|
for (const p of dead) if (p.createdAt < oldest.createdAt) oldest = p;
|
|
649
|
+
if (oldest.reliable) this.ensurePeerFlow(slot).stash(oldest.epoch, oldest.connTx.state());
|
|
583
650
|
slot.epochs.delete(oldest.epoch);
|
|
584
651
|
}
|
|
585
652
|
ps = new PeerState(slot.peer, epoch, reliable, now, this.limits.maxTombstones, this.limits.maxTombstoneBytes);
|
|
653
|
+
if (held !== void 0) ps.connTx.restore(held);
|
|
586
654
|
slot.epochs.set(epoch, ps);
|
|
587
655
|
if (!reliable) this.sawUnreliable = true;
|
|
588
656
|
return ps;
|
|
589
657
|
}
|
|
658
|
+
observeAdvertisement(ps, f) {
|
|
659
|
+
ps.connTx.observe(connWindowOf(f));
|
|
660
|
+
}
|
|
661
|
+
/** @internal */
|
|
662
|
+
advertise(f, reliable) {
|
|
663
|
+
if (reliable) f.connWindow = this.limits.maxPeerWindow;
|
|
664
|
+
}
|
|
665
|
+
ensurePeerFlow(slot) {
|
|
666
|
+
let pf = slot.flow;
|
|
667
|
+
if (pf === void 0) {
|
|
668
|
+
pf = new PeerFlowRx();
|
|
669
|
+
pf.enable(this.limits.maxPeerWindow, this.limits.maxDeadPeers);
|
|
670
|
+
slot.flow = pf;
|
|
671
|
+
}
|
|
672
|
+
return pf;
|
|
673
|
+
}
|
|
674
|
+
/** @internal */
|
|
675
|
+
grantPeer(ps, n) {
|
|
676
|
+
this.grantOn(ps.peer, ps.epoch, n);
|
|
677
|
+
}
|
|
678
|
+
grantEpoch(peer, epoch, n) {
|
|
679
|
+
this.grantOn(peer, epoch, n);
|
|
680
|
+
}
|
|
681
|
+
grantOn(peer, epoch, n) {
|
|
682
|
+
if (this.closed) return;
|
|
683
|
+
this.send(frame({
|
|
684
|
+
epoch: this.epoch,
|
|
685
|
+
peerEpoch: epoch,
|
|
686
|
+
flags: 16,
|
|
687
|
+
window: n
|
|
688
|
+
}), this.txFor(peer));
|
|
689
|
+
}
|
|
590
690
|
/** @internal */
|
|
591
691
|
kickSweep() {
|
|
592
692
|
if (!this.sawUnreliable) return;
|
|
@@ -613,6 +713,7 @@ var Server = class {
|
|
|
613
713
|
if (!this.allowReply(slot, now)) continue;
|
|
614
714
|
slot.pendingResets.delete(k);
|
|
615
715
|
this.pendingResetTotal--;
|
|
716
|
+
this.protoEvent("reset-sent", slot.peer, pr.sid);
|
|
616
717
|
jobs.push({
|
|
617
718
|
f: frame({
|
|
618
719
|
flags: 4,
|
|
@@ -644,6 +745,7 @@ var Server = class {
|
|
|
644
745
|
if (ps.liveCalls > 0 && !ps.dead) {
|
|
645
746
|
if (now - ps.lastRx >= t.livenessMs) {
|
|
646
747
|
ps.dead = true;
|
|
748
|
+
this.protoEvent("liveness-expired", slot.peer);
|
|
647
749
|
for (const st of ps.calls.values()) {
|
|
648
750
|
st.suppressTerm = true;
|
|
649
751
|
lost.push(st);
|
|
@@ -656,6 +758,7 @@ var Server = class {
|
|
|
656
758
|
} else if (now - ps.lastTx >= t.probeMs && now - ps.lastPing >= t.probeMs) {
|
|
657
759
|
ps.lastPing = now;
|
|
658
760
|
ps.lastTx = now;
|
|
761
|
+
this.protoEvent("keepalive-sent", slot.peer);
|
|
659
762
|
jobs.push({
|
|
660
763
|
f: frame({
|
|
661
764
|
epoch: this.epoch,
|
|
@@ -668,20 +771,19 @@ var Server = class {
|
|
|
668
771
|
}
|
|
669
772
|
if (ps.liveCalls === 0 && ps.tombs.size === 0 && now - ps.lastRx > 2 * t.tombstoneMs) slot.epochs.delete(epoch);
|
|
670
773
|
}
|
|
671
|
-
for (const ps of slot.epochs.values()) {
|
|
672
|
-
if (
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
}
|
|
774
|
+
for (const ps of slot.epochs.values()) for (const st of ps.calls.values()) {
|
|
775
|
+
if (st.reliable) continue;
|
|
776
|
+
const f = st.probeDue(now, t.probeMs, this.epoch);
|
|
777
|
+
if (f !== void 0) {
|
|
778
|
+
st.protoEvent("probe-sent");
|
|
779
|
+
ps.lastTx = now;
|
|
780
|
+
jobs.push({
|
|
781
|
+
f,
|
|
782
|
+
ctx: this.txFor(slot.peer)
|
|
783
|
+
});
|
|
682
784
|
}
|
|
683
785
|
}
|
|
684
|
-
if (slot.epochs.size === 0 && slot.liveCalls === 0 && slot.pendingResets.size === 0 && slot.resetAt.size === 0 && slot.replyBudget === void 0) this.slots.delete(peerKey);
|
|
786
|
+
if (slot.epochs.size === 0 && slot.liveCalls === 0 && slot.pendingResets.size === 0 && slot.resetAt.size === 0 && slot.replyBudget === void 0 && slot.flow === void 0) this.slots.delete(peerKey);
|
|
685
787
|
}
|
|
686
788
|
const cause = statusError(14, "peer lost");
|
|
687
789
|
for (const st of lost) st.cancel(cause);
|
|
@@ -701,6 +803,7 @@ var ServerStream = class {
|
|
|
701
803
|
stallMs;
|
|
702
804
|
context;
|
|
703
805
|
/** @internal */ ps;
|
|
806
|
+
/** @internal */ pf;
|
|
704
807
|
/** @internal */ slot;
|
|
705
808
|
/** @internal */ deadlineAt;
|
|
706
809
|
/** @internal */ deadlineTimer;
|
|
@@ -721,6 +824,8 @@ var ServerStream = class {
|
|
|
721
824
|
lastProbe = 0;
|
|
722
825
|
hReplayAt = 0;
|
|
723
826
|
rxWin = new RxWindow();
|
|
827
|
+
pinned = 0;
|
|
828
|
+
rxReleased = false;
|
|
724
829
|
/** @internal */ rxq;
|
|
725
830
|
rxCfg;
|
|
726
831
|
/** @internal */ rxDropped = 0;
|
|
@@ -757,6 +862,7 @@ var ServerStream = class {
|
|
|
757
862
|
},
|
|
758
863
|
peer,
|
|
759
864
|
method: reg.desc.path,
|
|
865
|
+
desc: reg.desc,
|
|
760
866
|
get deadline() {
|
|
761
867
|
return self.deadlineAt;
|
|
762
868
|
},
|
|
@@ -767,6 +873,7 @@ var ServerStream = class {
|
|
|
767
873
|
try {
|
|
768
874
|
validateMetadata(md);
|
|
769
875
|
} catch {
|
|
876
|
+
this.protoEvent("off-shape", 1);
|
|
770
877
|
return;
|
|
771
878
|
}
|
|
772
879
|
this.trailerMd = metadataJoin(this.trailerMd, md);
|
|
@@ -784,9 +891,22 @@ var ServerStream = class {
|
|
|
784
891
|
this.endLatch.trip();
|
|
785
892
|
}
|
|
786
893
|
/** @internal */
|
|
894
|
+
protoEvent(kind, count = 0) {
|
|
895
|
+
const sink = this.server.pstats;
|
|
896
|
+
if (sink.length === 0) return;
|
|
897
|
+
emit(sink, {
|
|
898
|
+
kind,
|
|
899
|
+
peer: this.peer,
|
|
900
|
+
sid: this.sid,
|
|
901
|
+
method: this.reg.desc.path,
|
|
902
|
+
count
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
/** @internal */
|
|
787
906
|
async handleRx(f, ctx) {
|
|
788
907
|
if (hasUnknownFlags(f) || !legalShape(shapeOf(f))) {
|
|
789
908
|
this.cancel(statusError(13, `drpc: frame carries unsupported flags 0x${f.flags.toString(16)}`));
|
|
909
|
+
this.creditUnbuffered(f);
|
|
790
910
|
return;
|
|
791
911
|
}
|
|
792
912
|
if (shapeOf(f) === 16) {
|
|
@@ -806,12 +926,15 @@ var ServerStream = class {
|
|
|
806
926
|
if (!isUnary(this.reg.desc) || this.hdrFrame !== void 0) this.replayH();
|
|
807
927
|
return;
|
|
808
928
|
}
|
|
809
|
-
|
|
929
|
+
const v = this.rxWin.check(f.seq);
|
|
930
|
+
if (v !== 0) this.creditUnbuffered(f);
|
|
931
|
+
switch (v) {
|
|
810
932
|
case 1:
|
|
811
933
|
this.noteValidatedRx();
|
|
812
934
|
return;
|
|
813
935
|
case 2: return;
|
|
814
936
|
case 3:
|
|
937
|
+
this.protoEvent("data-loss");
|
|
815
938
|
this.cancel(statusError(15, "seq window overrun: >W_fwd consecutive frames lost"));
|
|
816
939
|
return;
|
|
817
940
|
case 4:
|
|
@@ -819,22 +942,38 @@ var ServerStream = class {
|
|
|
819
942
|
return;
|
|
820
943
|
case 0: break;
|
|
821
944
|
}
|
|
945
|
+
const gap = this.rxWin.takeGap();
|
|
946
|
+
if (gap > 0) this.protoEvent("skipped", gap);
|
|
822
947
|
this.noteValidatedRx();
|
|
823
948
|
if (isTerminal(f)) this.cancel(frameStatus(f));
|
|
824
949
|
else if (isHalfClose(f)) this.rxEOF.trip();
|
|
825
950
|
else if (isData(f)) {
|
|
826
951
|
if (isUnary(this.reg.desc) || !this.reg.desc.clientStreams) {
|
|
827
952
|
this.rxDropped++;
|
|
953
|
+
this.creditUnbuffered(f);
|
|
828
954
|
return;
|
|
829
955
|
}
|
|
830
956
|
if (this.reliable) {
|
|
957
|
+
if (this.pf !== void 0 && !this.pf.admit()) {
|
|
958
|
+
this.cancel(statusError(13, "drpc: peer exceeded the connection flow-control window"));
|
|
959
|
+
this.creditUnbuffered(f);
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
if (!this.pin()) {
|
|
963
|
+
this.retirePeer(1);
|
|
964
|
+
return;
|
|
965
|
+
}
|
|
831
966
|
if (this.flowRx.active) {
|
|
832
|
-
if (!this.rxq.tryPut(f))
|
|
967
|
+
if (!this.rxq.tryPut(f)) {
|
|
968
|
+
if (this.unpin()) this.retirePeer(1);
|
|
969
|
+
this.cancel(statusError(13, "drpc: peer exceeded the advertised flow-control window"));
|
|
970
|
+
}
|
|
833
971
|
} else if (!await this.rxq.putBlocking(f, this.endLatch, ctx.signal)) {
|
|
972
|
+
if (this.unpin()) this.retirePeer(1);
|
|
834
973
|
this.rxDropped++;
|
|
835
974
|
this.cancel(statusError(14, "transport closed during delivery"));
|
|
836
975
|
}
|
|
837
|
-
} else this.rxq.putDrop(f, this.rxCfg.policy);
|
|
976
|
+
} else if (this.rxq.putDrop(f, this.rxCfg.policy) > 0) this.protoEvent("dropped", 1);
|
|
838
977
|
} else this.rxDropped++;
|
|
839
978
|
}
|
|
840
979
|
noteValidatedRx() {
|
|
@@ -845,11 +984,7 @@ var ServerStream = class {
|
|
|
845
984
|
async recv() {
|
|
846
985
|
for (;;) {
|
|
847
986
|
const f = this.rxq.tryTake();
|
|
848
|
-
if (f !== void 0)
|
|
849
|
-
const msg = await this.decodeMessage(f);
|
|
850
|
-
this.grantWindow(1);
|
|
851
|
-
return msg;
|
|
852
|
-
}
|
|
987
|
+
if (f !== void 0) return this.recvBuffered(f);
|
|
853
988
|
if (this.rxEOF.tripped) return void 0;
|
|
854
989
|
if (this.ctrl.signal.aborted) throw abortCause(this.ctrl.signal);
|
|
855
990
|
await Promise.race([
|
|
@@ -859,6 +994,39 @@ var ServerStream = class {
|
|
|
859
994
|
]);
|
|
860
995
|
}
|
|
861
996
|
}
|
|
997
|
+
async recvBuffered(f) {
|
|
998
|
+
if (!isOpen(f) && this.unpin()) this.retirePeer(1);
|
|
999
|
+
const msg = await this.decodeMessage(f);
|
|
1000
|
+
this.grantWindow(1);
|
|
1001
|
+
return msg;
|
|
1002
|
+
}
|
|
1003
|
+
pin() {
|
|
1004
|
+
if (this.rxReleased) return false;
|
|
1005
|
+
this.pinned++;
|
|
1006
|
+
return true;
|
|
1007
|
+
}
|
|
1008
|
+
unpin() {
|
|
1009
|
+
if (this.pinned === 0) return false;
|
|
1010
|
+
this.pinned--;
|
|
1011
|
+
return true;
|
|
1012
|
+
}
|
|
1013
|
+
/** @internal */
|
|
1014
|
+
releasePinned() {
|
|
1015
|
+
const pinned = this.pinned;
|
|
1016
|
+
this.pinned = 0;
|
|
1017
|
+
this.rxReleased = true;
|
|
1018
|
+
this.retirePeer(pinned);
|
|
1019
|
+
}
|
|
1020
|
+
creditUnbuffered(f) {
|
|
1021
|
+
if (!this.reliable || this.pf === void 0 || this.ps === void 0 || !isData(f)) return;
|
|
1022
|
+
const g = this.pf.unadmitted(this.clientEpoch, 1);
|
|
1023
|
+
if (g > 0) this.server.grantPeer(this.ps, g);
|
|
1024
|
+
}
|
|
1025
|
+
retirePeer(n) {
|
|
1026
|
+
if (n === 0 || this.pf === void 0 || this.ps === void 0) return;
|
|
1027
|
+
const g = this.pf.retire(this.clientEpoch, n, true);
|
|
1028
|
+
if (g > 0) this.server.grantPeer(this.ps, g);
|
|
1029
|
+
}
|
|
862
1030
|
async *[Symbol.asyncIterator]() {
|
|
863
1031
|
for (;;) {
|
|
864
1032
|
const m = await this.recv();
|
|
@@ -898,6 +1066,7 @@ var ServerStream = class {
|
|
|
898
1066
|
sendH() {
|
|
899
1067
|
const f = this.nextFrame();
|
|
900
1068
|
if (this.reliable) f.window = this.rxCfg.size;
|
|
1069
|
+
this.server.advertise(f, this.reliable);
|
|
901
1070
|
this.attachHeader(f, false);
|
|
902
1071
|
if (this.hdrFrame === void 0) this.hdrFrame = f;
|
|
903
1072
|
this.transmit(f).catch(noop);
|
|
@@ -924,6 +1093,7 @@ var ServerStream = class {
|
|
|
924
1093
|
if (f === void 0) {
|
|
925
1094
|
f = this.nextFrame();
|
|
926
1095
|
if (this.reliable) f.window = this.rxCfg.size;
|
|
1096
|
+
this.server.advertise(f, this.reliable);
|
|
927
1097
|
this.attachHeader(f, false);
|
|
928
1098
|
}
|
|
929
1099
|
this.transmit(f).catch(noop);
|
|
@@ -953,6 +1123,7 @@ var ServerStream = class {
|
|
|
953
1123
|
this.hdrFlushed = true;
|
|
954
1124
|
if (md !== void 0) this.txHeader = metadataJoin(this.txHeader, md);
|
|
955
1125
|
const f = this.nextFrame();
|
|
1126
|
+
this.server.advertise(f, this.reliable);
|
|
956
1127
|
this.attachHeader(f, true);
|
|
957
1128
|
if (this.hdrFrame === void 0) this.hdrFrame = f;
|
|
958
1129
|
try {
|
|
@@ -965,19 +1136,33 @@ var ServerStream = class {
|
|
|
965
1136
|
async send(msg) {
|
|
966
1137
|
const raw = this.resCodec.marshal(msg);
|
|
967
1138
|
if (!this.reg.desc.serverStreams) throw statusError(13, "send on a non-server-streaming call");
|
|
968
|
-
if (
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1139
|
+
if (this.ctrl.signal.aborted) throw abortCause(this.ctrl.signal);
|
|
1140
|
+
const connTx = this.reliable && this.ps !== void 0 ? this.ps.connTx : void 0;
|
|
1141
|
+
if (!tryAcquireBoth(this.flowTx, connTx)) {
|
|
1142
|
+
let peer = false;
|
|
1143
|
+
switch (await acquireBoth(this.flowTx, connTx, this.endLatch, this.stallMs, void 0, (p) => {
|
|
1144
|
+
peer = p;
|
|
1145
|
+
this.protoEvent(p ? "peer-flow-stall" : "flow-stall");
|
|
1146
|
+
})) {
|
|
1147
|
+
case "ok":
|
|
1148
|
+
this.protoEvent(peer ? "peer-flow-resume" : "flow-resume");
|
|
1149
|
+
break;
|
|
1150
|
+
case "stalled": throw statusError(14, `drpc: flow-control stall: the peer granted no credit for ${this.stallMs}ms`);
|
|
1151
|
+
case "peer-stalled": throw statusError(14, `drpc: flow-control stall: the peer granted no connection credit for ${this.stallMs}ms`);
|
|
1152
|
+
default: throw abortCause(this.ctrl.signal);
|
|
1153
|
+
}
|
|
972
1154
|
}
|
|
973
1155
|
let enc;
|
|
974
1156
|
try {
|
|
975
1157
|
enc = await this.encodePayload(raw);
|
|
976
1158
|
} catch (e) {
|
|
977
|
-
this.
|
|
1159
|
+
this.undoCredit();
|
|
978
1160
|
throw e;
|
|
979
1161
|
}
|
|
980
|
-
if (this.ctrl.signal.aborted)
|
|
1162
|
+
if (this.ctrl.signal.aborted) {
|
|
1163
|
+
this.undoCredit();
|
|
1164
|
+
throw abortCause(this.ctrl.signal);
|
|
1165
|
+
}
|
|
981
1166
|
const f = this.nextFrame();
|
|
982
1167
|
f.payload = enc.bytes;
|
|
983
1168
|
if (enc.compressed) f.flags |= 32;
|
|
@@ -998,7 +1183,11 @@ var ServerStream = class {
|
|
|
998
1183
|
undoRefused(f, err) {
|
|
999
1184
|
if (!isMessageTooLarge(err)) return;
|
|
1000
1185
|
this.txSeq.undo(f.seq);
|
|
1001
|
-
if (isData(f)) this.
|
|
1186
|
+
if (isData(f)) this.undoCredit();
|
|
1187
|
+
}
|
|
1188
|
+
undoCredit() {
|
|
1189
|
+
this.flowTx.undo();
|
|
1190
|
+
if (this.reliable && this.ps !== void 0) this.ps.connTx.undo();
|
|
1002
1191
|
}
|
|
1003
1192
|
async encodePayload(payload) {
|
|
1004
1193
|
const enc = this.comp === void 0 ? rawPayload(payload) : await compressPayload(this.comp, payload);
|
|
@@ -1029,6 +1218,7 @@ var ServerStream = class {
|
|
|
1029
1218
|
}
|
|
1030
1219
|
const f = this.nextFrame();
|
|
1031
1220
|
f.flags = 2;
|
|
1221
|
+
this.server.advertise(f, this.reliable);
|
|
1032
1222
|
if (this.txHeader !== void 0) {
|
|
1033
1223
|
f.header = this.txHeader;
|
|
1034
1224
|
this.hdrSent = true;
|
|
@@ -1076,4 +1266,4 @@ function illegalHeaderWrite() {
|
|
|
1076
1266
|
return statusError(13, "drpc: sendHeader called multiple times");
|
|
1077
1267
|
}
|
|
1078
1268
|
//#endregion
|
|
1079
|
-
export { ClientStream, Code, Conn, DEFAULT_MAX_RECV_MSG_SIZE, DEFAULT_MAX_SEND_MSG_SIZE, DEFAULT_STALL_MS, DropPolicy, EndOfStreamError, FlagClose, FlagCompressed, FlagOpen, FlagPing, FlagReset, FlagWindow, K_LOUD, MessageTooLargeError, RxVerdict, RxWindow, SHAPE_MASK, Server, StatusError, TxSeq, W_FWD, W_INIT, abortCause, bidiMethod, clientStreamingMethod, cloneMetadata, decodeBase64,
|
|
1269
|
+
export { ClientStream, Code, Conn, Counters, DEFAULT_MAX_RECV_MSG_SIZE, DEFAULT_MAX_SEND_MSG_SIZE, DEFAULT_STALL_MS, DropPolicy, EndOfStreamError, FlagClose, FlagCompressed, FlagOpen, FlagPing, FlagReset, FlagWindow, K_LOUD, MessageTooLargeError, RxVerdict, RxWindow, SHAPE_MASK, Server, StatusError, TxSeq, W_CONN, W_FWD, W_INIT, abortCause, bidiMethod, clientStreamingMethod, cloneMetadata, decodeBase64, decodeEnvelope, decodeFrame, encodeBase64, encodeEnvelope, encodeFrame, frame, frameStatus, getCompressor, hasConnAttacher, hasTransportInfo, hasUnknownFlags, isBinaryKey, isClose, isCompressed, isData, isHalfClose, isHeaderFrame, isMessageTooLarge, isOpen, isPing, isReset, isTerminal, isUnary, isWindow, legalShape, metadataJoin, resetFor, serverStreamingMethod, setFrameError, shapeOf, statusDetails, statusError, toStatusError, unaryMethod, unpack, validateMetadata, validateMetadataPair };
|