154 lines
5.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::command::context::CommandContext;
use crate::command::handler::CommandHandler;
use crate::command::response::{CommandError, CommandResponse, MessageKind};
use crate::command::Command;
use crate::gateway::session::SessionManager;
use crate::storage::SessionStore;
use async_trait::async_trait;
use std::sync::Arc;
/// 会话命令处理器
///
/// 处理与会话管理相关的命令
pub struct SessionCommandHandler {
store: Arc<SessionStore>,
session_manager: Option<SessionManager>,
}
impl SessionCommandHandler {
/// 创建新的会话命令处理器
///
/// # Arguments
/// * `store` - Session 存储
pub(crate) fn new(store: Arc<SessionStore>) -> Self {
Self {
store,
session_manager: None,
}
}
/// 设置 SessionManager用于 CreateSession 命令自动切换话题)
pub fn with_session_manager(mut self, session_manager: SessionManager) -> Self {
self.session_manager = Some(session_manager);
self
}
}
#[async_trait]
impl CommandHandler for SessionCommandHandler {
fn can_handle(&self, cmd: &Command) -> bool {
matches!(cmd, Command::CreateSession { .. })
}
async fn handle(
&self,
cmd: Command,
ctx: CommandContext,
) -> Result<CommandResponse, CommandError> {
match cmd {
Command::CreateSession { title } => handle_create_session(self, title, ctx).await,
Command::SaveSession { .. } => unreachable!("SaveSession should be handled by SaveSessionCommandHandler"),
_ => unreachable!("Other commands should be handled by other handlers"),
}
}
}
/// 处理创建会话命令
async fn handle_create_session(
handler: &SessionCommandHandler,
title: Option<String>,
ctx: CommandContext,
) -> Result<CommandResponse, CommandError> {
// 获取当前 session_id如果没有则报错
let session_id = ctx.session_id.as_deref()
.ok_or_else(|| CommandError::new("NO_SESSION", "No active session. Please ensure a session exists first."))?;
// 创建新话题(在同一个 Session 内)
let topic_title = title.unwrap_or_else(|| {
format!("Topic {}", &uuid::Uuid::new_v4().to_string()[..8])
});
let topic = handler
.store
.create_topic(session_id, &topic_title, None)
.map_err(|e| CommandError::new("CREATE_TOPIC_ERROR", e.to_string()))?;
// 获取 chat_id
let chat_id = ctx.chat_id.as_deref()
.ok_or_else(|| CommandError::new("NO_CHAT_ID", "No chat_id in context"))?;
// 如果有 SessionManager自动切换到新话题
if let Some(ref session_manager) = handler.session_manager {
if let Some(session) = session_manager.get(&ctx.channel_name).await {
let mut session_guard = session.lock().await;
session_guard.switch_topic(chat_id, &topic.id)
.map_err(|e| CommandError::new("SWITCH_TOPIC_ERROR", e.to_string()))?;
}
}
Ok(CommandResponse::success(ctx.request_id)
.with_message(MessageKind::Notification, &topic.title)
.with_metadata("topic_id", &topic.id)
.with_metadata("session_id", &topic.session_id)
.with_metadata("message_count", &topic.message_count.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::storage::SessionStore;
use std::sync::Arc;
fn create_test_handler() -> SessionCommandHandler {
let store = Arc::new(SessionStore::in_memory().unwrap());
SessionCommandHandler::new(store)
}
#[tokio::test]
async fn test_create_session_with_title() {
let handler = create_test_handler();
// 需要先创建一个 session
let store = handler.store.clone();
let session = store.create_session("cli", Some("test session")).unwrap();
let ctx = CommandContext::new("test", "cli")
.with_session_id(&session.id)
.with_chat_id(&session.id);
let cmd = Command::CreateSession {
title: Some("my topic".to_string()),
};
let result = handler.handle(cmd, ctx).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert!(resp.success);
assert!(resp.metadata.contains_key("topic_id"));
}
#[tokio::test]
async fn test_create_session_without_title() {
let handler = create_test_handler();
let store = handler.store.clone();
let session = store.create_session("cli", Some("test session")).unwrap();
let ctx = CommandContext::new("test", "cli")
.with_session_id(&session.id)
.with_chat_id(&session.id);
let cmd = Command::CreateSession { title: None };
let result = handler.handle(cmd, ctx).await;
assert!(result.is_ok());
let resp = result.unwrap();
assert!(resp.success);
}
#[test]
fn test_can_handle() {
let handler = create_test_handler();
assert!(handler.can_handle(&Command::CreateSession { title: None }));
}
}