Refactor error handling in IAM and CMS crates
- Introduced `RepositoryError` and `ServiceError` enums in both IAM and CMS domains for better error management. - Updated domain traits and services to return specific error types instead of `anyhow::Result`. - Enhanced session and OAuth repository implementations to handle errors more explicitly. - Refactored session service methods to return `Result<T, ServiceError>` for improved error handling. - Updated HTTP handlers to utilize the new error types. - Modified password hashing functions to run in a blocking context using `tokio::task::spawn_blocking`. - Added tests for new error handling mechanisms and async password functions.
This commit is contained in:
@@ -19,11 +19,13 @@
|
||||
//!
|
||||
//! - `FileSystemSessionLockRepository` — stateless singleton implementing
|
||||
//! `SessionLockRepository`
|
||||
use std::convert::TryInto;
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tracing;
|
||||
|
||||
use crate::domain::error::RepositoryError;
|
||||
use crate::domain::repository::SessionLockRepository;
|
||||
|
||||
/// Concrete filesystem session-lock repository, using a PID file
|
||||
@@ -39,7 +41,7 @@ impl FileSystemSessionLockRepository {
|
||||
}
|
||||
|
||||
impl SessionLockRepository for FileSystemSessionLockRepository {
|
||||
fn try_lock(&self, session_dir: &Path) -> anyhow::Result<bool> {
|
||||
fn try_lock(&self, session_dir: &Path) -> Result<bool, RepositoryError> {
|
||||
let path = session_dir.join(".lock");
|
||||
let pid = std::process::id();
|
||||
|
||||
@@ -49,15 +51,15 @@ impl SessionLockRepository for FileSystemSessionLockRepository {
|
||||
.open(&path)
|
||||
{
|
||||
Ok(mut file) => {
|
||||
write!(file, "{pid}")?;
|
||||
file.sync_all()?;
|
||||
write!(file, "{pid}")?; // → RepositoryError via From<io::Error>
|
||||
file.sync_all()?; // → RepositoryError via From<io::Error>
|
||||
tracing::debug!(path = %path.display(), pid, "session lock acquired");
|
||||
return Ok(true);
|
||||
}
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
|
||||
tracing::debug!(path = %path.display(), "lock file exists, checking staleness");
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
Err(e) => return Err(RepositoryError::Io(e)),
|
||||
}
|
||||
|
||||
let content = fs::read_to_string(&path).unwrap_or_default();
|
||||
@@ -75,18 +77,18 @@ impl SessionLockRepository for FileSystemSessionLockRepository {
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.write(true)
|
||||
.open(&tmp)?;
|
||||
write!(tmp_file, "{pid}")?;
|
||||
tmp_file.sync_all()?;
|
||||
.open(&tmp)?; // → RepositoryError via From<io::Error>
|
||||
write!(tmp_file, "{pid}")?; // → RepositoryError
|
||||
tmp_file.sync_all()?; // → RepositoryError
|
||||
}
|
||||
fs::rename(&tmp, &path)?;
|
||||
fs::rename(&tmp, &path)?; // → RepositoryError
|
||||
if let Some(parent) = path.parent() {
|
||||
let _ = fs::File::open(parent).and_then(|d| d.sync_all());
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn unlock(&self, session_dir: &Path) -> anyhow::Result<()> {
|
||||
fn unlock(&self, session_dir: &Path) -> Result<(), RepositoryError> {
|
||||
let path = session_dir.join(".lock");
|
||||
let _ = fs::remove_file(path);
|
||||
Ok(())
|
||||
@@ -95,7 +97,9 @@ impl SessionLockRepository for FileSystemSessionLockRepository {
|
||||
fn is_alive(&self, pid: u32) -> bool {
|
||||
// SAFETY: `libc::kill(pid, 0)` sends no signal; it only probes
|
||||
// whether the process exists and is signalable by us.
|
||||
if unsafe { libc::kill(pid as i32, 0) != 0 } {
|
||||
// PIDs on Linux fit in i32 (default pid_max ≈ 4 million).
|
||||
let pid_signed: i32 = pid.try_into().unwrap_or(0);
|
||||
if unsafe { libc::kill(pid_signed, 0) != 0 } {
|
||||
return false;
|
||||
}
|
||||
let proc_exe = std::path::PathBuf::from(format!("/proc/{pid}/exe"));
|
||||
|
||||
Reference in New Issue
Block a user