1use std::collections::VecDeque;
30use std::fmt;
31#[cfg(feature = "time")]
32use std::future::Future;
33use std::marker::PhantomData;
34use std::pin::Pin;
35use std::task::{Context, Poll};
36
37use futures_core::Stream;
38use serde::de::DeserializeOwned;
39
40use crate::{Error, MaybeSend, Response};
41
42pub const DONE: &str = "[DONE]";
44
45#[derive(Clone, Debug, Default, PartialEq, Eq)]
47pub struct Event {
48 pub event: Option<String>,
50 pub data: String,
52 pub id: Option<String>,
54}
55
56#[derive(Clone, Debug, Default)]
60pub struct Decoder {
61 buffer: Vec<u8>,
62 after_cr: bool,
63 started: bool,
64 event: Option<String>,
65 data: String,
66 has_data: bool,
67 id: Option<String>,
68}
69
70impl Decoder {
71 pub fn new() -> Self {
73 Self::default()
74 }
75
76 pub fn feed(&mut self, chunk: &[u8], events: &mut VecDeque<Event>) {
78 let mut chunk = chunk;
79 if !self.started {
80 let pending = self.buffer.len() + chunk.len();
82 let mut head = self.buffer.clone();
83 head.extend_from_slice(&chunk[..chunk.len().min(3)]);
84 if pending < 3 && b"\xEF\xBB\xBF".starts_with(&head) {
85 self.buffer.extend_from_slice(chunk);
86 return;
87 }
88 self.started = true;
89 let mut all = std::mem::take(&mut self.buffer);
90 all.extend_from_slice(chunk);
91 let rest = all.strip_prefix(b"\xEF\xBB\xBF").unwrap_or(&all).to_vec();
92 self.feed_lines(&rest, events);
93 return;
94 }
95 if self.after_cr {
96 if let Some(rest) = chunk.strip_prefix(b"\n") {
97 chunk = rest;
98 }
99 self.after_cr = false;
100 }
101 self.feed_lines(chunk, events);
102 }
103
104 fn feed_lines(&mut self, chunk: &[u8], events: &mut VecDeque<Event>) {
105 let mut start = 0;
106 let mut i = 0;
107 while i < chunk.len() {
108 match chunk[i] {
109 b'\n' | b'\r' => {
110 let mut line = std::mem::take(&mut self.buffer);
111 line.extend_from_slice(&chunk[start..i]);
112 self.line(&line, events);
113 if chunk[i] == b'\r' {
114 if i + 1 < chunk.len() {
115 if chunk[i + 1] == b'\n' {
116 i += 1;
117 }
118 } else {
119 self.after_cr = true;
120 }
121 }
122 start = i + 1;
123 }
124 _ => {}
125 }
126 i += 1;
127 }
128 self.buffer.extend_from_slice(&chunk[start..]);
129 }
130
131 fn line(&mut self, line: &[u8], events: &mut VecDeque<Event>) {
132 if line.is_empty() {
133 if self.has_data {
134 events.push_back(Event {
135 event: self.event.take(),
136 data: std::mem::take(&mut self.data),
137 id: self.id.clone(),
138 });
139 }
140 self.event = None;
141 self.data.clear();
142 self.has_data = false;
143 return;
144 }
145 if line[0] == b':' {
146 return;
147 }
148 let line = String::from_utf8_lossy(line);
149 let (field, value) = match line.find(':') {
150 Some(colon) => {
151 let value = &line[colon + 1..];
152 (&line[..colon], value.strip_prefix(' ').unwrap_or(value))
153 }
154 None => (&line[..], ""),
155 };
156 match field {
157 "data" => {
158 if self.has_data {
159 self.data.push('\n');
160 }
161 self.data.push_str(value);
162 self.has_data = true;
163 }
164 "event" => self.event = Some(value.to_owned()),
165 "id" if !value.contains('\0') => self.id = Some(value.to_owned()),
166 _ => {}
167 }
168 }
169
170 pub fn finish(&mut self) {
172 self.buffer.clear();
173 self.event = None;
174 self.data.clear();
175 self.has_data = false;
176 }
177}
178
179pub struct Events {
182 bytes: Option<Body>,
183 decoder: Decoder,
184 ready: VecDeque<Event>,
185 #[cfg(feature = "time")]
186 idle: Option<Idle>,
187}
188
189#[cfg(feature = "time")]
192struct Idle {
193 limit: std::time::Duration,
194 timer: Option<crate::timer::Sleep>,
195}
196
197#[cfg(not(target_family = "wasm"))]
198type Chunk = Box<dyn AsRef<[u8]> + Send>;
199#[cfg(target_family = "wasm")]
200type Chunk = Box<dyn AsRef<[u8]>>;
201type Body = crate::maybe::BoxStream<'static, Result<Chunk, Error>>;
202
203impl Events {
204 pub fn from_response(response: Response) -> Self {
206 Self::from_bytes(response.bytes_stream())
207 }
208
209 pub fn from_bytes<S, B>(bytes: S) -> Self
212 where
213 S: Stream<Item = Result<B, Error>> + MaybeSend + 'static,
214 B: AsRef<[u8]> + MaybeSend + 'static,
215 {
216 Self {
217 bytes: Some(Box::pin(Chunks(Box::pin(bytes)))),
218 decoder: Decoder::new(),
219 ready: VecDeque::new(),
220 #[cfg(feature = "time")]
221 idle: None,
222 }
223 }
224
225 #[cfg(feature = "time")]
238 pub fn idle_timeout(mut self, limit: std::time::Duration) -> Self {
239 self.idle = Some(Idle { limit, timer: None });
240 self
241 }
242
243 #[cfg(feature = "time")]
245 fn idle(&mut self, cx: &mut Context<'_>, reset: bool) -> Option<Error> {
246 let idle = self.idle.as_mut()?;
247 let deadline = crate::timer::Instant::now() + idle.limit;
248 match &mut idle.timer {
249 Some(timer) if reset => timer.reset(deadline),
250 Some(_) => {}
251 None => idle.timer = Some(crate::timer::Sleep::until(deadline)),
252 }
253 if reset {
254 return None;
255 }
256 let timer = idle.timer.as_mut()?;
257 match Pin::new(timer).poll(cx) {
258 Poll::Ready(()) => Some(Error::body(crate::error::TimedOut(format!(
259 "no server-sent event data for {:?}",
260 idle.limit
261 )))),
262 Poll::Pending => None,
263 }
264 }
265}
266
267impl Stream for Events {
268 type Item = Result<Event, Error>;
269
270 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
271 let this = &mut *self;
272 loop {
273 if let Some(event) = this.ready.pop_front() {
274 if event.data == DONE {
275 this.ready.clear();
276 this.bytes = None;
277 return Poll::Ready(None);
278 }
279 return Poll::Ready(Some(Ok(event)));
280 }
281 let Some(bytes) = this.bytes.as_mut() else {
282 return Poll::Ready(None);
283 };
284 match bytes.as_mut().poll_next(cx) {
285 Poll::Pending => {
286 #[cfg(feature = "time")]
287 if let Some(error) = this.idle(cx, false) {
288 this.bytes = None;
289 this.decoder.finish();
290 this.ready.clear();
291 return Poll::Ready(Some(Err(error)));
292 }
293 return Poll::Pending;
294 }
295 Poll::Ready(Some(Ok(chunk))) => {
296 #[cfg(feature = "time")]
297 this.idle(cx, true);
298 this.decoder.feed((*chunk).as_ref(), &mut this.ready)
299 }
300 Poll::Ready(Some(Err(error))) => {
301 this.bytes = None;
302 this.decoder.finish();
303 return Poll::Ready(Some(Err(error)));
304 }
305 Poll::Ready(None) => {
306 this.bytes = None;
307 this.decoder.finish();
308 }
309 }
310 }
311 }
312}
313
314impl fmt::Debug for Events {
315 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316 let mut debug = f.debug_struct("Events");
317 #[cfg(feature = "time")]
318 debug.field("idle_timeout", &self.idle.as_ref().map(|idle| idle.limit));
319 debug
320 .field("open", &self.bytes.is_some())
321 .field("ready", &self.ready)
322 .finish_non_exhaustive()
323 }
324}
325
326struct Chunks<S>(Pin<Box<S>>);
328
329impl<S, B> Stream for Chunks<S>
330where
331 S: Stream<Item = Result<B, Error>>,
332 B: AsRef<[u8]> + MaybeSend + 'static,
333{
334 type Item = Result<Chunk, Error>;
335
336 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
337 self.0
338 .as_mut()
339 .poll_next(cx)
340 .map(|item| item.map(|chunk| chunk.map(|bytes| Box::new(bytes) as Chunk)))
341 }
342}
343
344impl Events {
345 pub fn json<T: DeserializeOwned>(self) -> JsonEvents<T> {
351 JsonEvents {
352 events: self,
353 types: PhantomData,
354 }
355 }
356}
357
358pub struct JsonEvents<T> {
360 events: Events,
361 types: PhantomData<fn() -> T>,
362}
363
364impl<T> JsonEvents<T> {
365 pub fn into_events(self) -> Events {
367 self.events
368 }
369}
370
371impl<T: DeserializeOwned> Stream for JsonEvents<T> {
372 type Item = Result<T, Error>;
373
374 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
375 loop {
376 match Pin::new(&mut self.events).poll_next(cx) {
377 Poll::Ready(Some(Ok(event))) if event.data.trim().is_empty() => {}
378 Poll::Ready(Some(Ok(event))) => {
379 return Poll::Ready(Some(
380 serde_json::from_str(&event.data).map_err(Error::decode),
381 ));
382 }
383 Poll::Ready(Some(Err(error))) => return Poll::Ready(Some(Err(error))),
384 Poll::Ready(None) => return Poll::Ready(None),
385 Poll::Pending => return Poll::Pending,
386 }
387 }
388 }
389}
390
391impl<T> fmt::Debug for JsonEvents<T> {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 f.debug_struct("JsonEvents")
394 .field("events", &self.events)
395 .finish()
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402 use futures_util::StreamExt;
403
404 fn events(chunks: &[&'static str]) -> Events {
405 let chunks: Vec<Result<&'static [u8], Error>> =
406 chunks.iter().map(|chunk| Ok(chunk.as_bytes())).collect();
407 Events::from_bytes(futures_util::stream::iter(chunks))
408 }
409
410 #[test]
411 fn parses_across_chunks_and_line_endings() {
412 let mut decoder = Decoder::new();
413 let mut out = VecDeque::new();
414 decoder.feed(b"\xEF\xBB\xBFevent: a\r", &mut out);
415 decoder.feed(b"\ndata: 1\r\ndata:", &mut out);
416 decoder.feed(b"2\n: comment\nid: 7\n\ndata: x\n", &mut out);
417 decoder.finish();
418 assert_eq!(
419 out.into_iter().collect::<Vec<_>>(),
420 vec![Event {
421 event: Some("a".into()),
422 data: "1\n2".into(),
423 id: Some("7".into()),
424 }]
425 );
426 }
427
428 #[tokio::test]
429 async fn done_ends_the_stream() {
430 let data: Vec<_> = events(&["data: 1\n\n", "data: [DONE]\n\ndata: 2\n\n"])
431 .map(|event| event.unwrap().data)
432 .collect()
433 .await;
434 assert_eq!(data, vec!["1"]);
435 }
436
437 #[cfg(feature = "time")]
438 #[tokio::test(start_paused = true)]
439 async fn an_idle_stream_times_out() {
440 use std::time::Duration;
441 let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::<Result<&'static [u8], Error>>();
442 let rx = futures_util::stream::poll_fn(move |cx| rx.poll_recv(cx));
443 let mut events = Events::from_bytes(rx).idle_timeout(Duration::from_secs(10));
444 tx.send(Ok(b"data: 1\n\n".as_slice())).unwrap();
445 assert_eq!(events.next().await.unwrap().unwrap().data, "1");
446 tokio::time::sleep(Duration::from_secs(8)).await;
447 tx.send(Ok(b": ping\n".as_slice())).unwrap();
449 tokio::time::sleep(Duration::from_secs(8)).await;
450 tx.send(Ok(b"data: 2\n\n".as_slice())).unwrap();
451 assert_eq!(events.next().await.unwrap().unwrap().data, "2");
452 let started = tokio::time::Instant::now();
453 let error = events.next().await.unwrap().unwrap_err();
454 assert!(error.is_timeout() && error.is_body(), "{error:?}");
455 assert_eq!(started.elapsed(), Duration::from_secs(10));
456 assert!(events.next().await.is_none());
457 drop(tx);
458 }
459
460 #[tokio::test]
461 async fn decodes_json_and_goes_on_after_a_bad_payload() {
462 #[derive(serde::Deserialize, Debug, PartialEq)]
463 struct Chunk {
464 n: u32,
465 }
466 let items: Vec<_> =
467 events(&["data: {\"n\":1}\n\ndata: oops\n\ndata:\n\ndata: {\"n\":2}\n\n"])
468 .json::<Chunk>()
469 .collect()
470 .await;
471 assert_eq!(items.len(), 3);
472 assert_eq!(items[0].as_ref().unwrap(), &Chunk { n: 1 });
473 assert!(items[1].as_ref().unwrap_err().is_decode());
474 assert_eq!(items[2].as_ref().unwrap(), &Chunk { n: 2 });
475 }
476}