qubit_http/sse/sse_event.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # SSE event record
10//!
11//! One dispatch after frame reassembly (`data:` lines joined with `\n`).
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use serde::de::DeserializeOwned;
18
19use super::SseJsonMode;
20use crate::{HttpError, HttpResult};
21
22/// One Server-Sent Events dispatch after frame reassembly (`data:` lines joined with `\n`).
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct SseEvent {
25 /// `event:` field if present.
26 pub event: Option<String>,
27 /// Concatenated `data:` payload (newline-separated if multiple `data` lines).
28 pub data: String,
29 /// `id:` field if present.
30 pub id: Option<String>,
31 /// Parsed `retry:` milliseconds hint if valid.
32 pub retry: Option<u64>,
33}
34
35impl SseEvent {
36 /// Decodes the current event's `data` payload as JSON.
37 ///
38 /// # Type parameters
39 /// - `T`: Target type deserialized from [`SseEvent::data`].
40 ///
41 /// # Returns
42 /// `Ok(T)` when `data` is valid JSON for `T`.
43 ///
44 /// # Errors
45 /// Returns [`HttpError::sse_decode`] when JSON parsing fails.
46 /// The error message includes optional `event` and `id` context.
47 pub fn decode_json<T>(&self) -> HttpResult<T>
48 where
49 T: DeserializeOwned,
50 {
51 serde_json::from_str::<T>(&self.data).map_err(|error| {
52 HttpError::sse_decode(format!(
53 "Failed to decode SSE event data as JSON (event={:?}, id={:?}): {}",
54 self.event, self.id, error
55 ))
56 })
57 }
58
59 /// Decodes the current event's `data` payload as JSON with configurable strictness.
60 ///
61 /// # Parameters
62 /// - `mode`: JSON decoding strictness.
63 ///
64 /// # Type parameters
65 /// - `T`: Target type deserialized from [`SseEvent::data`].
66 ///
67 /// # Returns
68 /// - `Ok(Some(T))` when `data` is valid JSON for `T`.
69 /// - `Ok(None)` in lenient mode when JSON parsing fails.
70 ///
71 /// # Errors
72 /// Returns [`HttpError::sse_decode`] in strict mode when JSON parsing fails.
73 pub fn decode_json_with_mode<T>(&self, mode: SseJsonMode) -> HttpResult<Option<T>>
74 where
75 T: DeserializeOwned,
76 {
77 match mode {
78 SseJsonMode::Strict => self.decode_json::<T>().map(Some),
79 SseJsonMode::Lenient => match serde_json::from_str::<T>(&self.data) {
80 Ok(value) => Ok(Some(value)),
81 Err(error) => {
82 tracing::debug!(
83 "Skipping malformed SSE event JSON in lenient mode (event={:?}, id={:?}): {}",
84 self.event,
85 self.id,
86 error
87 );
88 Ok(None)
89 }
90 },
91 }
92 }
93}