mod command_handler;
mod dispatched_command;
use std::sync::Arc;
pub use command_handler::CommandHandler;
pub use dispatched_command::DispatchedCommand;
use futures::future::BoxFuture;
use simple_middleware::{Manager as MiddlewareManager, Next};
use crate::Busstop;
pub type NextCommandMiddleware = Next<DispatchedCommand, DispatchedCommand>;
pub type CommandMiddleware = Box<
dyn FnMut(DispatchedCommand, NextCommandMiddleware) -> BoxFuture<'static, DispatchedCommand>
+ Send
+ Sync,
>;
#[async_trait::async_trait]
pub trait DispatchableCommand: Send + Sync {
async fn dispatch_command(self) -> bool
where
Self: Sized + 'static,
{
Busstop::instance().dispatch_command(self).await
}
async fn command_handler<H: CommandHandler + Default + 'static>()
where
Self: Sized,
{
Busstop::instance()
.register_command::<Self>(H::default())
.await;
}
async fn command_middleware<M: 'static>(middleware: M)
where
Self: Sized,
M: FnMut(
DispatchedCommand,
Next<DispatchedCommand, DispatchedCommand>,
) -> BoxFuture<'static, DispatchedCommand>
+ Send
+ Sync,
{
Busstop::instance()
.register_command_middleware::<Self, M>(middleware)
.await;
}
async fn soft_command_handler<H: CommandHandler + Default + 'static>()
where
Self: Sized,
{
let bus = Busstop::instance();
if !bus.command_has_handler::<Self>().await {
bus.register_command::<Self>(H::default()).await;
}
}
async fn register_command_handler<H: CommandHandler + 'static>(handler: H)
where
Self: Sized,
{
Busstop::instance().register_command::<Self>(handler).await;
}
async fn register_soft_command_handler<H: CommandHandler + 'static>(handler: H)
where
Self: Sized,
{
let bus = Busstop::instance();
if !bus.command_has_handler::<Self>().await {
bus.register_command::<Self>(handler).await;
}
}
}
pub struct CommandHandlerManager {
name: String,
middleware: MiddlewareManager<DispatchedCommand, DispatchedCommand>,
}
impl CommandHandlerManager {
pub async fn new(handler: impl CommandHandler + 'static) -> Self {
let handler = Arc::new(Box::new(handler));
Self {
name: handler.command_handler_name().to_string(),
middleware: MiddlewareManager::last(move |dispatched, _| {
let instance = handler.clone();
Box::pin(async move { instance.clone().handle_command(dispatched).await })
})
.await,
}
}
pub fn name(&self) -> &String {
&self.name
}
pub async fn next<M>(&self, middleware: M) -> &Self
where
M: FnMut(DispatchedCommand, NextCommandMiddleware) -> BoxFuture<'static, DispatchedCommand>
+ Send
+ 'static,
{
self.middleware.next(middleware).await;
self
}
pub async fn handle(&self, dispatched: DispatchedCommand) -> DispatchedCommand {
let mut result = self.middleware.send(dispatched).await;
result.handled = true;
result
}
pub async fn handle_command<C: Send + Sync + 'static>(&self, command: C) -> DispatchedCommand {
self.handle(DispatchedCommand::new(
Box::new(command),
std::any::type_name::<C>(),
))
.await
}
}
#[cfg(test)]
mod test {
use super::*;
struct Cmd;
impl DispatchableCommand for Cmd {}
#[derive(Default)]
struct CmdHandler;
#[async_trait::async_trait]
impl CommandHandler for CmdHandler {
async fn handle_command(&self, c: DispatchedCommand) -> DispatchedCommand {
c
}
}
#[tokio::test]
async fn test_command_handler_manager() {
let manager = CommandHandlerManager::new(CmdHandler).await;
manager
.next(|c, n| Box::pin(async move { n.call(c).await }))
.await;
manager
.next(|c, n| Box::pin(async move { n.call(c).await }))
.await;
assert_eq!(manager.handle_command(Cmd).await.handled(), true)
}
}