UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

104 lines 4.71 kB
/** * Per-peer reassembly buffer for fragmented packets. * * When a sender's logical payload exceeds the MTU it gets split into * multiple {@link NetworkPacketType.FRAGMENT} packets, each carrying a * `(message_id, chunk_index, total_chunks, chunk_bytes)` tuple. The * receiver feeds those tuples to {@link receive}; once all chunks for a * `message_id` have arrived, `receive` returns the reassembled bytes * for the upper layer to dispatch. * * Loss recovery via NACK: a partially-received message that doesn't * complete within `nack_initial_delay_ms` triggers a NACK back to the * sender listing the missing chunk indices. NACK rounds repeat at * `nack_resend_interval_ms` up to `nack_max_rounds`; after that the * receiver gives up on the message and the sender's retention ages * out independently. Wire the per-tick driver via {@link service}. * * Loss-of-last-resort model: if even the NACK retries fail (link is * dead, sender retention was evicted, etc.) the message never * completes and FIFO-evicts when the pending cap is hit. Upper layers * are still expected to tolerate occasional missing messages — NACK * recovers most loss, not all. * * @author Alex Goldring * @copyright Company Named Limited (c) 2025 */ export class FragmentAssembler { /** * @param {{ * max_pending_messages?: number, * max_message_size?: number, * nack_initial_delay_ms?: number, * nack_resend_interval_ms?: number, * nack_max_rounds?: number, * }} [options] * `max_pending_messages` caps the number of in-flight reassembly * slots; when full, the oldest pending message is evicted to make * room. `max_message_size` rejects reassembled messages larger than * this many bytes (defensive against a malicious peer or a wedged * sender). The `nack_*` knobs control the retransmit-request timer * driven by {@link service}. */ constructor({ max_pending_messages, max_message_size, nack_initial_delay_ms, nack_resend_interval_ms, nack_max_rounds, }?: { max_pending_messages?: number; max_message_size?: number; nack_initial_delay_ms?: number; nack_resend_interval_ms?: number; nack_max_rounds?: number; }); /** @type {number} @readonly */ readonly max_pending_messages: number; /** @type {number} @readonly */ readonly max_message_size: number; /** @type {number} @readonly */ readonly nack_initial_delay_ms: number; /** @type {number} @readonly */ readonly nack_resend_interval_ms: number; /** @type {number} @readonly */ readonly nack_max_rounds: number; /** * Process an incoming fragment. Returns the reassembled bytes when * the message is complete, or null otherwise. * * @param {number} message_id sender-assigned message id * @param {number} chunk_index 0-based * @param {number} total_chunks expected number of chunks (>= 1) * @param {Uint8Array} chunk_bytes source byte array * @param {number} chunk_offset start offset within `chunk_bytes` * @param {number} chunk_length number of bytes from `chunk_offset` to consume * @returns {Uint8Array|null} */ receive(message_id: number, chunk_index: number, total_chunks: number, chunk_bytes: Uint8Array, chunk_offset: number, chunk_length: number): Uint8Array | null; /** * Per-tick maintenance: drive NACK emission for pending messages * whose initial delay has elapsed and whose resend interval has * lapsed, and drop messages whose NACK budget is exhausted. * * On the first service tick that observes a pending entry, its * arrival is timestamped (so the initial delay is measured from * `now_ms` of that tick rather than from the actual wall-clock * arrival of the first chunk — at typical tick rates the difference * is one tick, negligible vs. the 100 ms initial delay). * * `on_nack` is invoked once per eligible message with * `(message_id, indices, count)`. The `indices` argument is a * reused internal Uint8Array; only `indices[0..count)` is valid * and only for the duration of the call. * * @param {number} now_ms * @param {function(number, Uint8Array, number): void} on_nack */ service(now_ms: number, on_nack: (arg0: number, arg1: Uint8Array, arg2: number) => void): void; /** * Number of in-flight reassembly slots currently held. * @returns {number} */ pending_count(): number; /** * Drop all in-flight reassembly state. Useful on peer disconnect. */ clear(): void; #private; } //# sourceMappingURL=FragmentAssembler.d.ts.map