#[cfg(feature = "tcp-binder")]
pub mod tcp;
use async_trait::async_trait;
use log::{debug, trace};
use std::{
fmt::Debug,
future::Future,
io::{Error, ErrorKind, Result},
ops::{Deref, DerefMut},
sync::Arc,
time::Duration,
};
use tokio::{sync::Mutex, task, time};
use crate::{
handler::{self, Handler},
request::{Request, RequestReader},
response::{Response, ResponseWriter},
timer::{ThreadSafeTimer, TimerConfig, TimerCycle, TimerEvent, TimerLoop},
};
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub enum ServerState {
Running,
Stopping,
#[default]
Stopped,
}
pub struct ServerConfig {
handler: Arc<Handler<ServerEvent>>,
binders: Vec<Box<dyn ServerBind>>,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
handler: handler::default(),
binders: Vec::new(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ServerEvent {
Started,
Stopping,
Stopped,
}
#[derive(Clone, Debug, Default)]
pub struct ThreadSafeState(Arc<Mutex<ServerState>>);
impl ThreadSafeState {
pub fn new() -> Self {
Self::default()
}
async fn set(&self, next_state: ServerState) {
let mut state = self.lock().await;
*state = next_state;
}
pub async fn set_running(&self) {
self.set(ServerState::Running).await
}
pub async fn set_stopping(&self) {
self.set(ServerState::Stopping).await
}
pub async fn set_stopped(&self) {
self.set(ServerState::Stopped).await
}
}
impl Deref for ThreadSafeState {
type Target = Arc<Mutex<ServerState>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ThreadSafeState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[async_trait]
pub trait ServerBind: Debug + Send + Sync {
async fn bind(&self, timer: ThreadSafeTimer) -> Result<()>;
}
#[async_trait]
pub trait ServerStream: RequestReader + ResponseWriter {
async fn handle(&mut self, timer: ThreadSafeTimer) -> Result<()> {
let req = self.read().await?;
let res = match req {
Request::Start => {
debug!("starting timer");
timer.start().await?;
Response::Ok
}
Request::Get => {
debug!("getting timer");
let timer = timer.get().await;
trace!("{timer:#?}");
Response::Timer(timer)
}
Request::Set(duration) => {
debug!("setting timer");
timer.set(duration).await?;
Response::Ok
}
Request::Pause => {
debug!("pausing timer");
timer.pause().await?;
Response::Ok
}
Request::Resume => {
debug!("resuming timer");
timer.resume().await?;
Response::Ok
}
Request::Stop => {
debug!("stopping timer");
timer.stop().await?;
Response::Ok
}
};
self.write(res).await?;
Ok(())
}
}
impl<T: RequestReader + ResponseWriter> ServerStream for T {}
#[derive(Default)]
pub struct Server {
config: ServerConfig,
state: ThreadSafeState,
timer: ThreadSafeTimer,
}
impl Server {
pub async fn bind_with<F: Future<Output = Result<()>>>(
self,
wait: impl FnOnce() -> F + Send + Sync + 'static,
) -> Result<()> {
debug!("starting server");
let handler = &self.config.handler;
let fire_event = |event: ServerEvent| async move {
debug!("firing server event {event:?}");
if let Err(err) = handler(event.clone()).await {
debug!("error while firing server event, skipping it");
debug!("{err:?}");
}
};
self.state.set_running().await;
fire_event(ServerEvent::Started).await;
let state = self.state.clone();
let timer = self.timer.clone();
let tick = task::spawn(async move {
loop {
let mut state = state.lock().await;
match *state {
ServerState::Stopping => {
*state = ServerState::Stopped;
break;
}
ServerState::Stopped => {
break;
}
ServerState::Running => {
timer.update().await;
}
};
drop(state);
time::sleep(Duration::from_secs(1)).await;
}
});
for binder in self.config.binders {
let timer = self.timer.clone();
task::spawn(async move {
debug!("binding {binder:?}");
if let Err(err) = binder.bind(timer).await {
debug!("error while binding, skipping it");
debug!("{err:?}");
}
});
}
debug!("main loop started");
wait().await?;
debug!("main loop stopped");
self.state.set_stopping().await;
fire_event(ServerEvent::Stopping).await;
tick.await
.map_err(|_| Error::new(ErrorKind::Other, "cannot wait for timer thread"))?;
fire_event(ServerEvent::Stopped).await;
Ok(())
}
pub async fn bind(self) -> Result<()> {
self.bind_with(|| async {
loop {
time::sleep(Duration::from_secs(1)).await;
}
})
.await
}
}
#[derive(Default)]
pub struct ServerBuilder {
server_config: ServerConfig,
timer_config: TimerConfig,
}
impl ServerBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_server_config(mut self, config: ServerConfig) -> Self {
self.server_config = config;
self
}
pub fn with_timer_config(mut self, config: TimerConfig) -> Self {
self.timer_config = config;
self
}
pub fn with_pomodoro_config(mut self) -> Self {
let work = TimerCycle::new("Work", 25 * 60);
let short_break = TimerCycle::new("Short break", 5 * 60);
let long_break = TimerCycle::new("Long break", 15 * 60);
*self.timer_config.cycles = vec![
work.clone(),
short_break.clone(),
work.clone(),
short_break.clone(),
work.clone(),
short_break.clone(),
work.clone(),
short_break.clone(),
long_break,
];
self
}
pub fn with_52_17_config(mut self) -> Self {
let work = TimerCycle::new("Work", 52 * 60);
let rest = TimerCycle::new("Rest", 17 * 60);
*self.timer_config.cycles = vec![work, rest];
self
}
pub fn with_server_handler<F: Future<Output = Result<()>> + Send + 'static>(
mut self,
handler: impl Fn(ServerEvent) -> F + Send + Sync + 'static,
) -> Self {
self.server_config.handler = Arc::new(move |evt| Box::pin(handler(evt)));
self
}
pub fn with_binder(mut self, binder: Box<dyn ServerBind>) -> Self {
self.server_config.binders.push(binder);
self
}
pub fn with_timer_handler<F: Future<Output = Result<()>> + Send + 'static>(
mut self,
handler: impl Fn(TimerEvent) -> F + Sync + Send + 'static,
) -> Self {
self.timer_config.handler = Arc::new(move |evt| Box::pin(handler(evt)));
self
}
pub fn with_cycle<C>(mut self, cycle: C) -> Self
where
C: Into<TimerCycle>,
{
self.timer_config.cycles.push(cycle.into());
self
}
pub fn with_cycles<C, I>(mut self, cycles: I) -> Self
where
C: Into<TimerCycle>,
I: IntoIterator<Item = C>,
{
for cycle in cycles {
self.timer_config.cycles.push(cycle.into());
}
self
}
pub fn with_cycles_count(mut self, count: impl Into<TimerLoop>) -> Self {
self.timer_config.cycles_count = count.into();
self
}
pub fn build(self) -> Result<Server> {
Ok(Server {
config: self.server_config,
state: ThreadSafeState::new(),
timer: ThreadSafeTimer::new(self.timer_config)?,
})
}
}