Files
zesdex/crates/zesdex-iam/src/application/session_service.rs
T

89 lines
3.4 KiB
Rust
Raw Normal View History

//! Session management use-cases.
//!
//! `SessionServiceImpl` implements [`SessionService`] by delegating to
//! injected repository implementations, keeping the orchestration logic
//! independent of any concrete persistence mechanism.
//!
//! # Flow
//!
//! - **`create_session`** — generates a UUID v4 id, creates a `Session` entity,
//! delegates persistence to `SessionRepository`.
//! - **`list_all`** — delegates to `SessionRepository::list_sessions`.
//! - **`archive_session`** — loads session, sets `archived = true`, persists.
//!
//! # Components
//!
//! - `SessionServiceImpl<R, L>` — service over two generic repositories
//! - `new` / `create_session` / `list_all` / `archive_session` — lifecycle ops
use std::path::PathBuf;
use zesdex_entities::domain::auth::SessionId;
use zesdex_utils::CastOr;
use tracing;
use uuid::Uuid;
use crate::domain::error::ServiceError;
use crate::domain::repository::{SessionLockRepository, SessionRepository};
use crate::domain::service::SessionService;
use crate::domain::session::Session;
/// Concrete session service backed by generic repository implementations.
pub struct SessionServiceImpl<R: SessionRepository, L: SessionLockRepository> {
/// Repository for session CRUD operations.
pub session_repo: R,
/// Repository for session lock acquire/release.
pub lock_repo: L,
/// Base data directory passed to repository methods.
pub base_dir: PathBuf,
}
impl<R: SessionRepository, L: SessionLockRepository> SessionServiceImpl<R, L> {
/// Create a new session service with the given repositories and base
/// data directory.
pub fn new(session_repo: R, lock_repo: L, base_dir: PathBuf) -> Self {
SessionServiceImpl {
session_repo,
lock_repo,
base_dir,
}
}
}
impl<R: SessionRepository, L: SessionLockRepository> SessionService for SessionServiceImpl<R, L> {
fn create_session(&self, title: &str) -> Result<Session, ServiceError> {
let id = SessionId::new(&Uuid::new_v4().to_string())
.expect("UUID is always a valid session id");
let title_owned = if title.is_empty() {
"New Session".to_string()
} else {
title.to_string()
};
let session = Session::new(id.into_string(), title_owned);
tracing::debug!(session_id = %session.id, title = %session.title, "creating new session");
self.session_repo
.save_session(&self.base_dir, &session)?; // RepositoryError → ServiceError via From
Ok(session)
}
fn list_all(&self) -> Result<Vec<Session>, ServiceError> {
tracing::debug!("listing all sessions");
self.session_repo
.list_sessions(&self.base_dir)
.map_err(ServiceError::Repository)
}
fn archive_session(&self, id: SessionId) -> Result<(), ServiceError> {
tracing::debug!(session_id = %id, "archiving session");
let mut session = self.session_repo
.load_session(&self.base_dir, &id)?; // RepositoryError → ServiceError
session.archived = true;
let millis = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_millis();
session.updated_at = millis.cast_or(i64::MAX);
self.session_repo
.save_session(&self.base_dir, &session)?; // RepositoryError → ServiceError
Ok(())
}
}