mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
* perf(hub): gzip the SSE stream without delaying delivery SSE payloads are plain JSON that repeat the same field names on every event, so they compress well - measured 72-77% on real captured traffic from a hub with 15 active sessions. Compression could not simply be turned on, though. Hono's compress() middleware bails out whenever Transfer-Encoding is set, which streamSSE always sets, so mounting it is a no-op. Wrapping the body in a CompressionStream does compress, but it buffers until the stream ends - measured on a 10-event stream, every event arrived at once when the stream closed. On a connection that stays open for hours that means events never arrive at all. So drive zlib directly and issue a Z_SYNC_FLUSH after each chunk. That costs about one percentage point of ratio and keeps delivery immediate: verified in a real Chromium EventSource, first event at 13ms and each subsequent event at its own 500ms tick, with no error events. Clients that do not send Accept-Encoding: gzip keep the uncompressed stream. No event payload or timing changes. * fix(hub): cancel through the reader, gate reads on demand, honour q=0 Three defects in the first version of the SSE gzip wrapper: Cancelling the source directly threw. The wrapper holds a reader for the whole life of the connection, and cancelling a locked stream is invalid - in Bun it throws TypeError: Invalid state: ReadableStream is locked synchronously out of the cancel callback. Since SSE clients disconnect mid-stream as a matter of course, this fired on essentially every disconnect, and the upstream cancel never ran. Cancel through the reader instead, which is allowed to. Reads were not gated on downstream demand. Only zlib's own buffer was consulted, and SSE compresses well enough that a slow client can be megabytes behind while the compressed queue still looks nearly empty: a test with a non-reading consumer pulled 1752 chunks before stalling. Reading now waits for desiredSize to go positive, resumed from pull(). Accept-Encoding was matched with a substring test, so "gzip;q=0" - which means the client refuses gzip - was read as acceptance. Parse the q-value. Re-verified that none of this costs the property the change exists for: in a real Chromium EventSource the first event still arrives at 13ms and each one after it on its own 500ms tick, with no error events.