Carry numeric priorities through encrypted RPC and adapter writers with bounded admission. Correct push semantics and socket lifecycle cleanup, expose dispatch gating, and add opt-in connection health. Preserve the WebSocket setup API while allowing applications to override keepalive settings. Enable Android socket publication and document the 0.7.2-SNAPSHOT release workflow.
3.9 KiB
Numeric transport priority — 0.7.2-SNAPSHOT
import net.sergeych.kiloparsec.call
import net.sergeych.kiloparsec.push
remote.call(command, arguments, priority = 100)
remote.push(notification, arguments, priority = 0)
Larger signed Int values go first. Equal priorities preserve FIFO. Existing
call/push entry points remain unchanged and use zero unless invoked inside an
explicit priority call context. The overloads are extension functions, preserving
existing RemoteInterface implementers. A coroutine context carries the selected
value through the encrypted RPC wrappers; it becomes serialized outer-block data.
The adapter owns one outgoing writer. Waiting for a response does not occupy the writer: calls retain independent request IDs and response waiters. Both transport responses and errors copy the request's priority, including encrypted RPC errors returned inside an outer response. Pushes have no normal response.
Wire compatibility
The legacy block tag and body are unchanged. Nonzero priority is appended as four big-endian two's-complement bytes. Zero omits the trailer entirely. The new reader defaults to zero only when the trailer is absent; a partial trailer is malformed.
This relies on each Transport.Block having its own finite byte-array frame. TCP's existing length prefix, WebSocket messages and UDP data blocks provide that boundary. The old decoder consumes the legacy body and ignores trailing bytes. Do not use this EOF-terminated extension to concatenate unframed Block objects or embed them directly in a positional collection; wrap each block in its own bytes. The handshake remains version 1 because the original wire format is retained.
Old peers interoperate but do not honor/inherit priority. New peers can decode both formats. BiPack @Extendable is deliberately not added: it would insert a new field-count prefix before existing fields and break old readers.
Adapter behavior
TCP, WebSocket client/server, and UDP use a per-connection priority writer.
The writer reads the legacy header lengths and skips payloads to locate priority;
it does not deserialize/copy/decrypt the payload or guess from the last four bytes.
Transport.Device.send(block) defaults to the existing output channel for custom
or legacy devices. Built-in ProxyDevice-based adapters override it to enter their
writer directly. The old output channel remains available, bridged into that writer;
new transports should call send so pending senders are visible to priority ordering.
Custom adapters retain their existing FIFO behavior until they implement priority.
Queue admission is bounded to 128 waiting blocks and 32 MiB (plus the block currently being written). Overflow fails explicitly rather than allocating an unbounded backlog. Send awaits its adapter write callback, not a remote RPC reply. Queued cancellation removes the block; cancellation cannot recall a write already started. Closing the writer releases pending senders. There is no rate limiter or batch-collection delay. WebSocket writes flush after each block to avoid excessive look-ahead in the engine's FIFO. Socket/TLS buffers and network loss can still delay control behind bytes already submitted; priority is not a preemption guarantee.
Verification
Focused JVM tests cover signed numeric ordering, stable ties, queued cancellation, bounded admission, close, absent/partial trailers, unchanged legacy bodies, and priority inheritance through encrypted concurrent calls and encrypted errors. An encrypted simulated 16 KiB/s link saturated in both directions maintains control round trips below 400 ms and aggregate utilization above 80% of full-duplex capacity. This simulation does not model kernel/TLS buffering or packet loss. JVM, Android and JS compilation and socket/resource lifecycle tests pass. Caravan also checked call/error/response fixtures with the actual packaged 0.7.1-SNAPSHOT binary and the new 0.7.2-SNAPSHOT binary in separate JVM processes.