use std::{
future::Future,
pin::Pin,
task::{Context, Poll},
time::Duration,
};
use bytes::Bytes;
use tokio::time::{Instant, Sleep};
use topcoat_core::error::Result;
use crate::content::sse::Event;
#[derive(Clone, Debug)]
#[must_use]
pub struct KeepAlive {
event: Event,
interval: Duration,
}
impl KeepAlive {
pub fn new() -> Self {
const DEFAULT_INTERVAL: Duration = Duration::from_secs(15);
Self {
event: Event::new().comment(""),
interval: DEFAULT_INTERVAL,
}
}
pub fn interval(mut self, interval: Duration) -> Self {
self.interval = interval;
self
}
pub fn text(self, text: impl Into<String>) -> Self {
self.event(Event::new().comment(text))
}
pub fn event(mut self, event: Event) -> Self {
self.event = event;
self
}
pub(super) fn into_timer(self) -> Result<KeepAliveTimer> {
Ok(KeepAliveTimer {
frame: self.event.serialize()?,
interval: self.interval,
sleep: None,
})
}
}
impl Default for KeepAlive {
fn default() -> Self {
Self::new()
}
}
pub(super) struct KeepAliveTimer {
frame: Bytes,
interval: Duration,
sleep: Option<Pin<Box<Sleep>>>,
}
impl KeepAliveTimer {
pub(super) fn poll_frame(&mut self, cx: &mut Context<'_>) -> Poll<Bytes> {
let sleep = self
.sleep
.get_or_insert_with(|| Box::pin(tokio::time::sleep(self.interval)));
match sleep.as_mut().poll(cx) {
Poll::Ready(()) => {
sleep.as_mut().reset(Instant::now() + self.interval);
Poll::Ready(self.frame.clone())
}
Poll::Pending => Poll::Pending,
}
}
pub(super) fn defer(&mut self) {
if let Some(sleep) = &mut self.sleep {
sleep.as_mut().reset(Instant::now() + self.interval);
}
}
}