use serde_json::Value;
#[derive(Debug)]
pub struct SseDecoder {
buffer: String,
}
impl SseDecoder {
pub fn new() -> Self {
Self {
buffer: String::new(),
}
}
pub fn decode(&mut self, chunk: &[u8]) -> Vec<Value> {
let text = String::from_utf8_lossy(chunk);
self.buffer.push_str(&text);
let mut values = Vec::new();
while let Some(pos) = self.buffer.find('\n') {
let line: String = self.buffer.drain(..=pos).collect();
let line = line.trim();
if line.is_empty() {
continue;
}
if line.starts_with("event:") {
continue;
}
if let Some(data) = line
.strip_prefix("data: ")
.or_else(|| line.strip_prefix("data:"))
{
let data = data.trim();
if data == "[DONE]" {
continue;
}
if let Ok(val) = serde_json::from_str::<Value>(data) {
values.push(val);
}
}
}
values
}
pub fn flush(&mut self) -> Vec<Value> {
let remaining = self.buffer.trim().to_string();
self.buffer.clear();
if remaining.is_empty() {
return Vec::new();
}
let mut values = Vec::new();
for line in remaining.lines() {
let line = line.trim();
if let Some(data) = line
.strip_prefix("data: ")
.or_else(|| line.strip_prefix("data:"))
{
let data = data.trim();
if data != "[DONE]" {
if let Ok(val) = serde_json::from_str::<Value>(data) {
values.push(val);
}
}
}
}
values
}
}
impl Default for SseDecoder {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sse_basic_decode() {
let mut decoder = SseDecoder::new();
let chunk = b"data: {\"choices\":[{\"delta\":{\"content\":\"Hello\"}}]}\n\n";
let values = decoder.decode(chunk);
assert_eq!(values.len(), 1);
assert!(values[0]["choices"][0]["delta"]["content"]
.as_str()
.is_some());
}
#[test]
fn test_sse_done_ignored() {
let mut decoder = SseDecoder::new();
let chunk = b"data: {\"choices\":[{\"delta\":{\"content\":\"Hi\"}}]}\n\ndata: [DONE]\n\n";
let values = decoder.decode(chunk);
assert_eq!(values.len(), 1);
}
#[test]
fn test_sse_empty_lines_ignored() {
let mut decoder = SseDecoder::new();
let chunk = b"\n\n\ndata: {\"x\":1}\n\n\n\n";
let values = decoder.decode(chunk);
assert_eq!(values.len(), 1);
assert_eq!(values[0]["x"], 1);
}
#[test]
fn test_sse_event_lines_ignored() {
let mut decoder = SseDecoder::new();
let chunk = b"event: message\ndata: {\"x\":1}\n\n";
let values = decoder.decode(chunk);
assert_eq!(values.len(), 1);
}
#[test]
fn test_sse_split_across_chunks() {
let mut decoder = SseDecoder::new();
let v1 = decoder.decode(b"data: {\"cho");
assert!(v1.is_empty());
let v2 = decoder.decode(b"ices\":[{\"delta\":{\"content\":\"Hi\"}}]}\n\n");
assert_eq!(v2.len(), 1);
}
#[test]
fn test_sse_multiple_events() {
let mut decoder = SseDecoder::new();
let chunk = b"data: {\"a\":1}\n\ndata: {\"a\":2}\n\ndata: {\"a\":3}\n\ndata: [DONE]\n\n";
let values = decoder.decode(chunk);
assert_eq!(values.len(), 3);
}
}