bb29671733
Add a mechanism to prevent multiple instances of the desktop client from running simultaneously. This is achieved by creating a lock file. The first instance successfully acquires the lock, while subsequent attempts by other instances will fail, prompting them to exit gracefully. This ensures data integrity and prevents potential conflicts.
50 lines
1.6 KiB
Rust
50 lines
1.6 KiB
Rust
//! Regression guard for the single-instance lock in `main.rs`. The
|
|
//! implementation relies on `std::fs::File::try_lock` (stable since
|
|
//! Rust 1.89) — specifically that opening the same file a second time
|
|
//! from within the same process and calling `try_lock` yields
|
|
//! `TryLockError::WouldBlock` while the first handle lives.
|
|
//!
|
|
//! Two-process testing is out of scope (would need `std::process::Command`
|
|
//! with shared state); this test covers the in-process assumption which
|
|
//! is what our `acquire_single_instance_lock` depends on.
|
|
|
|
use std::fs::{OpenOptions, TryLockError};
|
|
|
|
use tempfile::TempDir;
|
|
|
|
#[test]
|
|
fn second_try_lock_on_same_file_blocks() {
|
|
let dir = TempDir::new().unwrap();
|
|
let path = dir.path().join("client.lock");
|
|
|
|
let first = OpenOptions::new()
|
|
.create(true)
|
|
.read(true)
|
|
.write(true)
|
|
.truncate(false)
|
|
.open(&path)
|
|
.unwrap();
|
|
first.try_lock().expect("first lock must succeed");
|
|
|
|
let second = OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.open(&path)
|
|
.unwrap();
|
|
match second.try_lock() {
|
|
Err(TryLockError::WouldBlock) => {}
|
|
Ok(()) => panic!("second try_lock unexpectedly succeeded"),
|
|
Err(e) => panic!("unexpected lock error: {e:?}"),
|
|
}
|
|
|
|
// Dropping `first` releases the OS lock; the third attempt then
|
|
// succeeds — proves the lock truly scopes to the file handle.
|
|
drop(first);
|
|
let third = OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.open(&path)
|
|
.unwrap();
|
|
third.try_lock().expect("after drop, re-lock must succeed");
|
|
}
|