use crate::bus::InboundMessage; use crate::command::context::CommandContext; use crate::command::response::{CommandError, CommandResponse}; use crate::command::Command; use crate::agent::AgentError; use crate::gateway::session::SessionManager; use async_trait::async_trait; /// 命令处理器 trait /// /// 实现此 trait 来处理特定类型的命令 /// 处理器是渠道无关的,只关心 Command 本身 #[async_trait] pub trait CommandHandler: Send + Sync { /// 是否可以处理此命令 fn can_handle(&self, cmd: &Command) -> bool; /// 执行命令 /// /// # Arguments /// * `cmd` - 要执行的命令 /// * `ctx` - 命令执行上下文 /// /// # Returns /// * `Ok(CommandResponse)` - 命令执行成功 /// * `Err(CommandError)` - 命令执行失败 async fn handle( &self, cmd: Command, ctx: CommandContext, ) -> Result; } /// InChat 命令处理器 trait /// /// 用于处理在聊天中直接输入的命令(如 Feishu/WeChat 等通道) /// 接收 InboundMessage 和 SessionManager #[async_trait] pub trait InChatCommandHandler: Send + Sync { /// 是否可以处理此命令 fn can_handle(&self, cmd: &Command) -> bool; /// 执行命令 /// /// # Arguments /// * `cmd` - 要执行的命令 /// * `inbound` - 入站消息(包含通道信息) /// * `session_manager` - 会话管理器(用于获取 session) /// /// # Returns /// * `Ok(Some(msg))` - 命令执行成功,返回要发送给用户的消息 /// * `Ok(None)` - 命令执行成功,无需发送消息 /// * `Err(AgentError)` - 命令执行失败 async fn handle( &self, cmd: Command, inbound: &InboundMessage, session_manager: &SessionManager, ) -> Result, AgentError>; } /// 命令路由器 /// /// 负责将命令分发到合适的处理器 pub struct CommandRouter { handlers: Vec>, } impl CommandRouter { /// 创建新的命令路由器 pub fn new() -> Self { Self { handlers: Vec::new(), } } /// 注册命令处理器 /// /// # Arguments /// * `handler` - 要注册的处理器 pub fn register(&mut self, handler: Box) { self.handlers.push(handler); } /// 分发命令到合适的处理器 /// /// # Arguments /// * `cmd` - 要执行的命令 /// * `ctx` - 命令执行上下文 /// /// # Returns /// * `Ok(CommandResponse)` - 命令执行成功 /// * `Err(CommandError)` - 没有合适的处理器或执行失败 pub async fn dispatch( &self, cmd: Command, ctx: CommandContext, ) -> Result { // 查找能处理此命令的处理器 for handler in &self.handlers { if handler.can_handle(&cmd) { return handler.handle(cmd, ctx).await; } } // 没有找到合适的处理器 Err(CommandError::new( "NO_HANDLER", format!("No handler found for command: {}", cmd.name()), )) } /// 分发命令,返回响应(如果失败则返回错误响应) /// /// 与 `dispatch` 不同,此方法不会返回 Err, /// 而是将错误包装在 CommandResponse 中 pub async fn dispatch_with_response( &self, cmd: Command, ctx: CommandContext, ) -> CommandResponse { let request_id = ctx.request_id; match self.dispatch(cmd, ctx).await { Ok(response) => response, Err(err) => CommandResponse::error(request_id, err), } } } impl Default for CommandRouter { fn default() -> Self { Self::new() } } /// InChat 命令路由器 /// /// 负责将在聊天中输入的命令分发到合适的处理器 pub struct InChatCommandRouter { handlers: Vec>, } impl InChatCommandRouter { /// 创建新的 InChat 命令路由器 pub fn new() -> Self { Self { handlers: Vec::new(), } } /// 注册 InChat 命令处理器 /// /// # Arguments /// * `handler` - 要注册的处理器 pub fn register(&mut self, handler: Box) { self.handlers.push(handler); } /// 分发命令到合适的处理器 /// /// # Arguments /// * `cmd` - 要执行的命令 /// * `inbound` - 入站消息 /// * `session_manager` - 会话管理器 /// /// # Returns /// * `Ok(Some(msg))` - 命令被处理,返回成功消息 /// * `Ok(None)` - 没有合适的处理器 /// * `Err(AgentError)` - 执行失败 pub async fn dispatch( &self, cmd: Command, inbound: &InboundMessage, session_manager: &SessionManager, ) -> Result, AgentError> { // 查找能处理此命令的处理器 for handler in &self.handlers { if handler.can_handle(&cmd) { let result = handler.handle(cmd, inbound, session_manager).await?; return Ok(result); } } // 没有找到合适的处理器 Ok(None) } } impl Default for InChatCommandRouter { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; use uuid::Uuid; struct TestHandler; #[async_trait] impl CommandHandler for TestHandler { fn can_handle(&self, cmd: &Command) -> bool { matches!(cmd, Command::CreateSession { .. }) } async fn handle( &self, _cmd: Command, ctx: CommandContext, ) -> Result { Ok(CommandResponse::success(ctx.request_id) .with_message(crate::command::response::MessageKind::Notification, "ok")) } } struct NoOpHandler; #[async_trait] impl CommandHandler for NoOpHandler { fn can_handle(&self, _cmd: &Command) -> bool { false } async fn handle( &self, _cmd: Command, _ctx: CommandContext, ) -> Result { unreachable!() } } #[tokio::test] async fn test_router_finds_handler() { let mut router = CommandRouter::new(); router.register(Box::new(TestHandler)); router.register(Box::new(NoOpHandler)); let ctx = CommandContext::new("test", "test"); let cmd = Command::CreateSession { title: None }; let result = router.dispatch(cmd, ctx).await; assert!(result.is_ok()); let resp = result.unwrap(); assert!(resp.success); } #[tokio::test] async fn test_router_no_handler() { let router = CommandRouter::new(); let ctx = CommandContext::new("test", "test"); let cmd = Command::CreateSession { title: None }; let result = router.dispatch(cmd, ctx).await; assert!(result.is_err()); } }