use std::fs::OpenOptions;
use std::io::Write;
use std::path::PathBuf;
use std::time::{Duration, Instant, SystemTime};
const STALE_AFTER: Duration = Duration::from_secs(300);
const MAX_WAIT: Duration = Duration::from_secs(600);
pub struct BrowserLock {
path: PathBuf,
}
impl BrowserLock {
#[must_use]
pub fn acquire() -> Self {
let path = std::env::temp_dir().join("wvq-browser-test.lock");
let deadline = Instant::now() + MAX_WAIT;
loop {
match OpenOptions::new().create_new(true).write(true).open(&path) {
Ok(mut file) => {
let _ = writeln!(file, "{}", std::process::id());
return Self { path };
}
Err(err) if err.kind() == std::io::ErrorKind::AlreadyExists => {
if is_stale(&path) || Instant::now() >= deadline {
let _ = std::fs::remove_file(&path);
continue;
}
std::thread::sleep(Duration::from_millis(50));
}
Err(_) => return Self { path },
}
}
}
}
fn is_stale(path: &std::path::Path) -> bool {
std::fs::metadata(path)
.and_then(|meta| meta.modified())
.ok()
.and_then(|modified| SystemTime::now().duration_since(modified).ok())
.is_some_and(|age| age > STALE_AFTER)
}
impl Drop for BrowserLock {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.path);
}
}