fix: notification of file changes in linked directories (#121)

This commit is contained in:
三咲雅 · Misaki Masa 2023-09-07 22:53:37 +08:00 committed by GitHub
parent 230362d6c7
commit 00932a77b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 16 deletions

View File

@ -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 anyhow::Result;
use shared::Url; use shared::Url;
@ -9,7 +9,7 @@ pub struct File {
pub(super) url: Url, pub(super) url: Url,
pub(super) meta: Metadata, pub(super) meta: Metadata,
pub(super) length: Option<u64>, pub(super) length: Option<u64>,
pub(super) link_to: Option<PathBuf>, pub(super) link_to: Option<Url>,
pub(super) is_link: bool, pub(super) is_link: bool,
pub(super) is_hidden: bool, pub(super) is_hidden: bool,
} }
@ -27,7 +27,7 @@ impl File {
if is_link { if is_link {
meta = fs::metadata(&url).await.unwrap_or(meta); 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()) }; let length = if meta.is_dir() { None } else { Some(meta.len()) };
@ -37,7 +37,7 @@ impl File {
} }
impl File { impl File {
// --- Path // --- Url
#[inline] #[inline]
pub fn url(&self) -> &Url { &self.url } pub fn url(&self) -> &Url { &self.url }
@ -80,5 +80,5 @@ impl File {
// --- Link to // --- Link to
#[inline] #[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() }
} }

View File

@ -136,7 +136,7 @@ impl Manager {
.map(|f| { .map(|f| {
( (
f.url_owned(), 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(); .collect();

View File

@ -99,7 +99,6 @@ impl Watcher {
} }
}) })
.collect(); .collect();
guard.sort_unstable_by(|_, a, _, b| b.cmp(a));
let lock = self.watched.clone(); let lock = self.watched.clone();
tokio::spawn(async move { tokio::spawn(async move {
@ -113,9 +112,7 @@ impl Watcher {
} }
} }
let mut guard = lock.write(); lock.write().extend(ext);
guard.extend(ext);
guard.sort_unstable_by(|_, a, _, b| b.cmp(a));
}); });
} }
@ -147,7 +144,7 @@ impl Watcher {
} }
} }
Self::file_changed(files.iter().collect()).await; Self::file_changed(&files, watched.clone()).await;
for file in files { for file in files {
emit!(Files(FilesOp::IOErr(file))); emit!(Files(FilesOp::IOErr(file)));
} }
@ -158,17 +155,34 @@ impl Watcher {
} }
} }
async fn file_changed(urls: Vec<&Url>) { async fn file_changed(urls: &[Url], watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>) {
if let Ok(mimes) = external::file(&urls).await { 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)); emit!(Mimetype(mimes));
} }
}
async fn dir_changed(url: &Url, watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>) { async fn dir_changed(url: &Url, watched: Arc<RwLock<IndexMap<Url, Option<Url>>>>) {
let linked: Vec<_> = watched let linked: Vec<_> = watched
.read() .read()
.iter() .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(); .collect();
let Ok(rx) = Files::from_dir(url).await else { let Ok(rx) = Files::from_dir(url).await else {