use std::time::Duration;
use axum::response::sse::Event as AxumSseEvent;
#[derive(Debug, Clone, Default)]
pub struct SseEvent {
data: Option<String>,
event: Option<String>,
id: Option<String>,
retry: Option<Duration>,
comment: Option<String>,
}
impl SseEvent {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn data(mut self, data: impl Into<String>) -> Self {
self.data = Some(data.into());
self
}
#[must_use]
pub fn json<T: serde::Serialize>(mut self, value: &T) -> Self {
self.data = Some(
serde_json::to_string(value).unwrap_or_else(|e| format!("{{\"error\":\"{e}\"}}")),
);
self
}
#[must_use]
pub fn event(mut self, event: impl Into<String>) -> Self {
self.event = Some(event.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, duration: Duration) -> Self {
self.retry = Some(duration);
self
}
#[must_use]
pub fn comment(mut self, comment: impl Into<String>) -> Self {
self.comment = Some(comment.into());
self
}
pub fn get_data(&self) -> Option<&str> {
self.data.as_deref()
}
pub fn get_event(&self) -> Option<&str> {
self.event.as_deref()
}
pub fn get_id(&self) -> Option<&str> {
self.id.as_deref()
}
pub fn get_retry(&self) -> Option<Duration> {
self.retry
}
pub fn get_comment(&self) -> Option<&str> {
self.comment.as_deref()
}
pub fn into_axum_event(self) -> AxumSseEvent {
let mut evt = AxumSseEvent::default();
if let Some(data) = self.data {
evt = evt.data(data);
}
if let Some(event) = self.event {
evt = evt.event(event);
}
if let Some(id) = self.id {
evt = evt.id(id);
}
if let Some(retry) = self.retry {
evt = evt.retry(retry);
}
if let Some(comment) = self.comment {
evt = evt.comment(comment);
}
evt
}
}
pub struct SseSender {
tx: tokio::sync::mpsc::Sender<SseEvent>,
}
impl SseSender {
pub fn new(tx: tokio::sync::mpsc::Sender<SseEvent>) -> Self {
Self { tx }
}
pub async fn send(&self, event: SseEvent) -> Result<(), tokio::sync::mpsc::error::SendError<SseEvent>> {
self.tx.send(event).await
}
}