Expand description
Decoding text/event-stream.
The encoder lives in ag-ui-core; this is the other half. It is a wire
format parser fed by a network, so it assumes nothing about what it is
handed: bytes arrive in arbitrary chunks that split lines, split UTF-8
sequences, and end without the terminating blank line the format calls for.
What it handles, because real servers and proxies do all of it:
data:repeated over several lines, rejoined with\n— the format’s own way of carrying a payload that contains newlines.- Comment lines (
: keep-alive), which proxies inject to hold a connection open and which dispatch nothing. - A body that ends without a blank line:
SseDecoder::finishdispatches the last frame rather than dropping it. \n,\r\nand lone\rline endings, including a\r\nsplit across two chunks.- A leading UTF-8 byte-order mark.
- A field with no colon, an empty field value, and unknown field names.
- A frame with no
datafield, which the format says not to dispatch.
What it refuses: invalid UTF-8, and a single frame larger than
SseDecoder::max_frame_size — an unterminated line is otherwise an
unbounded allocation driven by the other end. The cap is on the frame, not
on the chunk: one read carrying a thousand complete frames is ordinary, and
counting it against a per-frame limit would refuse a well-behaved server.
use ag_ui::client::transport::SseDecoder;
let mut decoder = SseDecoder::new();
decoder.push(b": keep-alive\n\ndata: {\"type\":\"RUN_ERROR\",\"mes")?;
assert!(decoder.next_frame()?.is_none());
decoder.push(b"sage\":\"boom\"}\n\n")?;
let frame = decoder.next_frame()?.expect("a complete frame");
assert_eq!(frame.into_event()?.event_type().as_str(), "RUN_ERROR");Structs§
- SseDecoder
- An incremental
text/event-streamdecoder. - SseFrame
- One decoded
text/event-streamframe.
Constants§
- DEFAULT_
MAX_ FRAME_ SIZE - The default cap on one frame, before the decoder gives up: 8 MiB.
Functions§
- decode_
events - Decodes a stream of byte chunks into a stream of events.