use std::fs;
use std::path::Path;
use anyhow::{bail, Context};
use bark::lock_manager::PidLockError;
use bark::lock_manager::pid_flock::FlockPidLockManager;
use crate::wallet::AUTH_TOKEN_FILE;
pub const BARKD_LOCK_FILE: &str = "barkd.lock";
pub fn wipe_datadir_except_barkd_files(datadir: &Path) -> anyhow::Result<()> {
let barkd_files = [BARKD_LOCK_FILE, AUTH_TOKEN_FILE];
for entry in fs::read_dir(datadir).context("failed to list datadir")? {
let entry = entry?;
if barkd_files.iter().any(|k| entry.file_name() == *k) {
continue;
}
let path = entry.path();
if entry.file_type()?.is_dir() {
fs::remove_dir_all(&path)
} else {
fs::remove_file(&path)
}.with_context(|| format!("failed to remove {}", path.display()))?;
}
Ok(())
}
pub fn acquire_barkd_lock(datadir: &Path) -> anyhow::Result<FlockPidLockManager> {
match FlockPidLockManager::new_with_lock_file(datadir, BARKD_LOCK_FILE) {
Ok(lock) => Ok(lock),
Err(PidLockError::AlreadyHeld { datadir, pid }) => match pid {
Some(pid) => bail!(
"another barkd is already running on datadir {} (pid {})",
datadir.display(), pid,
),
None => bail!(
"another barkd is already running on datadir {}",
datadir.display(),
),
},
Err(e) => Err(e).context("failed to acquire barkd lock"),
}
}
#[cfg(test)]
mod test {
use super::*;
fn tmp_dir() -> std::path::PathBuf {
let dir = std::env::temp_dir()
.join(format!("bark-connection-{}", std::process::id()))
.join(format!("{}", std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()));
fs::create_dir_all(&dir).unwrap();
dir
}
#[test]
fn wipe_keeps_barkd_files() {
let dir = tmp_dir();
let _lock = acquire_barkd_lock(&dir).unwrap();
fs::write(dir.join(AUTH_TOKEN_FILE), "tok").unwrap();
fs::write(dir.join("db.sqlite"), "x").unwrap();
fs::create_dir(dir.join("sub")).unwrap();
fs::write(dir.join("sub").join("f"), "y").unwrap();
wipe_datadir_except_barkd_files(&dir).unwrap();
assert!(dir.join(BARKD_LOCK_FILE).exists());
assert!(dir.join(AUTH_TOKEN_FILE).exists());
assert!(!dir.join("db.sqlite").exists());
assert!(!dir.join("sub").exists());
let _ = fs::remove_dir_all(&dir);
}
#[test]
fn barkd_lock_refuses_second_holder() {
let dir = tmp_dir();
let held = acquire_barkd_lock(&dir).unwrap();
let err = acquire_barkd_lock(&dir).unwrap_err();
assert!(
err.to_string().contains("another barkd is already running"),
"unexpected error: {}", err,
);
assert!(err.to_string().contains(&std::process::id().to_string()));
drop(held);
let _reacquired = acquire_barkd_lock(&dir).unwrap();
let _ = fs::remove_dir_all(&dir);
}
}