feat(core): implement config auto-reload

This commit is contained in:
Federico Terzi 2021-06-02 21:52:08 +02:00
parent 33eeee99a9
commit 833e39c328
9 changed files with 480 additions and 99 deletions

265
Cargo.lock generated
View File

@ -21,7 +21,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -30,7 +30,7 @@ version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -59,7 +59,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -136,6 +136,12 @@ version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -152,7 +158,7 @@ dependencies = [
"num-integer",
"num-traits",
"time",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -178,7 +184,7 @@ checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
dependencies = [
"atty",
"lazy_static",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -193,7 +199,7 @@ dependencies = [
"regex",
"terminal_size",
"unicode-width",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -214,7 +220,7 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -223,7 +229,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd01a6eb3daaafa260f6fc94c3a6c36390abc2080e38e3e34ced87393fb77d80"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
@ -237,7 +243,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-utils",
]
@ -247,7 +253,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-epoch",
"crossbeam-utils",
]
@ -258,7 +264,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"const_fn",
"crossbeam-utils",
"lazy_static",
@ -272,7 +278,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f6cb3c7f5b8e51bc3ebb73a2327ad4abdbd119dc13223f14f961d2f38486756"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crossbeam-utils",
]
@ -283,7 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
dependencies = [
"autocfg",
"cfg-if",
"cfg-if 1.0.0",
"lazy_static",
]
@ -339,7 +345,7 @@ checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
dependencies = [
"libc",
"redox_users",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -359,7 +365,7 @@ checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a"
dependencies = [
"libc",
"redox_users",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -436,13 +442,14 @@ dependencies = [
"maplit",
"markdown",
"named_pipe",
"notify",
"serde",
"serde_json",
"serde_yaml",
"simplelog",
"tempdir",
"thiserror",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -629,13 +636,25 @@ dependencies = [
"widestring",
]
[[package]]
name = "filetime"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall 0.2.5",
"winapi 0.3.9",
]
[[package]]
name = "flate2"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"crc32fast",
"libc",
"miniz_oxide",
@ -663,7 +682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
dependencies = [
"libc",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -672,12 +691,47 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394"
[[package]]
name = "fsevent"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6"
dependencies = [
"bitflags 1.2.1",
"fsevent-sys",
]
[[package]]
name = "fsevent-sys"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0"
dependencies = [
"libc",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
dependencies = [
"bitflags 1.2.1",
"fuchsia-zircon-sys",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "futf"
version = "0.1.4"
@ -694,7 +748,7 @@ version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
@ -705,7 +759,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
]
@ -783,6 +837,35 @@ dependencies = [
"syn 1.0.67",
]
[[package]]
name = "inotify"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f"
dependencies = [
"bitflags 1.2.1",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
dependencies = [
"libc",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
"libc",
]
[[package]]
name = "itertools"
version = "0.10.0"
@ -798,6 +881,16 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -837,7 +930,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@ -944,13 +1037,56 @@ dependencies = [
"autocfg",
]
[[package]]
name = "mio"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4"
dependencies = [
"cfg-if 0.1.10",
"fuchsia-zircon",
"fuchsia-zircon-sys",
"iovec",
"kernel32-sys",
"libc",
"log",
"miow",
"net2",
"slab",
"winapi 0.2.8",
]
[[package]]
name = "mio-extras"
version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
dependencies = [
"lazycell",
"log",
"mio",
"slab",
]
[[package]]
name = "miow"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d"
dependencies = [
"kernel32-sys",
"net2",
"winapi 0.2.8",
"ws2_32-sys",
]
[[package]]
name = "mockall"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18d614ad23f9bb59119b8b5670a85c7ba92c5e9adf4385c81ea00c51c8be33d5"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"downcast",
"fragile",
"lazy_static",
@ -965,7 +1101,7 @@ version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dd4234635bca06fc96c7368d038061e0aae1b00a764dc817e900dc974e3deea"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.67",
@ -977,7 +1113,18 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad9c443cce91fc3e12f017290db75dde490d685cdaaf508d7159d7cf41f0eb2b"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
name = "net2"
version = "0.2.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
dependencies = [
"cfg-if 0.1.10",
"libc",
"winapi 0.3.9",
]
[[package]]
@ -992,6 +1139,24 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "notify"
version = "4.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257"
dependencies = [
"bitflags 1.2.1",
"filetime",
"fsevent",
"fsevent-sys",
"inotify",
"libc",
"mio",
"mio-extras",
"walkdir",
"winapi 0.3.9",
]
[[package]]
name = "notify-rust"
version = "4.2.2"
@ -1066,7 +1231,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1218,7 +1383,7 @@ dependencies = [
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1385,7 +1550,7 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1481,6 +1646,12 @@ version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
[[package]]
name = "slab"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527"
[[package]]
name = "string_cache"
version = "0.8.1"
@ -1575,12 +1746,12 @@ version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"libc",
"rand 0.8.3",
"redox_syscall 0.2.5",
"remove_dir_all",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1610,7 +1781,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1619,7 +1790,7 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "956044ef122917dde830c19dec5f76d0670329fde4104836d62ebcb14f4865f1"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"proc-macro2",
"quote 1.0.9",
"syn 1.0.67",
@ -1663,7 +1834,7 @@ checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1748,7 +1919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
dependencies = [
"same-file",
"winapi",
"winapi 0.3.9",
"winapi-util",
]
@ -1770,6 +1941,12 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
[[package]]
name = "winapi"
version = "0.3.9"
@ -1780,6 +1957,12 @@ dependencies = [
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
@ -1792,7 +1975,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1816,7 +1999,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e30cba82e22b083dc5a422c2ee77e20dc7927271a0dc981360c57c1453cb48d"
dependencies = [
"winapi",
"winapi 0.3.9",
]
[[package]]
@ -1827,11 +2010,21 @@ checksum = "6c31a65da50d792c6f9bd2e3216249566c4fb1d2d34f9b7d2d66d2e93f62a242"
dependencies = [
"strum",
"strum_macros",
"winapi",
"winapi 0.3.9",
"winrt",
"xml-rs",
]
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]]
name = "xml-rs"
version = "0.6.1"

View File

@ -3,4 +3,8 @@ default_to_workspace = false
[tasks.test]
command = "cargo"
args = ["test", "--workspace", "--exclude", "espanso-modulo", "--no-default-features"]
args = ["test", "--workspace", "--exclude", "espanso-modulo", "--no-default-features"]
[tasks.test-output]
command = "cargo"
args = ["test", "--workspace", "--exclude", "espanso-modulo", "--no-default-features", "--", "--nocapture"]

View File

@ -53,6 +53,7 @@ fs_extra = "1.2.0"
dialoguer = "0.8.0"
colored = "2.0.0"
tempdir = "0.3.7"
notify = "4.0.17"
[target.'cfg(windows)'.dependencies]
named_pipe = "0.4.1"

View File

@ -20,34 +20,40 @@
use std::path::Path;
use anyhow::Result;
use crossbeam::channel::{Sender};
use crossbeam::channel::Sender;
use espanso_ipc::{EventHandlerResponse, IPCServer};
use log::{error, warn};
use crate::{exit_code::DAEMON_SUCCESS, ipc::IPCEvent};
pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<i32>) -> Result<()> {
let receiver = crate::ipc::spawn_daemon_ipc_server(runtime_dir)?;
let server = crate::ipc::create_daemon_ipc_server(runtime_dir)?;
std::thread::Builder::new()
.name("daemon-ipc-handler".to_string())
.spawn(move || loop {
match receiver.recv() {
Ok(event) => {
match event {
IPCEvent::Exit => {
if let Err(err) = exit_notify.send(DAEMON_SUCCESS) {
error!("experienced error while sending exit signal from daemon ipc handler: {}", err);
}
},
unexpected_event => {
warn!("received unexpected event in daemon ipc handler: {:?}", unexpected_event);
},
.spawn(move || {
server
.run(Box::new(move |event| match event {
IPCEvent::Exit => {
if let Err(err) = exit_notify.send(DAEMON_SUCCESS) {
error!(
"experienced error while sending exit signal from daemon ipc handler: {}",
err
);
}
EventHandlerResponse::NoResponse
}
}
Err(err) => {
error!("experienced error while receiving ipc event from daemon handler: {}", err);
}
}
unexpected_event => {
warn!(
"received unexpected event in daemon ipc handler: {:?}",
unexpected_event
);
EventHandlerResponse::NoResponse
}
}))
.expect("unable to start IPC handler");
})?;
Ok(())

View File

@ -27,11 +27,19 @@ use espanso_ipc::IPCClient;
use espanso_path::Paths;
use log::{error, info, warn};
use crate::{exit_code::{DAEMON_ALREADY_RUNNING, DAEMON_GENERAL_ERROR, DAEMON_LEGACY_ALREADY_RUNNING, DAEMON_SUCCESS, WORKER_EXIT_ALL_PROCESSES, WORKER_RESTART, WORKER_SUCCESS}, ipc::{create_ipc_client_to_worker, IPCEvent}, lock::{acquire_daemon_lock, acquire_legacy_lock, acquire_worker_lock}};
use crate::{
exit_code::{
DAEMON_ALREADY_RUNNING, DAEMON_GENERAL_ERROR, DAEMON_LEGACY_ALREADY_RUNNING, DAEMON_SUCCESS,
WORKER_EXIT_ALL_PROCESSES, WORKER_RESTART, WORKER_SUCCESS,
},
ipc::{create_ipc_client_to_worker, IPCEvent},
lock::{acquire_daemon_lock, acquire_legacy_lock, acquire_worker_lock},
};
use super::{CliModule, CliModuleArgs};
mod ipc;
mod watcher;
pub fn new() -> CliModule {
#[allow(clippy::needless_update)]
@ -72,10 +80,7 @@ fn daemon_main(args: CliModuleArgs) -> i32 {
info!("espanso version: {}", VERSION);
// TODO: print os system and version? (with os_info crate)
let worker_ipc = create_ipc_client_to_worker(&paths.runtime)
.expect("unable to create IPC client to worker process");
terminate_worker_if_already_running(&paths.runtime, worker_ipc);
terminate_worker_if_already_running(&paths.runtime);
let (exit_notify, exit_signal) = unbounded::<i32>();
@ -86,10 +91,49 @@ fn daemon_main(args: CliModuleArgs) -> i32 {
ipc::initialize_and_spawn(&paths.runtime, exit_notify.clone())
.expect("unable to initialize ipc server for daemon");
// TODO: start file watcher thread
let (watcher_notify, watcher_signal) = unbounded::<()>();
// TODO: check if "auto_restart" config option is enabled before starting it
watcher::initialize_and_spawn(&paths.config, watcher_notify)
.expect("unable to initialize config watcher thread");
loop {
select! {
recv(watcher_signal) -> _ => {
info!("configuration change detected, restarting worker process...");
match create_ipc_client_to_worker(&paths.runtime) {
Ok(mut worker_ipc) => {
if let Err(err) = worker_ipc.send_async(IPCEvent::Exit) {
error!(
"unable to send termination signal to worker process: {}",
err
);
}
}
Err(err) => {
error!("could not establish IPC connection with worker: {}", err);
}
}
// Wait until the worker process has terminated
let start = Instant::now();
let mut has_timed_out = true;
while start.elapsed() < std::time::Duration::from_secs(30) {
let lock_file = acquire_worker_lock(&paths.runtime);
if lock_file.is_some() {
has_timed_out = false;
break;
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
if !has_timed_out {
spawn_worker(&paths, exit_notify.clone());
} else {
error!("could not restart worker, as the exit process has timed out");
}
}
recv(exit_signal) -> code => {
match code {
Ok(code) => {
@ -120,18 +164,26 @@ fn daemon_main(args: CliModuleArgs) -> i32 {
DAEMON_SUCCESS
}
fn terminate_worker_if_already_running(runtime_dir: &Path, worker_ipc: impl IPCClient<IPCEvent>) {
fn terminate_worker_if_already_running(runtime_dir: &Path) {
let lock_file = acquire_worker_lock(&runtime_dir);
if lock_file.is_some() {
return;
}
warn!("a worker process is already running, sending termination signal...");
if let Err(err) = worker_ipc.send(IPCEvent::Exit) {
error!(
"unable to send termination signal to worker process: {}",
err
);
match create_ipc_client_to_worker(runtime_dir) {
Ok(mut worker_ipc) => {
if let Err(err) = worker_ipc.send_async(IPCEvent::Exit) {
error!(
"unable to send termination signal to worker process: {}",
err
);
}
}
Err(err) => {
error!("could not establish IPC connection with worker: {}", err);
}
}
let now = Instant::now();

View File

@ -0,0 +1,126 @@
/*
* 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 std::{path::Path, time::Duration};
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
use anyhow::Result;
use crossbeam::channel::Sender;
use log::{error, info, warn};
const WATCHER_DEBOUNCE_DURATION: u64 = 1;
pub fn initialize_and_spawn(config_dir: &Path, watcher_notify: Sender<()>) -> Result<()> {
let config_dir = config_dir.to_path_buf();
std::thread::Builder::new()
.name("watcher".to_string())
.spawn(move || loop {
watcher_main(&config_dir, &watcher_notify);
})?;
Ok(())
}
fn watcher_main(config_dir: &Path, watcher_notify: &Sender<()>) {
let (tx, rx) = std::sync::mpsc::channel();
let mut watcher: RecommendedWatcher =
Watcher::new(tx, Duration::from_secs(WATCHER_DEBOUNCE_DURATION))
.expect("unable to create file watcher");
watcher
.watch(&config_dir, RecursiveMode::Recursive)
.expect("unable to start file watcher");
info!("watching for changes in path: {:?}", config_dir);
loop {
let should_reload = match rx.recv() {
Ok(event) => {
let path = match event {
DebouncedEvent::Create(path) => Some(path),
DebouncedEvent::Write(path) => Some(path),
DebouncedEvent::Remove(path) => Some(path),
DebouncedEvent::Rename(_, path) => Some(path),
_ => None,
};
if let Some(path) = path {
let extension = path
.extension()
.unwrap_or_default()
.to_string_lossy()
.to_ascii_lowercase();
if ["yml", "yaml"].iter().any(|ext| ext == &extension) {
// Only load non-hidden yml files
!is_file_hidden(&path)
} else {
false
}
} else {
false
}
}
Err(e) => {
warn!("error while watching files: {:?}", e);
false
}
};
if should_reload {
if let Err(error) = watcher_notify.send(()) {
error!("unable to send watcher file changed event: {}", error);
}
}
}
}
fn is_file_hidden(path: &Path) -> bool {
let starts_with_dot = path
.file_name()
.unwrap_or_default()
.to_string_lossy()
.starts_with(".");
return starts_with_dot || has_hidden_attribute(path);
}
#[cfg(windows)]
fn has_hidden_attribute(path: &Path) -> bool {
use std::os::windows::prelude::*;
let metadata = std::fs::metadata(path);
if metadata.is_err() {
return false;
}
let attributes = metadata.unwrap().file_attributes();
if (attributes & 0x2) > 0 {
true
} else {
false
}
}
#[cfg(not(windows))]
fn has_hidden_attribute(path: &Path) -> bool {
false
}

View File

@ -20,34 +20,40 @@
use std::path::Path;
use anyhow::Result;
use crossbeam::channel::{Sender};
use crossbeam::channel::Sender;
use espanso_ipc::{EventHandlerResponse, IPCServer};
use log::{error, warn};
use crate::ipc::IPCEvent;
pub fn initialize_and_spawn(runtime_dir: &Path, exit_notify: Sender<()>) -> Result<()> {
let receiver = crate::ipc::spawn_worker_ipc_server(runtime_dir)?;
let server = crate::ipc::create_worker_ipc_server(runtime_dir)?;
std::thread::Builder::new()
.name("worker-ipc-handler".to_string())
.spawn(move || loop {
match receiver.recv() {
Ok(event) => {
match event {
.spawn(move || {
server.run(Box::new(move |event| {
match event {
IPCEvent::Exit => {
if let Err(err) = exit_notify.send(()) {
error!("experienced error while sending exit signal from worker ipc handler: {}", err);
error!(
"experienced error while sending exit signal from worker ipc handler: {}",
err
);
}
},
EventHandlerResponse::NoResponse
}
unexpected_event => {
warn!("received unexpected event in worker ipc handler: {:?}", unexpected_event);
},
warn!(
"received unexpected event in worker ipc handler: {:?}",
unexpected_event
);
EventHandlerResponse::NoResponse
}
}
}
Err(err) => {
error!("experienced error while receiving ipc event from worker handler: {}", err);
}
}
})).expect("unable to spawn IPC server");
})?;
Ok(())

View File

@ -68,6 +68,8 @@ fn worker_main(args: CliModuleArgs) -> i32 {
let match_store = args
.match_store
.expect("missing match store in worker main");
// TODO: show config loading errors in a GUI, if any
let icon_paths =
crate::icon::load_icon_paths(&paths.runtime).expect("unable to initialize icons");

View File

@ -18,7 +18,6 @@
*/
use anyhow::Result;
use crossbeam::channel::Receiver;
use espanso_ipc::{IPCServer, IPCClient};
use std::path::Path;
use serde::{Serialize, Deserialize};
@ -28,31 +27,23 @@ pub enum IPCEvent {
Exit,
}
pub fn spawn_daemon_ipc_server(runtime_dir: &Path) -> Result<Receiver<IPCEvent>> {
spawn_ipc_server(runtime_dir, "daemonv2")
pub fn create_daemon_ipc_server(runtime_dir: &Path) -> Result<impl IPCServer<IPCEvent>> {
create_ipc_server(runtime_dir, "daemonv2")
}
pub fn spawn_worker_ipc_server(runtime_dir: &Path) -> Result<Receiver<IPCEvent>> {
spawn_ipc_server(runtime_dir, "workerv2")
pub fn create_worker_ipc_server(runtime_dir: &Path) -> Result<impl IPCServer<IPCEvent>> {
create_ipc_server(runtime_dir, "workerv2")
}
pub fn create_ipc_client_to_worker(runtime_dir: &Path) -> Result<impl IPCClient<IPCEvent>> {
create_ipc_client(runtime_dir, "workerv2")
}
fn spawn_ipc_server(
fn create_ipc_server(
runtime_dir: &Path,
name: &str,
) -> Result<Receiver<IPCEvent>> {
let (server, receiver) = espanso_ipc::server(&format!("espanso{}", name), runtime_dir)?;
std::thread::Builder::new().name(format!("espanso-ipc-server-{}", name)).spawn(move || {
server.run().expect("unable to run ipc server");
})?;
// TODO: refactor the ipc server to handle a graceful exit?
Ok(receiver)
) -> Result<impl IPCServer<IPCEvent>> {
espanso_ipc::server(&format!("espanso{}", name), runtime_dir)
}