diff --git a/Cargo.lock b/Cargo.lock index 65751faa..204b8216 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", "version_check", "zerocopy", @@ -104,7 +104,7 @@ checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" dependencies = [ "async-lock", "autocfg", - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "futures-lite", "log", @@ -147,7 +147,7 @@ dependencies = [ "async-lock", "autocfg", "blocking", - "cfg-if 1.0.0", + "cfg-if", "event-listener", "futures-lite", "rustix 0.37.23", @@ -197,7 +197,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi 0.1.19", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -303,12 +303,6 @@ dependencies = [ "libc", ] -[[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" @@ -326,7 +320,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -371,7 +365,7 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -380,7 +374,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", @@ -394,7 +388,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -404,7 +398,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -416,7 +410,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "memoffset", "scopeguard", @@ -428,7 +422,7 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] @@ -438,7 +432,7 @@ version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -474,7 +468,7 @@ dependencies = [ "openssl-sys", "schannel", "socket2 0.4.9", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -490,7 +484,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -507,7 +501,7 @@ checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" dependencies = [ "libc", "libdbus-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -522,7 +516,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -534,7 +528,7 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -613,7 +607,7 @@ version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -682,7 +676,7 @@ version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall 0.3.5", "windows-sys", @@ -728,41 +722,15 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fsevent" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -dependencies = [ - "bitflags 1.3.2", - "fsevent-sys", -] - [[package]] name = "fsevent-sys" -version = "2.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" dependencies = [ "libc", ] -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "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 = "futures" version = "0.3.28" @@ -873,7 +841,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] @@ -1020,9 +988,9 @@ dependencies = [ [[package]] name = "inotify" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ "bitflags 1.3.2", "inotify-sys", @@ -1044,7 +1012,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -1058,15 +1026,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - [[package]] name = "isahc" version = "1.7.2" @@ -1121,26 +1080,30 @@ dependencies = [ ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "kqueue" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "kqueue-sys", + "libc", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "kqueue-sys" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" @@ -1164,8 +1127,8 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cfg-if 1.0.0", - "winapi 0.3.9", + "cfg-if", + "winapi", ] [[package]] @@ -1293,7 +1256,6 @@ dependencies = [ "linkify", "melib", "nix", - "notify", "notify-rust", "num_cpus", "pcre2", @@ -1393,45 +1355,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 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", + "wasi", + "windows-sys", ] [[package]] @@ -1452,17 +1383,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "nix" version = "0.27.1" @@ -1470,7 +1390,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ "bitflags 2.4.0", - "cfg-if 1.0.0", + "cfg-if", "libc", "memoffset", ] @@ -1487,20 +1407,21 @@ dependencies = [ [[package]] name = "notify" -version = "4.0.17" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.4.0", + "crossbeam-channel", "filetime", - "fsevent", "fsevent-sys", "inotify", + "kqueue", "libc", + "log", "mio", - "mio-extras", "walkdir", - "winapi 0.3.9", + "windows-sys", ] [[package]] @@ -1582,7 +1503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" dependencies = [ "bitflags 2.4.0", - "cfg-if 1.0.0", + "cfg-if", "foreign-types", "libc", "once_cell", @@ -1710,7 +1631,7 @@ checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" dependencies = [ "autocfg", "bitflags 1.3.2", - "cfg-if 1.0.0", + "cfg-if", "concurrent-queue", "libc", "log", @@ -1848,7 +1769,7 @@ dependencies = [ "spin", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2116,7 +2037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2216,7 +2137,7 @@ version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "fastrand 2.0.0", "redox_syscall 0.3.5", "rustix 0.38.9", @@ -2285,7 +2206,7 @@ version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "once_cell", ] @@ -2373,7 +2294,7 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -2512,7 +2433,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -2580,12 +2501,6 @@ dependencies = [ "untrusted", ] -[[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" @@ -2596,12 +2511,6 @@ 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" @@ -2614,7 +2523,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2750,16 +2659,6 @@ dependencies = [ "memchr", ] -[[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 = "xdg" version = "2.5.2" diff --git a/meli/Cargo.toml b/meli/Cargo.toml index 1593011f..ba6f18c6 100644 --- a/meli/Cargo.toml +++ b/meli/Cargo.toml @@ -33,7 +33,6 @@ libz-sys = { version = "1.1", features = ["static"], optional = true } linkify = { version = "^0.10", default-features = false } melib = { path = "../melib", version = "0.8.5-rc.3", features = [] } nix = { version = "0.27", default-features = false, features = ["signal", "poll", "term", "ioctl", "process"] } -notify = { version = "4.0.1", default-features = false } # >:c num_cpus = "1.12.0" serde = "1.0.71" serde_derive = "1.0.71" diff --git a/melib/Cargo.toml b/melib/Cargo.toml index b3ad509c..a10d86d9 100644 --- a/melib/Cargo.toml +++ b/melib/Cargo.toml @@ -39,7 +39,7 @@ log = { version = "0.4", features = ["std"] } native-tls = { version = "0.2.3", default-features = false, optional = true } nix = { version = "0.27", default-features = false, features = ["fs", "socket", "dir", "hostname"] } nom = { version = "7" } -notify = { version = "4.0.15", optional = true } +notify = { version = "6.1.1", optional = true } polling = "2.8" regex = { version = "1" } rusqlite = { version = "^0.29", default-features = false, features = ["array"], optional = true } @@ -70,7 +70,7 @@ nntp = ["tls"] nntp-trace = ["nntp"] maildir = ["notify"] mbox = ["notify"] -notmuch = [] +notmuch = ["notify"] smtp = ["tls", "base64"] smtp-trace = ["smtp"] sqlite3 = ["rusqlite"] diff --git a/melib/src/error.rs b/melib/src/error.rs index 42483988..12fe3f11 100644 --- a/melib/src/error.rs +++ b/melib/src/error.rs @@ -717,6 +717,24 @@ impl From for Error { } } +#[cfg(any(feature = "maildir", feature = "mbox", feature = "notmuch"))] +impl From for Error { + #[inline] + fn from(err: notify::Error) -> Self { + let kind = match err.kind { + notify::ErrorKind::MaxFilesWatch + | notify::ErrorKind::WatchNotFound + | notify::ErrorKind::Generic(_) => ErrorKind::External, + notify::ErrorKind::Io(_) => ErrorKind::OSError, + notify::ErrorKind::PathNotFound => ErrorKind::Configuration, + notify::ErrorKind::InvalidConfig(_) => ErrorKind::Bug, + }; + Self::new(err.to_string()) + .set_source(Some(Arc::new(err))) + .set_kind(kind) + } +} + impl From for Error { #[inline] fn from(kind: libloading::Error) -> Self { diff --git a/melib/src/maildir/backend.rs b/melib/src/maildir/backend.rs index 05d59546..992163ec 100644 --- a/melib/src/maildir/backend.rs +++ b/melib/src/maildir/backend.rs @@ -24,20 +24,6 @@ //! This module implements a maildir backend according to the maildir //! specification. -use futures::prelude::Stream; -use smallvec::SmallVec; - -use super::{MaildirMailbox, MaildirOp, MaildirPathTrait}; -use crate::{ - backends::{RefreshEventKind::*, *}, - conf::AccountSettings, - email::{Envelope, EnvelopeHash, Flag}, - error::{Error, ErrorKind, Result}, - utils::shellexpand::ShellExpandTrait, - Collection, -}; - -extern crate notify; use std::{ borrow::Cow, collections::{hash_map::DefaultHasher, HashMap, HashSet}, @@ -52,7 +38,19 @@ use std::{ time::Duration, }; -use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; +use futures::prelude::Stream; +use notify::{event::EventKind as NotifyEvent, RecommendedWatcher, RecursiveMode, Watcher}; +use smallvec::SmallVec; + +use super::{MaildirMailbox, MaildirOp, MaildirPathTrait}; +use crate::{ + backends::{RefreshEventKind::*, *}, + conf::AccountSettings, + email::{Envelope, EnvelopeHash, Flag}, + error::{Error, ErrorKind, IntoError, Result}, + utils::shellexpand::ShellExpandTrait, + Collection, +}; #[derive(Clone, Debug, PartialEq)] pub(super) enum PathMod { @@ -161,8 +159,8 @@ pub fn get_file_hash(file: &Path) -> EnvelopeHash { EnvelopeHash(hasher.finish()) } -pub fn move_to_cur(p: PathBuf) -> Result { - let mut new = p.clone(); +pub fn move_to_cur(p: &Path) -> Result { + let mut new = p.to_path_buf(); let file_name = p.to_string_lossy(); let slash_pos = file_name.bytes().rposition(|c| c == b'/').unwrap() + 1; new.pop(); @@ -173,8 +171,8 @@ pub fn move_to_cur(p: PathBuf) -> Result { if !file_name.ends_with(":2,") { new.set_extension(":2,"); } - debug!("moved to cur: {}", new.display()); - fs::rename(&p, &new)?; + log::trace!("moved to cur: {}", new.display()); + fs::rename(p, &new)?; Ok(new) } @@ -229,7 +227,7 @@ impl MailBackend for MaildirType { Ok(Box::pin(async move { let thunk = move |sender: &BackendEventConsumer| { - debug!("refreshing"); + log::trace!("refreshing"); let mut buf = Vec::with_capacity(4096); let files = Self::list_mail_in_maildir_fs(path.clone(), false)?; let mut current_hashes = { @@ -267,7 +265,7 @@ impl MailBackend for MaildirType { }), ); } else { - debug!( + log::trace!( "DEBUG: hash {}, path: {} couldn't be parsed", hash, file.as_path().display() @@ -301,15 +299,19 @@ impl MailBackend for MaildirType { } fn watch(&self) -> ResultFuture<()> { - let sender = self.event_consumer.clone(); - let (tx, rx) = channel(); - let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap(); let account_hash = AccountHash::from_bytes(self.name.as_bytes()); let root_mailbox = self.path.to_path_buf(); - watcher - .watch(&root_mailbox, RecursiveMode::Recursive) - .unwrap(); - debug!("watching {:?}", root_mailbox); + let sender = self.event_consumer.clone(); + let (tx, rx) = channel(); + let watcher = RecommendedWatcher::new( + tx, + notify::Config::default().with_poll_interval(Duration::from_secs(2)), + ) + .and_then(|mut watcher| { + watcher.watch(&root_mailbox, RecursiveMode::Recursive)?; + Ok(watcher) + }) + .map_err(|err| err.set_err_details("Failed to create file change monitor."))?; let hash_indexes = self.hash_indexes.clone(); let mailbox_index = self.mailbox_index.clone(); let root_mailbox_hash: MailboxHash = self @@ -329,201 +331,197 @@ impl MailBackend for MaildirType { let mut buf = Vec::with_capacity(4096); loop { match rx.recv() { - /* - * Event types: - * - * pub enum RefreshEventKind { - * Update(EnvelopeHash, Envelope), // Old hash, new envelope - * Create(Envelope), - * Remove(EnvelopeHash), - * Rescan, - * } - */ - Ok(event) => match event { + Ok(Ok(event)) => match event.kind { /* Create */ - DebouncedEvent::Create(mut pathbuf) => { - debug!("DebouncedEvent::Create(path = {:?}", pathbuf); - if path_is_new!(pathbuf) { - debug!("path_is_new"); - /* This creates a Rename event that we will receive later */ - pathbuf = match move_to_cur(pathbuf) { - Ok(p) => p, - Err(e) => { - debug!("error: {}", e.to_string()); - continue; - } - }; - } - let mailbox_hash = MailboxHash(get_path_hash!(pathbuf)); - let file_name = pathbuf - .as_path() - .strip_prefix(&root_mailbox) - .unwrap() - .to_path_buf(); - if let Ok(env) = add_path_to_index( - &hash_indexes, - mailbox_hash, - pathbuf.as_path(), - file_name, - &mut buf, - ) { - mailbox_index - .lock() - .unwrap() - .insert(env.hash(), mailbox_hash); - debug!( - "Create event {} {} {}", - env.hash(), - env.subject(), - pathbuf.display() - ); - if !env.is_seen() { - *mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1; + NotifyEvent::Create(_) => { + log::debug!("Create events: (path = {:?})", event.paths); + for mut pathbuf in event.paths { + if path_is_new!(pathbuf) { + // This creates a Rename event that we will receive later + pathbuf = match move_to_cur(&pathbuf) { + Ok(p) => p, + Err(err) => { + log::error!( + "Could not move {} to /cur: {}", + pathbuf.display(), + err + ); + pathbuf + } + }; } - *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1; - (sender)( - account_hash, - BackendEvent::Refresh(RefreshEvent { + let mailbox_hash = MailboxHash(get_path_hash!(pathbuf)); + let file_name = pathbuf + .as_path() + .strip_prefix(&root_mailbox) + .unwrap() + .to_path_buf(); + if let Ok(env) = add_path_to_index( + &hash_indexes, + mailbox_hash, + pathbuf.as_path(), + file_name, + &mut buf, + ) { + mailbox_index + .lock() + .unwrap() + .insert(env.hash(), mailbox_hash); + log::debug!( + "Create event {} {} {}", + env.hash(), + env.subject(), + pathbuf.display() + ); + if !env.is_seen() { + *mailbox_counts[&mailbox_hash].0.lock().unwrap() += 1; + } + *mailbox_counts[&mailbox_hash].1.lock().unwrap() += 1; + (sender)( account_hash, - mailbox_hash, - kind: Create(Box::new(env)), - }), - ); + BackendEvent::Refresh(RefreshEvent { + account_hash, + mailbox_hash, + kind: Create(Box::new(env)), + }), + ); + } } } - /* Update */ - DebouncedEvent::NoticeWrite(pathbuf) | DebouncedEvent::Write(pathbuf) => { - debug!("DebouncedEvent::Write(path = {:?}", &pathbuf); - let mailbox_hash = MailboxHash(get_path_hash!(pathbuf)); - let mut hash_indexes_lock = hash_indexes.lock().unwrap(); - let index_lock = - &mut hash_indexes_lock.entry(mailbox_hash).or_default(); - let file_name = pathbuf - .as_path() - .strip_prefix(&root_mailbox) - .unwrap() - .to_path_buf(); - /* Linear search in hash_index to find old hash */ - let old_hash: EnvelopeHash = { - if let Some((k, v)) = - index_lock.iter_mut().find(|(_, v)| *v.buf == pathbuf) - { - *v = pathbuf.clone().into(); - *k - } else { - drop(hash_indexes_lock); - /* Did we just miss a Create event? In any case, create - * envelope. */ - if let Ok(env) = add_path_to_index( - &hash_indexes, - mailbox_hash, - pathbuf.as_path(), - file_name, - &mut buf, - ) { - mailbox_index - .lock() - .unwrap() - .insert(env.hash(), mailbox_hash); + NotifyEvent::Modify( + notify::event::ModifyKind::Any + | notify::event::ModifyKind::Data(_) + | notify::event::ModifyKind::Other, + ) => { + log::debug!("Modify events: (path = {:?})", event.paths); + for pathbuf in event.paths { + let mailbox_hash = MailboxHash(get_path_hash!(pathbuf)); + let mut hash_indexes_lock = hash_indexes.lock().unwrap(); + let index_lock = + &mut hash_indexes_lock.entry(mailbox_hash).or_default(); + let file_name = pathbuf + .as_path() + .strip_prefix(&root_mailbox) + .unwrap() + .to_path_buf(); + /* Linear search in hash_index to find old hash */ + let old_hash: EnvelopeHash = { + if let Some((k, v)) = + index_lock.iter_mut().find(|(_, v)| *v.buf == pathbuf) + { + *v = pathbuf.clone().into(); + *k + } else { + drop(hash_indexes_lock); + /* Did we just miss a Create event? In any case, create + * envelope. */ + if let Ok(env) = add_path_to_index( + &hash_indexes, + mailbox_hash, + pathbuf.as_path(), + file_name, + &mut buf, + ) { + mailbox_index + .lock() + .unwrap() + .insert(env.hash(), mailbox_hash); + (sender)( + account_hash, + BackendEvent::Refresh(RefreshEvent { + account_hash, + mailbox_hash, + kind: Create(Box::new(env)), + }), + ); + } + continue; + } + }; + let new_hash: EnvelopeHash = get_file_hash(pathbuf.as_path()); + let mut reader = io::BufReader::new(fs::File::open(&pathbuf)?); + buf.clear(); + reader.read_to_end(&mut buf)?; + if index_lock.get_mut(&new_hash).is_none() { + if let Ok(mut env) = + Envelope::from_bytes(buf.as_slice(), Some(pathbuf.flags())) + { + env.set_hash(new_hash); + index_lock.insert(new_hash, pathbuf.into()); (sender)( account_hash, BackendEvent::Refresh(RefreshEvent { account_hash, mailbox_hash, - kind: Create(Box::new(env)), + kind: Update(old_hash, Box::new(env)), }), ); } + } + } + } + NotifyEvent::Remove(_) => { + for pathbuf in event.paths { + log::debug!("NotifyEvent::Remove(path = {:?}", pathbuf); + let mailbox_hash = MailboxHash(get_path_hash!(pathbuf)); + let mut hash_indexes_lock = hash_indexes.lock().unwrap(); + let index_lock = hash_indexes_lock.entry(mailbox_hash).or_default(); + let hash: EnvelopeHash = if let Some((k, _)) = + index_lock.iter().find(|(_, v)| *v.buf == pathbuf) + { + *k + } else { + log::debug!("removed but not contained in index"); + continue; + }; + if let Some(ref modif) = &index_lock[&hash].modified { + match modif { + PathMod::Path(path) => log::trace!( + "envelope {} has modified path set {}", + hash, + path.display() + ), + PathMod::Hash(hash) => log::trace!( + "envelope {} has modified path set {}", + hash, + &index_lock[hash].buf.display() + ), + } + index_lock.entry(hash).and_modify(|e| { + e.removed = false; + }); continue; } - }; - let new_hash: EnvelopeHash = get_file_hash(pathbuf.as_path()); - let mut reader = io::BufReader::new(fs::File::open(&pathbuf)?); - buf.clear(); - reader.read_to_end(&mut buf)?; - if index_lock.get_mut(&new_hash).is_none() { - debug!("write notice"); - if let Ok(mut env) = - Envelope::from_bytes(buf.as_slice(), Some(pathbuf.flags())) { - env.set_hash(new_hash); - debug!("{}\t{:?}", new_hash, &pathbuf); - debug!( - "hash {}, path: {:?} couldn't be parsed", - new_hash, &pathbuf - ); - index_lock.insert(new_hash, pathbuf.into()); - - /* Send Write notice */ - - (sender)( - account_hash, - BackendEvent::Refresh(RefreshEvent { - account_hash, - mailbox_hash, - kind: Update(old_hash, Box::new(env)), - }), - ); + let mut lck = mailbox_counts[&mailbox_hash].1.lock().unwrap(); + *lck = lck.saturating_sub(1); } - } - } - /* Remove */ - DebouncedEvent::NoticeRemove(pathbuf) | DebouncedEvent::Remove(pathbuf) => { - debug!("DebouncedEvent::Remove(path = {:?}", pathbuf); - let mailbox_hash = MailboxHash(get_path_hash!(pathbuf)); - let mut hash_indexes_lock = hash_indexes.lock().unwrap(); - let index_lock = hash_indexes_lock.entry(mailbox_hash).or_default(); - let hash: EnvelopeHash = if let Some((k, _)) = - index_lock.iter().find(|(_, v)| *v.buf == pathbuf) - { - *k - } else { - debug!("removed but not contained in index"); - continue; - }; - if let Some(ref modif) = &index_lock[&hash].modified { - match modif { - PathMod::Path(path) => debug!( - "envelope {} has modified path set {}", - hash, - path.display() - ), - PathMod::Hash(hash) => debug!( - "envelope {} has modified path set {}", - hash, - &index_lock[hash].buf.display() - ), + if !pathbuf.flags().contains(Flag::SEEN) { + let mut lck = mailbox_counts[&mailbox_hash].0.lock().unwrap(); + *lck = lck.saturating_sub(1); } + index_lock.entry(hash).and_modify(|e| { - e.removed = false; + e.removed = true; }); - continue; - } - { - let mut lck = mailbox_counts[&mailbox_hash].1.lock().unwrap(); - *lck = lck.saturating_sub(1); - } - if !pathbuf.flags().contains(Flag::SEEN) { - let mut lck = mailbox_counts[&mailbox_hash].0.lock().unwrap(); - *lck = lck.saturating_sub(1); - } - - index_lock.entry(hash).and_modify(|e| { - e.removed = true; - }); - (sender)( - account_hash, - BackendEvent::Refresh(RefreshEvent { + (sender)( account_hash, - mailbox_hash, - kind: Remove(hash), - }), - ); + BackendEvent::Refresh(RefreshEvent { + account_hash, + mailbox_hash, + kind: Remove(hash), + }), + ); + } } - /* Envelope hasn't changed */ - DebouncedEvent::Rename(src, dest) => { - debug!("DebouncedEvent::Rename(src = {:?}, dest = {:?})", src, dest); + NotifyEvent::Modify(notify::event::ModifyKind::Name( + notify::event::RenameMode::Both, + )) if event.paths.len() == 2 => { + let [ref src, ref dest] = event.paths[..] else { + unreachable!() + }; + log::debug!("NotifyEvent::Rename(src = {:?}, dest = {:?})", src, dest); let mailbox_hash = MailboxHash(get_path_hash!(src)); let dest_mailbox = { let dest_mailbox = MailboxHash(get_path_hash!(dest)); @@ -545,7 +543,6 @@ impl MailBackend for MaildirType { if index_lock.contains_key(&old_hash) && !index_lock[&old_hash].removed { - debug!("contains_old_key"); if let Some(dest_mailbox) = dest_mailbox { index_lock.entry(old_hash).and_modify(|e| { e.removed = true; @@ -576,7 +573,7 @@ impl MailBackend for MaildirType { .lock() .unwrap() .insert(env.hash(), dest_mailbox); - debug!( + log::trace!( "Create event {} {} {}", env.hash(), env.subject(), @@ -597,7 +594,6 @@ impl MailBackend for MaildirType { } } else { index_lock.entry(old_hash).and_modify(|e| { - debug!(&e.modified); e.modified = Some(PathMod::Hash(new_hash)); }); (sender)( @@ -626,7 +622,7 @@ impl MailBackend for MaildirType { ); } mailbox_index.lock().unwrap().insert(new_hash, mailbox_hash); - index_lock.insert(new_hash, dest.into()); + index_lock.insert(new_hash, dest.to_path_buf().into()); } continue; } else if !index_lock.contains_key(&new_hash) @@ -644,19 +640,19 @@ impl MailBackend for MaildirType { e.modified = Some(PathMod::Hash(new_hash)); e.removed = false; }); - debug!( + log::trace!( "contains_old_key, key was marked as removed (by external \ source)" ); } else { - debug!("not contains_new_key"); + log::trace!("not contains_new_key"); } let file_name = dest .as_path() .strip_prefix(&root_mailbox) .unwrap() .to_path_buf(); - debug!("filename = {:?}", file_name); + log::trace!("filename = {:?}", file_name); drop(hash_indexes_lock); if let Ok(env) = add_path_to_index( &hash_indexes, @@ -669,7 +665,7 @@ impl MailBackend for MaildirType { .lock() .unwrap() .insert(env.hash(), dest_mailbox.unwrap_or(mailbox_hash)); - debug!( + log::trace!( "Create event {} {} {}", env.hash(), env.subject(), @@ -695,7 +691,7 @@ impl MailBackend for MaildirType { ); continue; } else { - debug!("not valid email"); + log::trace!("not valid email"); } } else if let Some(dest_mailbox) = dest_mailbox { drop(hash_indexes_lock); @@ -715,7 +711,7 @@ impl MailBackend for MaildirType { .lock() .unwrap() .insert(env.hash(), dest_mailbox); - debug!( + log::trace!( "Create event {} {} {}", env.hash(), env.subject(), @@ -746,7 +742,7 @@ impl MailBackend for MaildirType { kind: Rename(old_hash, new_hash), }), ); - debug!("contains_new_key"); + log::trace!("contains_new_key"); if old_flags != new_flags { (sender)( account_hash, @@ -758,17 +754,10 @@ impl MailBackend for MaildirType { ); } } - - /* Maybe a re-read should be triggered here just to be safe. - (sender)(account_hash, BackendEvent::Refresh(RefreshEvent { - account_hash, - mailbox_hash: get_path_hash!(dest), - kind: Rescan, - })); - */ } - /* Trigger rescan of mailbox */ - DebouncedEvent::Rescan => { + _ => { + log::debug!("Received unexpected fs watcher notify event: {:?}", event); + /* Trigger rescan of mailbox */ (sender)( account_hash, BackendEvent::Refresh(RefreshEvent { @@ -778,9 +767,9 @@ impl MailBackend for MaildirType { }), ); } - _ => {} }, - Err(e) => debug!("watch error: {:?}", e), + Ok(Err(e)) => log::debug!("watch error: {:?}", e), + Err(e) => log::debug!("watch error: {:?}", e), } } })) @@ -949,13 +938,13 @@ impl MailBackend for MaildirType { hash_index.entry(env_hash).or_default().modified = Some(PathMod::Path(dest_path.clone())); if move_ { - debug!("renaming {:?} to {:?}", path_src, dest_path); + log::trace!("renaming {:?} to {:?}", path_src, dest_path); fs::rename(&path_src, &dest_path)?; - debug!("success in rename"); + log::trace!("success in rename"); } else { - debug!("copying {:?} to {:?}", path_src, dest_path); + log::trace!("copying {:?} to {:?}", path_src, dest_path); fs::copy(&path_src, &dest_path)?; - debug!("success in copy"); + log::trace!("success in copy"); } dest_path.pop(); } @@ -1290,7 +1279,7 @@ impl MaildirType { } path.push(filename); } - debug!("saving at {}", path.display()); + log::trace!("saving at {}", path.display()); let file = fs::File::create(path).unwrap(); let metadata = file.metadata()?; let mut permissions = metadata.permissions(); @@ -1327,7 +1316,7 @@ impl MaildirType { path.push("new"); for p in path.read_dir()?.flatten() { if !read_only { - move_to_cur(p.path()).ok().take(); + move_to_cur(&p.path()).ok().take(); } else { files.push(p.path()); } @@ -1348,7 +1337,7 @@ fn add_path_to_index( file_name: PathBuf, buf: &mut Vec, ) -> Result { - debug!("add_path_to_index path {:?} filename{:?}", path, file_name); + log::trace!("add_path_to_index path {:?} filename{:?}", path, file_name); let env_hash = get_file_hash(path); hash_index .lock() @@ -1361,7 +1350,7 @@ fn add_path_to_index( reader.read_to_end(buf)?; let mut env = Envelope::from_bytes(buf.as_slice(), Some(path.flags()))?; env.set_hash(env_hash); - debug!( + log::trace!( "add_path_to_index gen {}\t{}", env_hash, file_name.display() diff --git a/melib/src/maildir/stream.rs b/melib/src/maildir/stream.rs index 49d34039..20f58024 100644 --- a/melib/src/maildir/stream.rs +++ b/melib/src/maildir/stream.rs @@ -54,7 +54,7 @@ impl MaildirStream { let chunk_size = 2048; path.push("new"); for p in path.read_dir()?.flatten() { - move_to_cur(p.path()).ok().take(); + move_to_cur(&p.path()).ok().take(); } path.pop(); path.push("cur"); diff --git a/melib/src/mbox/mod.rs b/melib/src/mbox/mod.rs index 6bb0b21f..a74f5957 100644 --- a/melib/src/mbox/mod.rs +++ b/melib/src/mbox/mod.rs @@ -144,7 +144,7 @@ use crate::{ collection::Collection, conf::AccountSettings, email::{parser::BytesExt, *}, - error::{Error, ErrorKind, Result}, + error::{Error, ErrorKind, IntoError, Result}, get_path_hash, utils::shellexpand::ShellExpandTrait, }; @@ -162,10 +162,9 @@ use std::{ }; use futures::Stream; +use notify::{event::EventKind as NotifyEvent, RecommendedWatcher, RecursiveMode, Watcher}; use smallvec::SmallVec; -use self::notify::{watcher, DebouncedEvent, RecursiveMode, Watcher}; - pub mod write; pub type Offset = usize; @@ -451,7 +450,7 @@ impl MboxFormat { } } Err(err) => { - debug!("Could not parse mail {:?}", err); + log::debug!("Could not parse mail {:?}", err); Err(nom::Err::Error(NomError { input, code: NomErrorKind::Tag, @@ -498,7 +497,7 @@ impl MboxFormat { Ok((&[], env)) } Err(err) => { - debug!("Could not parse mail at {:?}", err); + log::debug!("Could not parse mail at {:?}", err); Err(nom::Err::Error(NomError { input, code: NomErrorKind::Tag, @@ -555,7 +554,7 @@ impl MboxFormat { } } Err(err) => { - debug!("Could not parse mail {:?}", err); + log::debug!("Could not parse mail {:?}", err); Err(nom::Err::Error(NomError { input, code: NomErrorKind::Tag, @@ -602,7 +601,7 @@ impl MboxFormat { Ok((&[], env)) } Err(err) => { - debug!("Could not parse mail {:?}", err); + log::debug!("Could not parse mail {:?}", err); Err(nom::Err::Error(NomError { input, code: NomErrorKind::Tag, @@ -953,118 +952,129 @@ impl MailBackend for MboxType { fn watch(&self) -> ResultFuture<()> { let sender = self.event_consumer.clone(); let (tx, rx) = channel(); - let mut watcher = watcher(tx, std::time::Duration::from_secs(10)) - .map_err(|e| e.to_string()) - .map_err(Error::new)?; - { - let mailboxes_lck = self.mailboxes.lock().unwrap(); - for f in mailboxes_lck.values() { - watcher - .watch(&f.fs_path, RecursiveMode::Recursive) - .map_err(|e| e.to_string()) - .map_err(Error::new)?; - log::debug!("watching {:?}", f.fs_path.as_path()); + let watcher = RecommendedWatcher::new( + tx, + notify::Config::default().with_poll_interval(std::time::Duration::from_secs(10)), + ) + .and_then(|mut watcher| { + { + let mailboxes_lck = self.mailboxes.lock().unwrap(); + for f in mailboxes_lck.values() { + watcher.watch(&f.fs_path, RecursiveMode::Recursive)?; + log::debug!("watching {:?}", f.fs_path.as_path()); + } } - } + Ok(watcher) + }) + .map_err(|err| err.set_err_details("Failed to create file change monitor."))?; let account_hash = AccountHash::from_bytes(self.account_name.as_bytes()); let mailboxes = self.mailboxes.clone(); let mailbox_index = self.mailbox_index.clone(); let prefer_mbox_type = self.prefer_mbox_type; Ok(Box::pin(async move { + let _watcher = watcher; loop { match rx.recv() { - /* - * Event types: - * - * pub enum RefreshEventKind { - * Update(EnvelopeHash, Envelope), // Old hash, new envelope - * Create(Envelope), - * Remove(EnvelopeHash), - * Rescan, - * } - */ - Ok(event) => match event { + Ok(Ok(event)) => match event.kind { /* Update */ - DebouncedEvent::NoticeWrite(pathbuf) | DebouncedEvent::Write(pathbuf) => { - let mailbox_hash = MailboxHash(get_path_hash!(&pathbuf)); - let file = match std::fs::OpenOptions::new() - .read(true) - .write(true) - .open(&pathbuf) - { - Ok(f) => f, - Err(_) => { + NotifyEvent::Modify( + notify::event::ModifyKind::Any + | notify::event::ModifyKind::Data(_) + | notify::event::ModifyKind::Other, + ) => { + for pathbuf in event.paths { + let mailbox_hash = MailboxHash(get_path_hash!(&pathbuf)); + let file = match std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(&pathbuf) + { + Ok(f) => f, + Err(_) => { + continue; + } + }; + get_rw_lock_blocking(&file, &pathbuf)?; + let mut mailbox_lock = mailboxes.lock().unwrap(); + let mut buf_reader = BufReader::new(file); + let mut contents = Vec::new(); + if let Err(e) = buf_reader.read_to_end(&mut contents) { + debug!(e); continue; - } - }; - get_rw_lock_blocking(&file, &pathbuf)?; - let mut mailbox_lock = mailboxes.lock().unwrap(); - let mut buf_reader = BufReader::new(file); - let mut contents = Vec::new(); - if let Err(e) = buf_reader.read_to_end(&mut contents) { - debug!(e); - continue; - }; - if contents.starts_with(mailbox_lock[&mailbox_hash].content.as_slice()) - { - if let Ok((_, envelopes)) = mbox_parse( - mailbox_lock[&mailbox_hash].index.clone(), - &contents, - mailbox_lock[&mailbox_hash].content.len(), - prefer_mbox_type, - ) { - let mut mailbox_index_lck = mailbox_index.lock().unwrap(); - for env in envelopes { - mailbox_index_lck.insert(env.hash(), mailbox_hash); - (sender)( - account_hash, - BackendEvent::Refresh(RefreshEvent { + }; + if contents + .starts_with(mailbox_lock[&mailbox_hash].content.as_slice()) + { + if let Ok((_, envelopes)) = mbox_parse( + mailbox_lock[&mailbox_hash].index.clone(), + &contents, + mailbox_lock[&mailbox_hash].content.len(), + prefer_mbox_type, + ) { + let mut mailbox_index_lck = mailbox_index.lock().unwrap(); + for env in envelopes { + mailbox_index_lck.insert(env.hash(), mailbox_hash); + (sender)( account_hash, - mailbox_hash, - kind: RefreshEventKind::Create(Box::new(env)), - }), - ); + BackendEvent::Refresh(RefreshEvent { + account_hash, + mailbox_hash, + kind: RefreshEventKind::Create(Box::new(env)), + }), + ); + } } + } else { + (sender)( + account_hash, + BackendEvent::Refresh(RefreshEvent { + account_hash, + mailbox_hash, + kind: RefreshEventKind::Rescan, + }), + ); } - } else { - (sender)( - account_hash, - BackendEvent::Refresh(RefreshEvent { + mailbox_lock + .entry(mailbox_hash) + .and_modify(|f| f.content = contents); + } + } + NotifyEvent::Remove(_) => { + for pathbuf in event.paths { + if mailboxes + .lock() + .unwrap() + .values() + .any(|f| f.fs_path == pathbuf) + { + let mailbox_hash = MailboxHash(get_path_hash!(&pathbuf)); + (sender)( account_hash, - mailbox_hash, - kind: RefreshEventKind::Rescan, - }), - ); + BackendEvent::Refresh(RefreshEvent { + account_hash, + mailbox_hash, + kind: RefreshEventKind::Failure(Error::new(format!( + "mbox mailbox {} was removed.", + pathbuf.display() + ))), + }), + ); + return Ok(()); + } } - mailbox_lock - .entry(mailbox_hash) - .and_modify(|f| f.content = contents); } - /* Remove */ - DebouncedEvent::NoticeRemove(pathbuf) | DebouncedEvent::Remove(pathbuf) => { + NotifyEvent::Modify(notify::event::ModifyKind::Name( + notify::event::RenameMode::Both, + )) if event.paths.len() == 2 => { + let [ref src, ref dest] = event.paths[..] else { + unreachable!() + }; if mailboxes .lock() .unwrap() .values() - .any(|f| f.fs_path == pathbuf) + .any(|f| f.fs_path == *src) { - let mailbox_hash = MailboxHash(get_path_hash!(&pathbuf)); - (sender)( - account_hash, - BackendEvent::Refresh(RefreshEvent { - account_hash, - mailbox_hash, - kind: RefreshEventKind::Failure(Error::new(format!( - "mbox mailbox {} was removed.", - pathbuf.display() - ))), - }), - ); - return Ok(()); - } - } - DebouncedEvent::Rename(src, dest) => { - if mailboxes.lock().unwrap().values().any(|f| f.fs_path == src) { let mailbox_hash = MailboxHash(get_path_hash!(&src)); (sender)( account_hash, @@ -1081,8 +1091,9 @@ impl MailBackend for MboxType { return Ok(()); } } - /* Trigger rescan of mailboxes */ - DebouncedEvent::Rescan => { + _ => { + log::debug!("Received unexpected fs watcher notify event: {:?}", event); + /* Trigger rescan of mailboxes */ let mailboxes_lck = mailboxes.lock().unwrap(); for &mailbox_hash in mailboxes_lck.keys() { (sender)( @@ -1096,12 +1107,12 @@ impl MailBackend for MboxType { } return Ok(()); } - _ => {} }, - Err(e) => { - log::debug!("watch error: {:?}", e); + Ok(Err(err)) => log::debug!("watch error: {:?}", err), + Err(err) => { + log::debug!("watch error: {:?}", err); return Err(Error::new(format!( - "Mbox watching thread exited with error: {e}" + "Mbox watching thread exited with error: {err}" ))); } } diff --git a/melib/src/notmuch/mod.rs b/melib/src/notmuch/mod.rs index 1994293b..84ab424f 100644 --- a/melib/src/notmuch/mod.rs +++ b/melib/src/notmuch/mod.rs @@ -32,15 +32,16 @@ use std::{ }; use futures::Stream; +use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use smallvec::SmallVec; use crate::{ backends::*, conf::AccountSettings, email::{Envelope, EnvelopeHash, Flag}, - error::{Error, Result}, + error::{Error, ErrorKind, IntoError, Result}, utils::shellexpand::ShellExpandTrait, - Collection, ErrorKind, + Collection, }; macro_rules! call { @@ -698,9 +699,6 @@ impl MailBackend for NotmuchDb { } fn watch(&self) -> ResultFuture<()> { - extern crate notify; - use notify::{watcher, RecursiveMode, Watcher}; - let account_hash = self.account_hash; let tag_index = self.collection.tag_index.clone(); let lib = self.lib.clone(); @@ -712,8 +710,15 @@ impl MailBackend for NotmuchDb { let event_consumer = self.event_consumer.clone(); let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = watcher(tx, std::time::Duration::from_secs(2)).unwrap(); - watcher.watch(&self.path, RecursiveMode::Recursive).unwrap(); + let watcher = RecommendedWatcher::new( + tx, + notify::Config::default().with_poll_interval(std::time::Duration::from_secs(2)), + ) + .and_then(|mut watcher| { + watcher.watch(&self.path, RecursiveMode::Recursive)?; + Ok(watcher) + }) + .map_err(|err| err.set_err_details("Failed to create file change monitor."))?; Ok(Box::pin(async move { let _watcher = watcher; let rx = rx;