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