use std::fs::{File, OpenOptions};
use std::path::Path;
use anyhow::Context;
use fs2::FileExt;
pub struct SessionLock {
_file: File,
}
impl SessionLock {
pub fn exclusive(state_path: &Path) -> anyhow::Result<Self> {
let lock_path = lock_path(state_path);
let file = OpenOptions::new()
.create(true)
.truncate(false)
.write(true)
.open(&lock_path)
.with_context(|| format!("Failed to open lock file: {}", lock_path.display()))?;
file.lock_exclusive()
.with_context(|| "Failed to acquire exclusive lock on session")?;
Ok(SessionLock { _file: file })
}
pub fn shared(state_path: &Path) -> anyhow::Result<Self> {
let lock_path = lock_path(state_path);
let file = OpenOptions::new()
.create(true)
.truncate(false)
.write(true)
.open(&lock_path)
.with_context(|| format!("Failed to open lock file: {}", lock_path.display()))?;
file.lock_shared()
.with_context(|| "Failed to acquire shared lock on session")?;
Ok(SessionLock { _file: file })
}
}
fn lock_path(state_path: &Path) -> std::path::PathBuf {
let mut p = state_path.to_path_buf();
let stem = p
.file_name()
.unwrap_or_default()
.to_string_lossy()
.into_owned();
p.set_file_name(format!("{stem}.lock"));
p
}