1#[cfg(not(feature = "std"))]
2use alloc::string::{FromUtf8Error, String, ToString};
3
4#[cfg(feature = "std")]
5use std::string::FromUtf8Error;
6
7use crate::event::Event;
8use crate::parser::{is_bom, is_lf, line, RawEventLine};
9use crate::utf8_stream::{Utf8Stream, Utf8StreamError};
10use core::fmt;
11use core::pin::Pin;
12use core::time::Duration;
13use futures_core::stream::Stream;
14use futures_core::task::{Context, Poll};
15use pin_project_lite::pin_project;
16
17#[derive(Default, Debug)]
18struct EventBuilder {
19 event: Event,
20 is_complete: bool,
21}
22
23impl EventBuilder {
24 fn add(&mut self, line: RawEventLine) {
45 match line {
46 RawEventLine::Field(field, val) => {
47 let val = val.unwrap_or("");
48 match field {
49 "event" => {
50 self.event.event = val.to_string();
51 }
52 "data" => {
53 self.event.data.push_str(val);
54 self.event.data.push('\u{000A}');
55 }
56 "id" => {
57 if !val.contains('\u{0000}') {
58 self.event.id = val.to_string()
59 }
60 }
61 "retry" => {
62 if let Ok(val) = val.parse::<u64>() {
63 self.event.retry = Some(Duration::from_millis(val))
64 }
65 }
66 _ => {}
67 }
68 }
69 RawEventLine::Comment => {}
70 RawEventLine::Empty => self.is_complete = true,
71 }
72 }
73
74 fn dispatch(&mut self) -> Option<Event> {
85 let builder = core::mem::take(self);
86 let mut event = builder.event;
87 self.event.id = event.id.clone();
88
89 if event.data.is_empty() {
90 return None;
91 }
92
93 if is_lf(event.data.chars().next_back().unwrap()) {
94 event.data.pop();
95 }
96
97 if event.event.is_empty() {
98 event.event = "message".to_string();
99 }
100
101 Some(event)
102 }
103}
104
105#[derive(Debug, Clone, Copy)]
106pub enum EventStreamState {
107 NotStarted,
108 Started,
109 Terminated,
110}
111
112impl EventStreamState {
113 fn is_terminated(self) -> bool {
114 matches!(self, Self::Terminated)
115 }
116 fn is_started(self) -> bool {
117 matches!(self, Self::Started)
118 }
119}
120
121pin_project! {
122 pub struct EventStream<S> {
124 #[pin]
125 stream: Utf8Stream<S>,
126 buffer: String,
127 builder: EventBuilder,
128 state: EventStreamState,
129 last_event_id: String,
130 already_scanned: usize,
131 }
132}
133
134impl<S> EventStream<S> {
135 pub fn new(stream: S) -> Self {
137 Self {
138 stream: Utf8Stream::new(stream),
139 buffer: String::new(),
140 builder: EventBuilder::default(),
141 state: EventStreamState::NotStarted,
142 last_event_id: String::new(),
143 already_scanned: 0,
144 }
145 }
146
147 pub fn set_last_event_id(&mut self, id: impl Into<String>) {
150 self.last_event_id = id.into();
151 }
152
153 pub fn last_event_id(&self) -> &str {
155 &self.last_event_id
156 }
157}
158
159#[derive(Debug, PartialEq)]
161pub enum EventStreamError<E> {
162 Utf8(FromUtf8Error),
164 Transport(E),
166}
167
168impl<E> From<Utf8StreamError<E>> for EventStreamError<E> {
169 fn from(err: Utf8StreamError<E>) -> Self {
170 match err {
171 Utf8StreamError::Utf8(err) => Self::Utf8(err),
172 Utf8StreamError::Transport(err) => Self::Transport(err),
173 }
174 }
175}
176
177impl<E> fmt::Display for EventStreamError<E>
178where
179 E: fmt::Display,
180{
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 match self {
183 Self::Utf8(err) => f.write_fmt(format_args!("UTF8 error: {}", err)),
184 Self::Transport(err) => f.write_fmt(format_args!("Transport error: {}", err)),
185 }
186 }
187}
188
189#[cfg(feature = "std")]
190impl<E> std::error::Error for EventStreamError<E> where E: fmt::Display + fmt::Debug + Send + Sync {}
191
192fn parse_event(
193 buffer: &mut String,
194 builder: &mut EventBuilder,
195 already_scanned: &mut usize,
196) -> Option<Event> {
197 if buffer.is_empty() {
198 return None;
199 }
200 loop {
201 let (rem, next_line) = line(buffer.as_ref(), *already_scanned)
202 .inspect_err(|resume_from| *already_scanned = *resume_from)
203 .ok()?;
204 builder.add(next_line);
205 let consumed = buffer.len() - rem.len();
206 let rem = buffer.split_off(consumed);
207
208 *already_scanned = 0;
209 *buffer = rem;
210 if builder.is_complete {
211 if let Some(event) = builder.dispatch() {
212 return Some(event);
213 }
214 }
215 }
216}
217
218impl<S, B, E> Stream for EventStream<S>
219where
220 S: Stream<Item = Result<B, E>>,
221 B: AsRef<[u8]>,
222{
223 type Item = Result<Event, EventStreamError<E>>;
224
225 fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
226 let mut this = self.project();
227
228 if let Some(event) = parse_event(this.buffer, this.builder, this.already_scanned) {
229 *this.last_event_id = event.id.clone();
230 return Poll::Ready(Some(Ok(event)));
231 }
232
233 if this.state.is_terminated() {
234 return Poll::Ready(None);
235 }
236
237 loop {
238 match this.stream.as_mut().poll_next(cx) {
239 Poll::Ready(Some(Ok(string))) => {
240 if string.is_empty() {
241 continue;
242 }
243
244 let slice = if this.state.is_started() {
245 &string
246 } else {
247 *this.state = EventStreamState::Started;
248 if is_bom(string.chars().next().unwrap()) {
249 &string[3..]
250 } else {
251 &string
252 }
253 };
254 this.buffer.push_str(slice);
255
256 if let Some(event) =
257 parse_event(this.buffer, this.builder, this.already_scanned)
258 {
259 *this.last_event_id = event.id.clone();
260 return Poll::Ready(Some(Ok(event)));
261 }
262 }
263 Poll::Ready(Some(Err(err))) => return Poll::Ready(Some(Err(err.into()))),
264 Poll::Ready(None) => {
265 *this.state = EventStreamState::Terminated;
266 return Poll::Ready(None);
267 }
268 Poll::Pending => return Poll::Pending,
269 }
270 }
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277 use futures::prelude::*;
278
279 #[tokio::test]
280 async fn valid_data_fields() {
281 assert_eq!(
282 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
283 "data: Hello, world!\n\n"
284 )]))
285 .try_collect::<Vec<_>>()
286 .await
287 .unwrap(),
288 vec![Event {
289 event: "message".to_string(),
290 data: "Hello, world!".to_string(),
291 ..Default::default()
292 }]
293 );
294 assert_eq!(
295 EventStream::new(futures::stream::iter(vec![
296 Ok::<_, ()>("data: Hello,"),
297 Ok::<_, ()>(" world!\n\n")
298 ]))
299 .try_collect::<Vec<_>>()
300 .await
301 .unwrap(),
302 vec![Event {
303 event: "message".to_string(),
304 data: "Hello, world!".to_string(),
305 ..Default::default()
306 }]
307 );
308 assert_eq!(
309 EventStream::new(futures::stream::iter(vec![
310 Ok::<_, ()>("data: Hello,"),
311 Ok::<_, ()>(""),
312 Ok::<_, ()>(" world!\n\n")
313 ]))
314 .try_collect::<Vec<_>>()
315 .await
316 .unwrap(),
317 vec![Event {
318 event: "message".to_string(),
319 data: "Hello, world!".to_string(),
320 ..Default::default()
321 }]
322 );
323 assert_eq!(
324 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
325 "data: Hello, world!\n"
326 )]))
327 .try_collect::<Vec<_>>()
328 .await
329 .unwrap(),
330 vec![]
331 );
332 assert_eq!(
333 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
334 "data: Hello,\ndata: world!\n\n"
335 )]))
336 .try_collect::<Vec<_>>()
337 .await
338 .unwrap(),
339 vec![Event {
340 event: "message".to_string(),
341 data: "Hello,\nworld!".to_string(),
342 ..Default::default()
343 }]
344 );
345 assert_eq!(
346 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
347 "data: Hello,\n\ndata: world!\n\n"
348 )]))
349 .try_collect::<Vec<_>>()
350 .await
351 .unwrap(),
352 vec![
353 Event {
354 event: "message".to_string(),
355 data: "Hello,".to_string(),
356 ..Default::default()
357 },
358 Event {
359 event: "message".to_string(),
360 data: "world!".to_string(),
361 ..Default::default()
362 }
363 ]
364 );
365 }
366
367 #[tokio::test]
368 async fn spec_examples() {
369 assert_eq!(
370 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
371 "data: This is the first message.
372
373data: This is the second message, it
374data: has two lines.
375
376data: This is the third message.
377
378"
379 )]))
380 .try_collect::<Vec<_>>()
381 .await
382 .unwrap(),
383 vec![
384 Event {
385 event: "message".to_string(),
386 data: "This is the first message.".to_string(),
387 ..Default::default()
388 },
389 Event {
390 event: "message".to_string(),
391 data: "This is the second message, it\nhas two lines.".to_string(),
392 ..Default::default()
393 },
394 Event {
395 event: "message".to_string(),
396 data: "This is the third message.".to_string(),
397 ..Default::default()
398 }
399 ]
400 );
401 assert_eq!(
402 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
403 "event: add
404data: 73857293
405
406event: remove
407data: 2153
408
409event: add
410data: 113411
411
412"
413 )]))
414 .try_collect::<Vec<_>>()
415 .await
416 .unwrap(),
417 vec![
418 Event {
419 event: "add".to_string(),
420 data: "73857293".to_string(),
421 ..Default::default()
422 },
423 Event {
424 event: "remove".to_string(),
425 data: "2153".to_string(),
426 ..Default::default()
427 },
428 Event {
429 event: "add".to_string(),
430 data: "113411".to_string(),
431 ..Default::default()
432 }
433 ]
434 );
435 assert_eq!(
436 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
437 "data: YHOO
438data: +2
439data: 10
440
441"
442 )]))
443 .try_collect::<Vec<_>>()
444 .await
445 .unwrap(),
446 vec![Event {
447 event: "message".to_string(),
448 data: "YHOO\n+2\n10".to_string(),
449 ..Default::default()
450 },]
451 );
452 assert_eq!(
453 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
454 ": test stream
455
456data: first event
457id: 1
458
459data:second event
460id
461
462data: third event
463
464"
465 )]))
466 .try_collect::<Vec<_>>()
467 .await
468 .unwrap(),
469 vec![
470 Event {
471 event: "message".to_string(),
472 id: "1".to_string(),
473 data: "first event".to_string(),
474 ..Default::default()
475 },
476 Event {
477 event: "message".to_string(),
478 data: "second event".to_string(),
479 ..Default::default()
480 },
481 Event {
482 event: "message".to_string(),
483 data: " third event".to_string(),
484 ..Default::default()
485 }
486 ]
487 );
488 assert_eq!(
489 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
490 "data
491
492data
493data
494
495data:
496"
497 )]))
498 .try_collect::<Vec<_>>()
499 .await
500 .unwrap(),
501 vec![
502 Event {
503 event: "message".to_string(),
504 data: "".to_string(),
505 ..Default::default()
506 },
507 Event {
508 event: "message".to_string(),
509 data: "\n".to_string(),
510 ..Default::default()
511 },
512 ]
513 );
514 assert_eq!(
515 EventStream::new(futures::stream::iter(vec![Ok::<_, ()>(
516 "data:test
517
518data: test
519
520"
521 )]))
522 .try_collect::<Vec<_>>()
523 .await
524 .unwrap(),
525 vec![
526 Event {
527 event: "message".to_string(),
528 data: "test".to_string(),
529 ..Default::default()
530 },
531 Event {
532 event: "message".to_string(),
533 data: "test".to_string(),
534 ..Default::default()
535 },
536 ]
537 );
538 }
539}