agent_first_pay/store/
lock.rs1use fs2::FileExt;
2use std::fs::File;
3use std::path::Path;
4use std::time::{Duration, Instant};
5
6const DEFAULT_TIMEOUT_MS: u64 = 5000;
8const RETRY_INTERVAL_MS: u64 = 50;
10
11#[derive(Debug)]
14pub struct DataLock {
15 _file: File,
16}
17
18pub fn acquire(data_dir: &str, timeout_ms: Option<u64>) -> Result<DataLock, String> {
21 let timeout = Duration::from_millis(timeout_ms.unwrap_or(DEFAULT_TIMEOUT_MS));
22
23 let dir = Path::new(data_dir);
24 std::fs::create_dir_all(dir)
25 .map_err(|e| format!("cannot create data directory {data_dir}: {e}"))?;
26
27 let lock_path = dir.join("afpay.lock");
28 let file = File::create(&lock_path)
29 .map_err(|e| format!("cannot create lock file {}: {e}", lock_path.display()))?;
30
31 let start = Instant::now();
32 loop {
33 match file.try_lock_exclusive() {
34 Ok(()) => return Ok(DataLock { _file: file }),
35 Err(_) => {
36 if start.elapsed() >= timeout {
37 return Err(format!(
38 "timeout acquiring lock on {data_dir} after {}ms; another operation may be in progress",
39 timeout.as_millis()
40 ));
41 }
42 std::thread::sleep(Duration::from_millis(RETRY_INTERVAL_MS));
43 }
44 }
45 }
46}