feat(core): prevent multiple daemon and worker instances
This commit is contained in:
parent
e08bf2f69a
commit
22ba3a5e03
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -311,6 +311,7 @@ dependencies = [
|
|||
"espanso-path",
|
||||
"espanso-render",
|
||||
"espanso-ui",
|
||||
"fs2",
|
||||
"html2text",
|
||||
"lazy_static",
|
||||
"log",
|
||||
|
@ -484,6 +485,16 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69a039c3498dc930fe810151a34ba0c1c70b02b8625035592e74432f678591f2"
|
||||
|
||||
[[package]]
|
||||
name = "fs2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-cprng"
|
||||
version = "0.1.1"
|
||||
|
|
|
@ -37,4 +37,5 @@ serde = { version = "1.0.123", features = ["derive"] }
|
|||
serde_json = "1.0.62"
|
||||
markdown = "0.3.0"
|
||||
html2text = "0.2.1"
|
||||
log-panics = "2.0.0"
|
||||
log-panics = "2.0.0"
|
||||
fs2 = "0.4.3"
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
use std::process::Command;
|
||||
|
||||
use log::info;
|
||||
use log::{error, info};
|
||||
|
||||
use crate::lock::acquire_daemon_lock;
|
||||
|
||||
use super::{CliModule, CliModuleArgs};
|
||||
|
||||
|
@ -41,16 +43,20 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||
fn daemon_main(args: CliModuleArgs) {
|
||||
let paths = args.paths.expect("missing paths in daemon main");
|
||||
|
||||
// Make sure only one instance of the daemon is running
|
||||
let lock_file = acquire_daemon_lock(&paths.runtime);
|
||||
if lock_file.is_none() {
|
||||
error!("daemon is already running!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
info!("espanso version: {}", VERSION);
|
||||
// TODO: print os system and version? (with os_info crate)
|
||||
|
||||
// TODO: check daemon lock file to avoid duplicates
|
||||
|
||||
// TODO: check worker lock file, if taken stop the worker process through IPC
|
||||
|
||||
// TODO: start IPC server
|
||||
|
||||
// TODO: start file watcher thread
|
||||
// TODO: register signals to terminate the worker if the daemon terminates
|
||||
|
||||
let espanso_exe_path =
|
||||
std::env::current_exe().expect("unable to obtain espanso executable location");
|
||||
|
@ -71,4 +77,12 @@ fn daemon_main(args: CliModuleArgs) {
|
|||
}
|
||||
|
||||
command.spawn().expect("unable to spawn worker process");
|
||||
|
||||
// TODO: start IPC server
|
||||
|
||||
// TODO: start file watcher thread
|
||||
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_millis(1000));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use log::error;
|
||||
|
||||
use crate::lock::acquire_worker_lock;
|
||||
|
||||
use self::ui::util::convert_icon_paths_to_tray_vec;
|
||||
|
||||
use super::{CliModule, CliModuleArgs};
|
||||
|
@ -39,6 +43,15 @@ pub fn new() -> CliModule {
|
|||
}
|
||||
|
||||
fn worker_main(args: CliModuleArgs) {
|
||||
let paths = args.paths.expect("missing paths in worker main");
|
||||
|
||||
// Avoid running multiple worker instances
|
||||
let lock_file = acquire_worker_lock(&paths.runtime);
|
||||
if lock_file.is_none() {
|
||||
error!("worker is already running!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let config_store = args
|
||||
.config_store
|
||||
.expect("missing config store in worker main");
|
||||
|
@ -46,8 +59,6 @@ fn worker_main(args: CliModuleArgs) {
|
|||
.match_store
|
||||
.expect("missing match store in worker main");
|
||||
|
||||
let paths = args.paths.expect("missing paths in worker main");
|
||||
|
||||
let icon_paths =
|
||||
self::ui::icon::load_icon_paths(&paths.runtime).expect("unable to initialize icons");
|
||||
|
||||
|
|
72
espanso/src/lock.rs
Normal file
72
espanso/src/lock.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* This file is part of espanso.
|
||||
*
|
||||
* Copyright (C) 2019-2021 Federico Terzi
|
||||
*
|
||||
* espanso is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* espanso is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with espanso. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use anyhow::Result;
|
||||
use fs2::FileExt;
|
||||
use std::{
|
||||
fs::{File, OpenOptions},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
pub struct Lock {
|
||||
lock_file: File,
|
||||
}
|
||||
|
||||
impl Lock {
|
||||
pub fn release(self) -> Result<()> {
|
||||
self.lock_file.unlock()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn acquire(runtime_dir: &Path, name: &str) -> Option<Lock> {
|
||||
let lock_file_path = runtime_dir.join(format!("{}.lock", name));
|
||||
let lock_file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.open(&lock_file_path)
|
||||
.expect(&format!(
|
||||
"unable to create reference to lock file: {:?}",
|
||||
lock_file_path
|
||||
));
|
||||
|
||||
if lock_file.try_lock_exclusive().is_ok() {
|
||||
Some(Lock { lock_file })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Lock {
|
||||
fn drop(&mut self) {
|
||||
self
|
||||
.lock_file
|
||||
.unlock()
|
||||
.expect(&format!("unable to unlock lock_file: {:?}", self.lock_file));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn acquire_daemon_lock(runtime_dir: &Path) -> Option<Lock> {
|
||||
Lock::acquire(runtime_dir, "espanso-daemon.lock")
|
||||
}
|
||||
|
||||
pub fn acquire_worker_lock(runtime_dir: &Path) -> Option<Lock> {
|
||||
Lock::acquire(runtime_dir, "espanso-worker.lock")
|
||||
}
|
|
@ -35,6 +35,7 @@ use crate::cli::LogMode;
|
|||
mod cli;
|
||||
mod engine;
|
||||
mod gui;
|
||||
mod lock;
|
||||
mod logging;
|
||||
mod util;
|
||||
|
||||
|
@ -253,7 +254,7 @@ fn main() {
|
|||
if handler.enable_logs {
|
||||
let config = ConfigBuilder::new()
|
||||
.set_time_to_local(true)
|
||||
.set_time_format(format!("%H:%M:%S [{}]", handler.subcommand))
|
||||
.set_time_format(format!("%H:%M:%S [{}({})]", handler.subcommand, std::process::id()))
|
||||
.set_location_level(LevelFilter::Off)
|
||||
.add_filter_ignore_str("html5ever")
|
||||
.build();
|
||||
|
|
Loading…
Reference in New Issue
Block a user