use axum::response::sse::Event;
use serde::Serialize;
use std::time::Duration;
pub trait SseEventExt {
fn json<T: Serialize>(data: &T) -> Result<Event, serde_json::Error>;
fn json_named<T: Serialize>(event_name: &str, data: &T) -> Result<Event, serde_json::Error>;
}
impl SseEventExt for Event {
fn json<T: Serialize>(data: &T) -> Result<Event, serde_json::Error> {
let json = serde_json::to_string(data)?;
Ok(Event::default().data(json))
}
fn json_named<T: Serialize>(event_name: &str, data: &T) -> Result<Event, serde_json::Error> {
let json = serde_json::to_string(data)?;
Ok(Event::default().event(event_name).data(json))
}
}
#[derive(Debug, Clone)]
pub struct TypedEvent<T> {
pub event_type: Option<String>,
pub id: Option<String>,
pub retry: Option<Duration>,
pub data: T,
}
impl<T: Serialize> TypedEvent<T> {
#[must_use]
pub fn new(data: T) -> Self {
Self {
event_type: None,
id: None,
retry: None,
data,
}
}
#[must_use]
pub fn event_type(mut self, name: impl Into<String>) -> Self {
self.event_type = Some(name.into());
self
}
#[must_use]
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
#[must_use]
pub fn retry(mut self, retry: Duration) -> Self {
self.retry = Some(retry);
self
}
pub fn into_event(self) -> Result<Event, serde_json::Error> {
let json = serde_json::to_string(&self.data)?;
let mut event = Event::default().data(json);
if let Some(name) = self.event_type {
event = event.event(name);
}
if let Some(id) = self.id {
event = event.id(id);
}
if let Some(retry) = self.retry {
event = event.retry(retry);
}
Ok(event)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Serialize)]
struct TestData {
message: String,
}
#[test]
fn test_event_json() {
let data = TestData {
message: "Hello".to_string(),
};
let event = Event::json(&data);
assert!(event.is_ok());
}
#[test]
fn test_event_json_named() {
let data = TestData {
message: "Hello".to_string(),
};
let event = Event::json_named("test", &data);
assert!(event.is_ok());
}
#[test]
fn test_typed_event() {
let event = TypedEvent::new(TestData {
message: "Hello".to_string(),
})
.event_type("notification")
.id("event-1")
.retry(Duration::from_secs(5));
assert_eq!(event.event_type, Some("notification".to_string()));
assert_eq!(event.id, Some("event-1".to_string()));
assert_eq!(event.retry, Some(Duration::from_secs(5)));
let axum_event = event.into_event();
assert!(axum_event.is_ok());
}
}