#[cfg(test)]
mod tests;
use crate::core::New;
use crate::header::Header;
use crate::range::Range;
use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
pub struct SseEvent {
id: Option<String>,
event: Option<String>,
data: String,
retry_ms: Option<u32>,
}
impl SseEvent {
pub fn data(data: impl Into<String>) -> Self {
SseEvent { id: None, event: None, data: data.into(), retry_ms: None }
}
pub fn id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
pub fn event_type(mut self, event: impl Into<String>) -> Self {
self.event = Some(event.into());
self
}
pub fn retry(mut self, ms: u32) -> Self {
self.retry_ms = Some(ms);
self
}
pub fn encode(&self) -> Vec<u8> {
let mut out = String::new();
if let Some(id) = &self.id {
out.push_str("id: ");
out.push_str(id);
out.push('\n');
}
if let Some(event) = &self.event {
out.push_str("event: ");
out.push_str(event);
out.push('\n');
}
for line in self.data.lines() {
out.push_str("data: ");
out.push_str(line);
out.push('\n');
}
if self.data.is_empty() {
out.push_str("data: \n");
}
if let Some(ms) = self.retry_ms {
out.push_str("retry: ");
out.push_str(&ms.to_string());
out.push('\n');
}
out.push('\n');
out.into_bytes()
}
}
pub struct Sse {
chunks: Vec<Vec<u8>>,
}
impl Sse {
pub fn new() -> Self {
Sse { chunks: Vec::new() }
}
pub fn event(mut self, event_type: &str, data: &str) -> Self {
self.chunks.push(
SseEvent::data(data).event_type(event_type).encode(),
);
self
}
pub fn data(mut self, data: &str) -> Self {
self.chunks.push(SseEvent::data(data).encode());
self
}
pub fn push(mut self, event: SseEvent) -> Self {
self.chunks.push(event.encode());
self
}
pub fn retry(mut self, ms: u32) -> Self {
self.chunks.push(format!("retry: {}\n\n", ms).into_bytes());
self
}
pub fn comment(mut self, text: &str) -> Self {
self.chunks.push(format!(": {}\n\n", text).into_bytes());
self
}
pub fn into_response(self) -> Response {
let body: Vec<u8> = self.chunks.into_iter().flatten().collect();
let mut response = Response::new();
response.status_code = *STATUS_CODE_REASON_PHRASE.n200_ok.status_code;
response.reason_phrase =
STATUS_CODE_REASON_PHRASE.n200_ok.reason_phrase.to_string();
response.headers.push(Header {
name: Header::_CACHE_CONTROL.to_string(),
value: "no-cache".to_string(),
});
response.headers.push(Header {
name: "X-Accel-Buffering".to_string(),
value: "no".to_string(),
});
response.content_range_list = vec![Range::get_content_range(
body,
"text/event-stream".to_string(),
)];
response
}
}