From c176de9a30c721a3f5de970e691546fcbe031afc Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 4 Apr 2026 21:10:44 +0800 Subject: [PATCH] .. --- yazi-actor/src/app/plugin_do.rs | 6 ++---- yazi-scheduler/src/fetch/progress.rs | 4 ++-- yazi-scheduler/src/file/progress.rs | 8 ++++---- yazi-scheduler/src/hook/hook.rs | 15 +++++++++++++-- yazi-scheduler/src/hook/in.rs | 16 ++++++++++++++++ yazi-scheduler/src/plugin/progress.rs | 4 ++-- yazi-scheduler/src/preload/in.rs | 3 +-- yazi-scheduler/src/preload/out.rs | 4 ++++ yazi-scheduler/src/preload/preload.rs | 12 +++--------- yazi-scheduler/src/preload/progress.rs | 15 ++++++++------- yazi-scheduler/src/process/progress.rs | 12 ++++++------ yazi-scheduler/src/scheduler.rs | 12 +++++++++--- yazi-scheduler/src/worker.rs | 23 +++++++++++------------ 13 files changed, 81 insertions(+), 53 deletions(-) diff --git a/yazi-actor/src/app/plugin_do.rs b/yazi-actor/src/app/plugin_do.rs index 6120f721..9a28e808 100644 --- a/yazi-actor/src/app/plugin_do.rs +++ b/yazi-actor/src/app/plugin_do.rs @@ -4,11 +4,10 @@ use scopeguard::defer; use tracing::{error, warn}; use yazi_binding::runtime_mut; use yazi_core::app::PluginMode; -use yazi_dds::Sendable; use yazi_macro::succ; use yazi_parser::app::PluginForm; use yazi_plugin::LUA; -use yazi_runner::loader::{LOADER, Loader}; +use yazi_runner::{entry::EntryJob, loader::{LOADER, Loader}}; use yazi_scheduler::NotifyProxy; use yazi_shared::data::Data; @@ -48,8 +47,7 @@ impl Actor for PluginDo { if let Some(cb) = opt.callback { cb(&LUA, plugin) } else { - let job = LUA.create_table_from([("args", Sendable::args_to_table(&LUA, opt.args)?)])?; - plugin.call_method("entry", job) + plugin.call_method("entry", EntryJob { args: opt.args, ..Default::default() }) } }); if let Err(ref e) = result { diff --git a/yazi-scheduler/src/fetch/progress.rs b/yazi-scheduler/src/fetch/progress.rs index 33c6e346..f63c1b28 100644 --- a/yazi-scheduler/src/fetch/progress.rs +++ b/yazi-scheduler/src/fetch/progress.rs @@ -11,8 +11,8 @@ impl From for TaskSummary { fn from(value: FetchProg) -> Self { Self { total: 1, - success: (value.state == Some(true)) as u32, - failed: (value.state == Some(false)) as u32, + success: value.success() as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } diff --git a/yazi-scheduler/src/file/progress.rs b/yazi-scheduler/src/file/progress.rs index d69bbaa1..2c1f5e8d 100644 --- a/yazi-scheduler/src/file/progress.rs +++ b/yazi-scheduler/src/file/progress.rs @@ -119,8 +119,8 @@ impl From for TaskSummary { fn from(value: FileProgLink) -> Self { Self { total: 1, - success: (value.state == Some(true)) as u32, - failed: (value.state == Some(false)) as u32, + success: value.success() as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } @@ -243,8 +243,8 @@ impl From for TaskSummary { fn from(value: FileProgTrash) -> Self { Self { total: 1, - success: (value.state == Some(true)) as u32, - failed: (value.state == Some(false)) as u32, + success: value.success() as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } diff --git a/yazi-scheduler/src/hook/hook.rs b/yazi-scheduler/src/hook/hook.rs index 90b2cc55..b4a23837 100644 --- a/yazi-scheduler/src/hook/hook.rs +++ b/yazi-scheduler/src/hook/hook.rs @@ -6,11 +6,12 @@ use yazi_dds::Pump; use yazi_fs::ok_or_not_found; use yazi_vfs::provider; -use crate::{Ongoing, TaskOp, TaskOps, TasksProxy, file::{FileOutCopy, FileOutCut, FileOutDelete, FileOutDownload, FileOutHardlink, FileOutLink, FileOutTrash, FileOutUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInOutCopy, HookInOutCut, HookInOutHardlink, HookInOutLink, HookInTrash, HookInUpload}}; +use crate::{Ongoing, TaskOp, TaskOps, TasksProxy, file::{FileOutCopy, FileOutCut, FileOutDelete, FileOutDownload, FileOutHardlink, FileOutLink, FileOutTrash, FileOutUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInOutCopy, HookInOutCut, HookInOutHardlink, HookInOutLink, HookInPreload, HookInTrash, HookInUpload}, preload::{Preload, PreloadOut}}; pub(crate) struct Hook { ops: TaskOps, ongoing: Arc>, + preload: Arc, tx: async_priority_channel::Sender, } @@ -18,9 +19,10 @@ impl Hook { pub(crate) fn new( ops: &mpsc::UnboundedSender, ongoing: &Arc>, + preload: &Arc, tx: async_priority_channel::Sender, ) -> Self { - Self { ops: ops.into(), ongoing: ongoing.clone(), tx } + Self { ops: ops.into(), ongoing: ongoing.clone(), preload: preload.clone(), tx } } // --- File @@ -98,6 +100,15 @@ impl Hook { } self.ops.out(task.id, FileOutUpload::Clean); } + + // --- Preload + pub(crate) async fn preload(&self, task: HookInPreload) { + if !self.ongoing.lock().intact(task.id) { + self.preload.loaded.lock().get_mut(&task.hash).map(|x| *x &= !(1 << task.idx)); + } + + self.ops.out(task.id, PreloadOut::Clean); + } } impl Hook { diff --git a/yazi-scheduler/src/hook/in.rs b/yazi-scheduler/src/hook/in.rs index 4d1f7024..31a5259b 100644 --- a/yazi-scheduler/src/hook/in.rs +++ b/yazi-scheduler/src/hook/in.rs @@ -12,6 +12,7 @@ pub(crate) enum HookIn { Hardlink(HookInOutHardlink), Download(HookInDownload), Upload(HookInUpload), + Preload(HookInPreload), } impl_from_in!( @@ -23,6 +24,7 @@ impl_from_in!( Hardlink(HookInOutHardlink), Download(HookInDownload), Upload(HookInUpload), + Preload(HookInPreload), ); impl HookIn { @@ -36,6 +38,7 @@ impl HookIn { Self::Hardlink(r#in) => r#in.id, Self::Download(r#in) => r#in.id, Self::Upload(r#in) => r#in.id, + Self::Preload(r#in) => r#in.id, } } @@ -49,6 +52,7 @@ impl HookIn { Self::Hardlink(r#in) => Self::Hardlink(HookInOutHardlink { id, ..r#in }), Self::Download(r#in) => Self::Download(HookInDownload { id, ..r#in }), Self::Upload(r#in) => Self::Upload(HookInUpload { id, ..r#in }), + Self::Preload(r#in) => Self::Preload(HookInPreload { id, ..r#in }), } } } @@ -210,3 +214,15 @@ impl HookInUpload { Self { id: Id::ZERO, target: target.into() } } } + +// --- Preload +#[derive(Debug)] +pub(crate) struct HookInPreload { + pub(crate) id: Id, + pub(crate) idx: u8, + pub(crate) hash: u64, +} + +impl HookInPreload { + pub(crate) fn new(idx: u8, hash: u64) -> Self { Self { id: Id::ZERO, idx, hash } } +} diff --git a/yazi-scheduler/src/plugin/progress.rs b/yazi-scheduler/src/plugin/progress.rs index 87fb45a8..a2f1d71c 100644 --- a/yazi-scheduler/src/plugin/progress.rs +++ b/yazi-scheduler/src/plugin/progress.rs @@ -12,8 +12,8 @@ impl From for TaskSummary { fn from(value: PluginProgEntry) -> Self { Self { total: 1, - success: (value.state == Some(true)) as u32, - failed: (value.state == Some(false)) as u32, + success: value.success() as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } diff --git a/yazi-scheduler/src/preload/in.rs b/yazi-scheduler/src/preload/in.rs index 8aefba6a..ab15fcd0 100644 --- a/yazi-scheduler/src/preload/in.rs +++ b/yazi-scheduler/src/preload/in.rs @@ -1,10 +1,9 @@ use yazi_config::plugin::Preloader; -use yazi_shared::{CompletionToken, Id}; +use yazi_shared::Id; #[derive(Clone, Debug)] pub(crate) struct PreloadIn { pub(crate) id: Id, pub(crate) plugin: &'static Preloader, pub(crate) target: yazi_fs::File, - pub(crate) done: CompletionToken, } diff --git a/yazi-scheduler/src/preload/out.rs b/yazi-scheduler/src/preload/out.rs index 991eb45e..9cef4d44 100644 --- a/yazi-scheduler/src/preload/out.rs +++ b/yazi-scheduler/src/preload/out.rs @@ -6,6 +6,7 @@ use crate::{Task, TaskProg}; pub(crate) enum PreloadOut { Succ, Fail(String), + Clean, } impl From for PreloadOut { @@ -23,6 +24,9 @@ impl PreloadOut { prog.state = Some(false); task.log(reason); } + Self::Clean => { + prog.cleaned = Some(true); + } } } } diff --git a/yazi-scheduler/src/preload/preload.rs b/yazi-scheduler/src/preload/preload.rs index e8ef34c5..bc0c2ee7 100644 --- a/yazi-scheduler/src/preload/preload.rs +++ b/yazi-scheduler/src/preload/preload.rs @@ -8,7 +8,6 @@ use tracing::error; use yazi_config::Priority; use yazi_fs::FsHash64; use yazi_runner::{RUNNER, preloader::{PreloadError, PreloadJob}}; -use yazi_shared::CompletionToken; use crate::{HIGH, LOW, NORMAL, TaskOp, TaskOps, preload::{PreloadIn, PreloadOut}}; @@ -17,7 +16,7 @@ pub struct Preload { tx: async_priority_channel::Sender, pub loaded: Mutex>, - pub loading: Mutex>, + pub loading: Mutex>, } impl Preload { @@ -35,12 +34,7 @@ impl Preload { } pub(crate) async fn preload(&self, task: PreloadIn) -> Result<(), PreloadOut> { - let url_hash = task.target.url.hash_u64(); - let file_hash = task.target.hash_u64(); - - if let Some(prev) = self.loading.lock().put(url_hash, task.done) { - prev.complete(false); - } + let hash = task.target.hash_u64(); let mut rx = RUNNER.preload(PreloadJob { action: &task.plugin.run, file: task.target }).await; let state = match rx.recv().await.unwrap_or(Err(PreloadError::Cancelled)) { @@ -50,7 +44,7 @@ impl Preload { }; if !state.complete { - self.loaded.lock().get_mut(&file_hash).map(|x| *x &= !(1 << task.plugin.idx)); + self.loaded.lock().get_mut(&hash).map(|x| *x &= !(1 << task.plugin.idx)); } if let Some(e) = state.error { error!("Error when running preloader `{}`:\n{e}", task.plugin.run.name); diff --git a/yazi-scheduler/src/preload/progress.rs b/yazi-scheduler/src/preload/progress.rs index 101b8d8b..e28c8969 100644 --- a/yazi-scheduler/src/preload/progress.rs +++ b/yazi-scheduler/src/preload/progress.rs @@ -4,15 +4,16 @@ use crate::TaskSummary; #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)] pub struct PreloadProg { - pub state: Option, + pub state: Option, + pub cleaned: Option, } impl From for TaskSummary { fn from(value: PreloadProg) -> Self { Self { total: 1, - success: (value.state == Some(true)) as u32, - failed: (value.state == Some(false)) as u32, + success: value.success() as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } @@ -21,13 +22,13 @@ impl From for TaskSummary { impl PreloadProg { pub fn cooked(self) -> bool { self.state == Some(true) } - pub fn running(self) -> bool { self.state.is_none() } + pub fn running(self) -> bool { self.state.is_none() || (self.cleaned.is_none() && self.cooked()) } - pub fn success(self) -> bool { self.cooked() } + pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() } - pub fn failed(self) -> bool { self.state == Some(false) } + pub fn failed(self) -> bool { self.cleaned == Some(false) || self.state == Some(false) } - pub fn cleaned(self) -> Option { None } + pub fn cleaned(self) -> Option { self.cleaned } pub fn percent(self) -> Option { None } } diff --git a/yazi-scheduler/src/process/progress.rs b/yazi-scheduler/src/process/progress.rs index 0128e1b6..69c8357e 100644 --- a/yazi-scheduler/src/process/progress.rs +++ b/yazi-scheduler/src/process/progress.rs @@ -11,9 +11,9 @@ pub struct ProcessProgBlock { impl From for TaskSummary { fn from(value: ProcessProgBlock) -> Self { Self { - total: (value.state == Some(false)) as u32, + total: value.failed() as u32, success: 0, - failed: (value.state == Some(false)) as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } @@ -42,9 +42,9 @@ pub struct ProcessProgOrphan { impl From for TaskSummary { fn from(value: ProcessProgOrphan) -> Self { Self { - total: (value.state == Some(false)) as u32, + total: value.failed() as u32, success: 0, - failed: (value.state == Some(false)) as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } @@ -74,8 +74,8 @@ impl From for TaskSummary { fn from(value: ProcessProgBg) -> Self { Self { total: 1, - success: (value.state == Some(true)) as u32, - failed: (value.state == Some(false)) as u32, + success: value.success() as u32, + failed: value.failed() as u32, percent: value.percent().map(Into::into), } } diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index aa0fd4b6..be0800f0 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -3,10 +3,11 @@ use std::{ops::Deref, sync::Arc, time::Duration}; use hashbrown::HashMap; use tokio::task::JoinHandle; use yazi_config::{YAZI, plugin::{Fetcher, Preloader}}; +use yazi_fs::FsHash64; use yazi_runner::entry::EntryJob; use yazi_shared::{CompletionToken, Id, SStr, Throttle, data::{Data, DataKey}, url::{UrlBuf, UrlLike}}; -use crate::{Behavior, HIGH, LOW, NORMAL, Task, TaskProg, Worker, fetch::{FetchIn, FetchProg}, file::{FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload, FileOutCopy, FileOutCut, FileOutDownload, FileOutHardlink, FileOutUpload, FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInTrash, HookInUpload}, plugin::{PluginInEntry, PluginProgEntry}, preload::{PreloadIn, PreloadProg}, process::{ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessOpt, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}, size::{SizeIn, SizeProg}}; +use crate::{Behavior, HIGH, LOW, NORMAL, Task, TaskProg, Worker, fetch::{FetchIn, FetchProg}, file::{FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload, FileOutCopy, FileOutCut, FileOutDownload, FileOutHardlink, FileOutUpload, FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInPreload, HookInTrash, HookInUpload}, plugin::{PluginInEntry, PluginProgEntry}, preload::{PreloadIn, PreloadProg}, process::{ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessOpt, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}, size::{SizeIn, SizeProg}}; pub struct Scheduler { pub worker: Worker, @@ -202,9 +203,14 @@ impl Scheduler { pub fn preload_paged(&self, preloader: &'static Preloader, target: &yazi_fs::File) { let name = format!("Run preloader `{}`", preloader.run.name); - let (id, done) = self.add::(name, |t| (t.id, t.done.clone())); + let hook = HookInPreload::new(preloader.idx, target.hash_u64()); - self.preload.submit(PreloadIn { id, plugin: preloader, target: target.clone(), done }); + let id = self.add_hooked::(name, hook, |t| t.id); + if let Some(prev) = self.preload.loading.lock().put(target.url.hash_u64(), id) { + self.cancel(prev); + } + + self.preload.submit(PreloadIn { id, plugin: preloader, target: target.clone() }); } pub fn prework_size(&self, targets: Vec<&UrlBuf>) { diff --git a/yazi-scheduler/src/worker.rs b/yazi-scheduler/src/worker.rs index ca3f0a9a..b0679164 100644 --- a/yazi-scheduler/src/worker.rs +++ b/yazi-scheduler/src/worker.rs @@ -30,20 +30,18 @@ impl Worker { let (process_tx, process_rx) = async_priority_channel::unbounded(); let (hook_tx, hook_rx) = async_priority_channel::unbounded(); let (op_tx, op_rx) = mpsc::unbounded_channel(); + let ongoing = Arc::new(Mutex::new(Ongoing::default())); + let file = Arc::new(File::new(&op_tx, file_tx)); + let plugin = Arc::new(Plugin::new(&op_tx, plugin_tx)); + let fetch = Arc::new(Fetch::new(&op_tx, fetch_tx)); + let preload = Arc::new(Preload::new(&op_tx, preload_tx)); + let size = Arc::new(Size::new(&op_tx, size_tx)); + let process = Arc::new(Process::new(&op_tx, process_tx)); + let hook = Arc::new(Hook::new(&op_tx, &ongoing, &preload, hook_tx)); - let me = Self { - file: Arc::new(File::new(&op_tx, file_tx)), - plugin: Arc::new(Plugin::new(&op_tx, plugin_tx)), - fetch: Arc::new(Fetch::new(&op_tx, fetch_tx)), - preload: Arc::new(Preload::new(&op_tx, preload_tx)), - size: Arc::new(Size::new(&op_tx, size_tx)), - process: Arc::new(Process::new(&op_tx, process_tx)), - hook: Arc::new(Hook::new(&op_tx, &ongoing, hook_tx)), - - ops: TaskOps(op_tx), - ongoing, - }; + let me = + Self { file, plugin, fetch, preload, size, process, hook, ops: TaskOps(op_tx), ongoing }; let handles = [] .into_iter() @@ -270,6 +268,7 @@ impl Worker { HookIn::Hardlink(r#in) => self.hook.hardlink(r#in).await, HookIn::Download(r#in) => self.hook.download(r#in).await, HookIn::Upload(r#in) => self.hook.upload(r#in).await, + HookIn::Preload(r#in) => self.hook.preload(r#in).await, } }