use crate::csp::{
comm::{Responder, RxChan, VoidTx},
message::Message,
shutdown::NoShutdown,
};
use super::handler::Handler;
with_rt! {
use either::Either;
use crate::{
csp::{
comm::OutputTx,
shutdown::ShutdownRx,
},
utils::poll_biased::PollBiased,
};
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Server<H, X> {
pub handler: H,
pub rx: X,
}
pub struct ServeOptions<OTx, SRx> {
pub shutdown_rx: SRx,
pub output_tx: OTx,
}
impl<SRx> ServeOptions<VoidTx, SRx> {
pub const fn with_shutdown_token(shutdown_rx: SRx) -> Self {
Self {
shutdown_rx,
output_tx: VoidTx,
}
}
}
impl Default for ServeOptions<VoidTx, NoShutdown> {
fn default() -> Self {
Self {
shutdown_rx: NoShutdown,
output_tx: VoidTx,
}
}
}
impl<H, X> Server<H, X> {
#[cfg(feature = "tokio")]
pub async fn serve<T, E, OTx, SRx>(
&mut self,
mut options: ServeOptions<OTx, SRx>,
) -> Result<(), E>
where
T: Send + 'static,
E: Send + 'static,
OTx: OutputTx<H::Output, E> + 'static,
H: Handler<T, E> + Clone + 'static,
X: RxChan<T, E, H::Output>,
X::Responder: Send + 'static,
SRx: ShutdownRx<E>,
{
loop {
let result = PollBiased::new(options.shutdown_rx.wait_shutdown(), self.rx.recv()).await;
match result {
Either::Left(_) => return Ok(()),
Either::Right(message) => {
let message = message?;
let out_tx = options.output_tx.clone();
let handler = self.handler.clone();
tokio::spawn(async move {
let output = handler.handle(message.data).await;
if let Some(responder) = message.responder {
responder.respond_with(output).await?;
} else {
out_tx.send(output).await?;
}
Ok::<_, E>(())
});
}
}
}
}
pub async fn handle_message<T, E>(
&mut self,
message: Message<T, X::Responder>,
) -> Result<Option<Result<H::Output, E>>, E>
where
H: Handler<T, E>,
X: RxChan<T, E, H::Output>,
{
let output = self.handler.handle(message.data).await;
if let Some(responder) = message.responder {
responder.respond_with(output).await?;
Ok(None)
} else {
Ok(Some(output))
}
}
}