use single_instance::SingleInstance;
use thiserror::Error;
const INSTANCE_ID: &str = "mindfork-rs-single-instance";
pub struct InstanceGuard {
_inner: SingleInstance,
}
#[derive(Debug, Error)]
pub enum InstanceError {
#[error("application is already running")]
AlreadyRunning,
#[error("failed to initialize the single-instance lock: {0}")]
Init(String),
}
pub fn acquire() -> Result<InstanceGuard, InstanceError> {
acquire_named(INSTANCE_ID)
}
fn acquire_named(name: &str) -> Result<InstanceGuard, InstanceError> {
let inner = SingleInstance::new(name).map_err(|e| InstanceError::Init(e.to_string()))?;
if !inner.is_single() {
return Err(InstanceError::AlreadyRunning);
}
Ok(InstanceGuard { _inner: inner })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn second_acquire_reports_already_running() {
let name = "mindfork-rs-test-second-acquire-reports-already-running";
let first = acquire_named(name).expect("first acquire should succeed");
match acquire_named(name) {
Err(InstanceError::AlreadyRunning) => {}
Err(other) => panic!("expected AlreadyRunning, got: {other:?}"),
Ok(_) => panic!("second acquire should not succeed while the first is alive"),
}
drop(first);
let _again = acquire_named(name).expect("after drop, acquiring again is possible");
}
}