Files
zesdex/apps/infrastructure/src/persistence/iam/session_lock_repo.rs
T
asepharyana da2ed6da25 feat(tui): add usage overlay and sidebar for displaying usage statistics and tasks
feat(tui): implement status bar with connection and turn state indicators
feat(tui): create workflow panel for agent status and progress visualization
feat(web): introduce web frontend interface with static file serving
feat(ws): add WebSocket interface for real-time communication and session management
2026-07-20 09:04:57 +07:00

88 lines
2.7 KiB
Rust

//! Filesystem-backed `SessionLockRepository` implementation using a PID file
//! (`<session_dir>/.lock`) with atomic `O_CREAT|O_EXCL` acquisition.
use std::convert::TryInto;
use std::io::Write;
use std::path::Path;
use zesdex_domain::auth::{RepositoryError, SessionLockRepository};
/// Concrete filesystem session-lock repository.
#[derive(Debug, Clone, Default)]
pub struct FileSystemSessionLockRepository;
impl FileSystemSessionLockRepository {
pub fn new() -> Self {
FileSystemSessionLockRepository
}
}
impl SessionLockRepository for FileSystemSessionLockRepository {
fn try_lock(&self, session_dir: &Path) -> Result<bool, RepositoryError> {
let path = session_dir.join(".lock");
let pid = std::process::id();
match std::fs::OpenOptions::new()
.create_new(true)
.write(true)
.open(&path)
{
Ok(mut file) => {
write!(file, "{pid}")?;
file.sync_all()?;
return Ok(true);
}
Err(ref e) if e.kind() == std::io::ErrorKind::AlreadyExists => {}
Err(e) => return Err(RepositoryError::Io(e)),
}
let content = std::fs::read_to_string(&path).unwrap_or_default();
if let Ok(existing_pid) = content.trim().parse::<u32>() {
if self.is_alive(existing_pid) {
return Ok(false);
}
}
let tmp = path.with_extension("lock.tmp");
{
let mut tmp_file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&tmp)?;
write!(tmp_file, "{pid}")?;
tmp_file.sync_all()?;
}
std::fs::rename(&tmp, &path)?;
if let Some(parent) = path.parent() {
let _ = std::fs::File::open(parent).and_then(|d| d.sync_all());
}
Ok(true)
}
fn unlock(&self, session_dir: &Path) -> Result<(), RepositoryError> {
let path = session_dir.join(".lock");
let _ = std::fs::remove_file(path);
Ok(())
}
fn is_alive(&self, pid: u32) -> bool {
let pid_signed: i32 = match pid.try_into() {
Ok(p) => p,
Err(_) => return false,
};
if unsafe { libc::kill(pid_signed, 0) != 0 } {
return false;
}
let proc_exe = std::path::PathBuf::from(format!("/proc/{pid}/exe"));
if let Ok(target) = std::fs::read_link(&proc_exe) {
if let Ok(exe) = std::env::current_exe() {
if target != exe {
return false;
}
}
}
true
}
}