use crate::command::context::CommandContext; use crate::command::handler::{CommandHandler, CommandMetadata}; use crate::command::response::{CommandError, CommandResponse, MessageKind}; use crate::command::Command; use crate::storage::SessionStore; use async_trait::async_trait; use std::sync::Arc; /// 列出话题命令处理器 pub struct ListSessionsCommandHandler { store: Arc, } impl ListSessionsCommandHandler { pub fn new(store: Arc) -> Self { Self { store } } } #[async_trait] impl CommandHandler for ListSessionsCommandHandler { fn can_handle(&self, cmd: &Command) -> bool { matches!(cmd, Command::ListSessions { .. }) } fn metadata(&self) -> Option { Some(CommandMetadata { name: "list", description: "列出所有话题", usage: "/list [all]", }) } async fn handle( &self, cmd: Command, ctx: CommandContext, ) -> Result { match cmd { Command::ListSessions { include_archived } => { handle_list_sessions(self, include_archived, ctx).await } _ => unreachable!(), } } } async fn handle_list_sessions( handler: &ListSessionsCommandHandler, _include_archived: bool, ctx: CommandContext, ) -> Result { let session_id = ctx.session_id.as_deref() .ok_or_else(|| CommandError::new("NO_SESSION", "No active session"))?; let topics = handler .store .list_topics(session_id) .map_err(|e| CommandError::new("LIST_TOPICS_ERROR", e.to_string()))?; let current_topic_id = ctx.topic_id.as_deref().unwrap_or(""); let message = if topics.is_empty() { "No topics found. Use /new to create a topic.".to_string() } else { let mut lines = vec![format!("Found {} topic(s):", topics.len())]; lines.push(String::new()); for (idx, topic) in topics.iter().enumerate() { let num = idx + 1; let is_current = topic.id == current_topic_id; let marker = if is_current { " *" } else { "" }; // 使用辅助方法获取消息数量 let msg_count = handler.store .get_topic_message_count(&topic.id) .unwrap_or(0); lines.push(format!( "{}. {}{} ({})", num, topic.title, marker, msg_count )); // 显示描述(如果有) if let Some(ref desc) = topic.description { if !desc.is_empty() { lines.push(format!(" {}", desc)); } } } lines.push(String::new()); lines.push("* = current topic".to_string()); lines.push("Use /use <number> to switch".to_string()); lines.join("\n") }; let topics_json = serde_json::to_string(&topics) .map_err(|e| CommandError::new("SERIALIZE_ERROR", e.to_string()))?; Ok(CommandResponse::success(ctx.request_id) .with_message(MessageKind::Notification, &message) .with_metadata("topics", &topics_json) .with_metadata("count", &topics.len().to_string()) .with_metadata("current_topic_id", current_topic_id)) }