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.
70 lines
3.9 KiB
Markdown
70 lines
3.9 KiB
Markdown
# Numeric transport priority — 0.7.2-SNAPSHOT
|
|
|
|
```kotlin
|
|
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.
|