// Watermark-based backpressure for a WebSocket-like sender. The route polls
// `bufferedAmount` after each send; once it crosses `highWaterBytes` the sink
// (a TerminalAttachment) is told to pause its PTY. While paused, we sample
// `bufferedAmount` on `pollMs` and resume once it drains back below
// `lowWaterBytes`. The split watermarks give the socket headroom and avoid
// thrashing between pause and resume on every send.
export class SocketBackpressure {
    socket;
    sink;
    options;
    paused = false;
    drainTimer = null;
    constructor(socket, sink, options) {
        this.socket = socket;
        this.sink = sink;
        this.options = options;
    }
    // Call after each socket.send to re-evaluate backpressure.
    observe() {
        if (this.paused)
            return;
        if (this.socket.bufferedAmount <= this.options.highWaterBytes)
            return;
        this.paused = true;
        this.sink.pause();
        this.startDrainPoll();
    }
    // Stop polling. Does NOT release a held pause — the sink (attachment) is
    // responsible for releasing on its own dispose, so we don't double-resume
    // when both the socket and the attachment close.
    dispose() {
        this.stopDrainPoll();
    }
    startDrainPoll() {
        if (this.drainTimer)
            return;
        this.drainTimer = setInterval(() => this.tick(), this.options.pollMs);
        if (typeof this.drainTimer.unref === 'function') {
            this.drainTimer.unref();
        }
    }
    stopDrainPoll() {
        if (this.drainTimer) {
            clearInterval(this.drainTimer);
            this.drainTimer = null;
        }
    }
    tick() {
        if (!this.socket.isOpen()) {
            this.stopDrainPoll();
            return;
        }
        if (this.socket.bufferedAmount > this.options.lowWaterBytes) {
            return;
        }
        this.stopDrainPoll();
        if (this.paused) {
            this.paused = false;
            this.sink.resume();
        }
    }
}
//# sourceMappingURL=socketBackpressure.js.map