From 00932a77b760b0459e77ac8444f0a11eb030564d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Thu, 7 Sep 2023 22:53:37 +0800 Subject: [PATCH] fix: notification of file changes in linked directories (#121) --- core/src/files/file.rs | 10 +++++----- core/src/manager/manager.rs | 2 +- core/src/manager/watcher.rs | 34 ++++++++++++++++++++++++---------- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/core/src/files/file.rs b/core/src/files/file.rs index abfdbf38..fb6bc342 100644 --- a/core/src/files/file.rs +++ b/core/src/files/file.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, ffi::OsStr, fs::Metadata, path::PathBuf}; +use std::{borrow::Cow, ffi::OsStr, fs::Metadata}; use anyhow::Result; use shared::Url; @@ -9,7 +9,7 @@ pub struct File { pub(super) url: Url, pub(super) meta: Metadata, pub(super) length: Option, - pub(super) link_to: Option, + pub(super) link_to: Option, pub(super) is_link: bool, pub(super) is_hidden: bool, } @@ -27,7 +27,7 @@ impl File { if is_link { meta = fs::metadata(&url).await.unwrap_or(meta); - link_to = fs::read_link(&url).await.ok(); + link_to = fs::read_link(&url).await.map(Url::from).ok(); } let length = if meta.is_dir() { None } else { Some(meta.len()) }; @@ -37,7 +37,7 @@ impl File { } impl File { - // --- Path + // --- Url #[inline] pub fn url(&self) -> &Url { &self.url } @@ -80,5 +80,5 @@ impl File { // --- Link to #[inline] - pub fn link_to(&self) -> Option<&PathBuf> { self.link_to.as_ref() } + pub fn link_to(&self) -> Option<&Url> { self.link_to.as_ref() } } diff --git a/core/src/manager/manager.rs b/core/src/manager/manager.rs index 518d3892..a7761e68 100644 --- a/core/src/manager/manager.rs +++ b/core/src/manager/manager.rs @@ -136,7 +136,7 @@ impl Manager { .map(|f| { ( f.url_owned(), - if f.is_dir() { Some(MIME_DIR.to_owned()) } else { self.mimetype.get(f.url()).cloned() }, + f.is_dir().then(|| MIME_DIR.to_owned()).or_else(|| self.mimetype.get(f.url()).cloned()), ) }) .collect(); diff --git a/core/src/manager/watcher.rs b/core/src/manager/watcher.rs index d501de04..1e6c3fcd 100644 --- a/core/src/manager/watcher.rs +++ b/core/src/manager/watcher.rs @@ -99,7 +99,6 @@ impl Watcher { } }) .collect(); - guard.sort_unstable_by(|_, a, _, b| b.cmp(a)); let lock = self.watched.clone(); tokio::spawn(async move { @@ -113,9 +112,7 @@ impl Watcher { } } - let mut guard = lock.write(); - guard.extend(ext); - guard.sort_unstable_by(|_, a, _, b| b.cmp(a)); + lock.write().extend(ext); }); } @@ -147,7 +144,7 @@ impl Watcher { } } - Self::file_changed(files.iter().collect()).await; + Self::file_changed(&files, watched.clone()).await; for file in files { emit!(Files(FilesOp::IOErr(file))); } @@ -158,17 +155,34 @@ impl Watcher { } } - async fn file_changed(urls: Vec<&Url>) { - if let Ok(mimes) = external::file(&urls).await { - emit!(Mimetype(mimes)); - } + async fn file_changed(urls: &[Url], watched: Arc>>>) { + let Ok(mut mimes) = external::file(urls).await else { + return; + }; + + let linked: Vec<_> = watched + .read() + .iter() + .filter_map(|(k, v)| v.as_ref().map(|v| (k, v))) + .fold(Vec::new(), |mut aac, (k, v)| { + mimes + .iter() + .filter(|(f, _)| f.parent().map(|p| p == **v) == Some(true)) + .for_each(|(f, m)| aac.push((k.join(f.file_name().unwrap()), m.clone()))); + aac + }); + + mimes.extend(linked); + emit!(Mimetype(mimes)); } async fn dir_changed(url: &Url, watched: Arc>>>) { let linked: Vec<_> = watched .read() .iter() - .map_while(|(k, v)| v.as_ref().and_then(|v| url.strip_prefix(v)).map(|v| k.join(v))) + .filter_map(|(k, v)| v.as_ref().map(|v| (k, v))) + .filter(|(_, v)| *v == url) + .map(|(k, _)| k.clone()) .collect(); let Ok(rx) = Files::from_dir(url).await else {