//! Conversation use-case implementation. //! //! `ConversationServiceImpl` implements [`ConversationService`] from the //! domain layer. It is generic over `R: ConversationRepository`, delegating //! all persistence to that adapter. //! //! # Flow //! //! Each method computes the session directory from the session ID, then //! delegates the actual I/O to the injected `repo`. Error context is //! added at this layer to identify which session caused the failure. use std::path::PathBuf; use tracing; use zesdex_domain::cms::{Conversation, ConversationRepository, ServiceError}; use zesdex_domain::core::ChatMessage; /// Service implementation for conversation CRUD operations. /// /// Generic over `R: ConversationRepository` so the persistence layer /// can be swapped without changing business logic. pub struct ConversationServiceImpl { pub repo: R, /// Base directory containing session subdirectories. pub sessions_dir: PathBuf, } impl ConversationServiceImpl { /// Create a new service with the given repository and sessions directory. pub fn new(repo: R, sessions_dir: impl Into) -> Self { tracing::debug!("creating ConversationServiceImpl"); Self { repo, sessions_dir: sessions_dir.into(), } } /// Compute the session directory for a given session id. fn session_dir(&self, session_id: &str) -> PathBuf { self.sessions_dir.join(session_id) } } impl zesdex_domain::cms::ConversationService for ConversationServiceImpl { fn load_conversation(&self, session_id: &str) -> Result { tracing::debug!("loading conversation for session {session_id}"); let dir = self.session_dir(session_id); self.repo.load(&dir).map_err(ServiceError::Repository) } fn save_conversation(&self, conv: &Conversation) -> Result<(), ServiceError> { tracing::debug!("saving conversation for session {}", conv.session_id); let dir = self.session_dir(&conv.session_id); self.repo.save(&dir, conv)?; Ok(()) } fn add_message( &self, conv: &mut Conversation, msg: ChatMessage, ) -> Result<(), ServiceError> { tracing::debug!("adding message to session {}", conv.session_id); conv.push(msg); let dir = self.session_dir(&conv.session_id); self.repo.save(&dir, conv)?; Ok(()) } }