chore(vendor): import pi 1.3.0
Imported as a linear vendor commit so forge rebases do not replay the upstream root tree. git-subtree-dir: third_party/pi git-subtree-split: 71023aec1546d6d677a65669c5665c0927ce0dd0
This commit is contained in:
1 parent
719370c8f7
commit
6081e3e325
1743 files changed
+205459
-131704
No files matched your search
@@ -0,0 +1,73 @@
|
||||
// A link wrapper that counts what crosses it, per direction: frames by type and bytes (JSON text length). It can also
|
||||
// hold back the acknowledgements its own side sends (`paused`), to fill the peer's flow-control window.
|
||||
import type { Frame, Link } from "../../src/index.ts";
|
||||
|
||||
export class CountingLink implements Link {
|
||||
readonly inner: Link;
|
||||
/** Frames this side sent, in order. */
|
||||
readonly sent: Frame[] = [];
|
||||
/** Frames this side received, in order. */
|
||||
readonly received: Frame[] = [];
|
||||
sentBytes = 0;
|
||||
receivedBytes = 0;
|
||||
/** Acknowledgements are held back (the peer's window fills up). */
|
||||
paused = false;
|
||||
#held: Frame | undefined;
|
||||
|
||||
constructor(inner: Link) {
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
get closed(): boolean {
|
||||
return this.inner.closed;
|
||||
}
|
||||
|
||||
send(frame: Frame): number | undefined {
|
||||
if (frame.t === "ack" && this.paused) {
|
||||
this.#held = frame;
|
||||
return 0;
|
||||
}
|
||||
this.sent.push(frame);
|
||||
this.sentBytes += JSON.stringify(frame).length;
|
||||
return this.inner.send(frame);
|
||||
}
|
||||
|
||||
/** Lets the held acknowledgement through and stops holding them. */
|
||||
release(): void {
|
||||
this.paused = false;
|
||||
const held = this.#held;
|
||||
this.#held = undefined;
|
||||
if (held !== undefined) this.inner.send(held);
|
||||
}
|
||||
|
||||
receive(handler: (frame: Frame) => void): void {
|
||||
this.inner.receive((frame) => {
|
||||
this.received.push(frame);
|
||||
this.receivedBytes += JSON.stringify(frame).length;
|
||||
handler(frame);
|
||||
});
|
||||
}
|
||||
|
||||
onClose(handler: (reason: string) => void): void {
|
||||
this.inner.onClose(handler);
|
||||
}
|
||||
|
||||
close(reason?: string): void {
|
||||
this.inner.close(reason);
|
||||
}
|
||||
|
||||
/** Frames of type `t` this side sent (`sent`) or received (`received`). */
|
||||
count(direction: "sent" | "received", t: Frame["t"]): number {
|
||||
return this[direction].filter((frame) => frame.t === t).length;
|
||||
}
|
||||
|
||||
/** Frames this side sent or received, except pings, pongs and acknowledgements. */
|
||||
traffic(direction: "sent" | "received"): Frame[] {
|
||||
return this[direction].filter((frame) => frame.t !== "ping" && frame.t !== "pong" && frame.t !== "ack");
|
||||
}
|
||||
}
|
||||
|
||||
export type StateFrame = Extract<Frame, { t: "state" }>;
|
||||
|
||||
export const stateFrames = (frames: readonly Frame[]): StateFrame[] =>
|
||||
frames.filter((frame): frame is StateFrame => frame.t === "state");
|
||||
Reference in new issue
Block a user