feat: support task initialization failure status (#3227)

This commit is contained in:
三咲雅 misaki masa 2025-10-03 22:35:48 +08:00 committed by GitHub
parent 149a5feffb
commit cd6881c9fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 110 additions and 49 deletions

View file

@ -32,6 +32,7 @@ impl UserData for TaskSnap {
fields.add_field_method_get("running", |_, me| Ok(me.prog.running()));
fields.add_field_method_get("success", |_, me| Ok(me.prog.success()));
fields.add_field_method_get("failed", |_, me| Ok(me.prog.failed()));
fields.add_field_method_get("percent", |_, me| Ok(me.prog.percent()));
}
}

View file

@ -27,7 +27,7 @@ impl File {
pub(crate) async fn paste(&self, mut task: FileInPaste) -> Result<(), FileOutPaste> {
if task.cut && ok_or_not_found(provider::rename(&task.from, &task.to).await).is_ok() {
return Ok(self.ops.out(task.id, FileOutPaste::Init));
return Ok(self.ops.out(task.id, FileOutPaste::Succ));
}
if task.cha.is_none() {
@ -44,7 +44,7 @@ impl File {
self.ops.out(id, FileOutPaste::New(cha.len));
self.queue(task, LOW);
}
return Ok(self.ops.out(id, FileOutPaste::Init));
return Ok(self.ops.out(id, FileOutPaste::Succ));
}
macro_rules! continue_unless_ok {
@ -91,7 +91,7 @@ impl File {
}
}
Ok(self.ops.out(task.id, FileOutPaste::Init))
Ok(self.ops.out(task.id, FileOutPaste::Succ))
}
pub(crate) async fn paste_do(&self, mut task: FileInPaste) -> Result<(), FileOutPasteDo> {
@ -175,7 +175,7 @@ impl File {
let id = task.id;
self.ops.out(id, FileOutHardlink::New);
self.queue(task, NORMAL);
self.ops.out(id, FileOutHardlink::Init);
self.ops.out(id, FileOutHardlink::Succ);
return Ok(());
}
@ -218,7 +218,7 @@ impl File {
}
}
Ok(self.ops.out(task.id, FileOutHardlink::Init))
Ok(self.ops.out(task.id, FileOutHardlink::Succ))
}
pub(crate) async fn hardlink_do(&self, task: FileInHardlink) -> Result<(), FileOutHardlinkDo> {
@ -243,7 +243,7 @@ impl File {
task.length = cha.len;
self.ops.out(id, FileOutDelete::New(cha.len));
self.queue(task, NORMAL);
self.ops.out(id, FileOutDelete::Init);
self.ops.out(id, FileOutDelete::Succ);
return Ok(());
}
@ -266,7 +266,7 @@ impl File {
}
}
Ok(self.ops.out(task.id, FileOutDelete::Init))
Ok(self.ops.out(task.id, FileOutDelete::Succ))
}
pub(crate) async fn delete_do(&self, task: FileInDelete) -> Result<(), FileOutDeleteDo> {

View file

@ -5,12 +5,13 @@ use crate::{Task, TaskProg};
pub(crate) enum FileOutPaste {
New(u64),
Deform(String),
Init,
Succ,
Fail(String),
Clean,
}
impl From<std::io::Error> for FileOutPaste {
fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) }
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
}
impl FileOutPaste {
@ -26,8 +27,12 @@ impl FileOutPaste {
prog.failed_files += 1;
task.log(reason);
}
Self::Init => {
prog.collected = true;
Self::Succ => {
prog.collected = Some(true);
}
Self::Fail(reason) => {
prog.collected = Some(false);
task.log(reason);
}
Self::Clean => {
prog.cleaned = true;
@ -116,11 +121,12 @@ impl FileOutLink {
pub(crate) enum FileOutHardlink {
New,
Deform(String),
Init,
Succ,
Fail(String),
}
impl From<std::io::Error> for FileOutHardlink {
fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) }
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
}
impl FileOutHardlink {
@ -135,8 +141,12 @@ impl FileOutHardlink {
prog.failed += 1;
task.log(reason);
}
Self::Init => {
prog.collected = true;
Self::Succ => {
prog.collected = Some(true);
}
Self::Fail(reason) => {
prog.collected = Some(false);
task.log(reason);
}
}
}
@ -172,13 +182,13 @@ impl FileOutHardlinkDo {
#[derive(Debug)]
pub(crate) enum FileOutDelete {
New(u64),
Deform(String),
Init,
Succ,
Fail(String),
Clean,
}
impl From<std::io::Error> for FileOutDelete {
fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) }
fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) }
}
impl FileOutDelete {
@ -189,13 +199,12 @@ impl FileOutDelete {
prog.total_files += 1;
prog.total_bytes += size;
}
Self::Deform(reason) => {
prog.total_files += 1;
prog.failed_files += 1;
task.log(reason);
Self::Succ => {
prog.collected = Some(true);
}
Self::Init => {
prog.collected = true;
Self::Fail(reason) => {
prog.collected = Some(false);
task.log(reason);
}
Self::Clean => {
prog.cleaned = true;

View file

@ -9,7 +9,7 @@ pub struct FileProgPaste {
pub failed_files: u32,
pub total_bytes: u64,
pub processed_bytes: u64,
pub collected: bool,
pub collected: Option<bool>,
pub cleaned: bool,
}
@ -26,20 +26,26 @@ impl From<FileProgPaste> for TaskSummary {
impl FileProgPaste {
pub fn running(self) -> bool {
!self.collected || self.success_files + self.failed_files != self.total_files
self.collected.is_none() || self.success_files + self.failed_files != self.total_files
}
pub fn success(self) -> bool { self.collected && self.success_files == self.total_files }
pub fn success(self) -> bool {
self.collected == Some(true) && self.success_files == self.total_files
}
pub fn failed(self) -> bool { self.collected == Some(false) }
pub fn cleaned(self) -> bool { self.cleaned }
pub fn percent(self) -> Option<f32> {
Some(if self.success() {
100.0
} else if self.total_bytes == 0 {
99.99
} else {
} else if self.failed() {
0.0
} else if self.total_bytes != 0 {
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
} else {
99.99
})
}
}
@ -66,6 +72,8 @@ impl FileProgLink {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { false }
pub fn percent(self) -> Option<f32> { None }
@ -77,7 +85,7 @@ pub struct FileProgHardlink {
pub total: u32,
pub success: u32,
pub failed: u32,
pub collected: bool,
pub collected: Option<bool>,
}
impl From<FileProgHardlink> for TaskSummary {
@ -92,9 +100,13 @@ impl From<FileProgHardlink> for TaskSummary {
}
impl FileProgHardlink {
pub fn running(self) -> bool { !self.collected || self.success + self.failed != self.total }
pub fn running(self) -> bool {
self.collected.is_none() || self.success + self.failed != self.total
}
pub fn success(self) -> bool { self.collected && self.success == self.total }
pub fn success(self) -> bool { self.collected == Some(true) && self.success == self.total }
pub fn failed(self) -> bool { self.collected == Some(false) }
pub fn cleaned(self) -> bool { false }
@ -109,7 +121,7 @@ pub struct FileProgDelete {
pub failed_files: u32,
pub total_bytes: u64,
pub processed_bytes: u64,
pub collected: bool,
pub collected: Option<bool>,
pub cleaned: bool,
}
@ -126,20 +138,26 @@ impl From<FileProgDelete> for TaskSummary {
impl FileProgDelete {
pub fn running(self) -> bool {
!self.collected || self.success_files + self.failed_files != self.total_files
self.collected.is_none() || self.success_files + self.failed_files != self.total_files
}
pub fn success(self) -> bool { self.collected && self.success_files == self.total_files }
pub fn success(self) -> bool {
self.collected == Some(true) && self.success_files == self.total_files
}
pub fn failed(self) -> bool { self.collected == Some(false) }
pub fn cleaned(self) -> bool { self.cleaned }
pub fn percent(self) -> Option<f32> {
Some(if self.success() {
100.0
} else if self.total_bytes == 0 {
99.99
} else {
} else if self.failed() {
0.0
} else if self.total_bytes != 0 {
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
} else {
99.99
})
}
}
@ -166,6 +184,8 @@ impl FileProgTrash {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { false }
pub fn percent(self) -> Option<f32> { None }

View file

@ -59,7 +59,7 @@ impl Ongoing {
for task in self.values() {
let s: TaskSummary = task.prog.into();
if s.total == 0 {
if s.total == 0 && !task.prog.failed() {
continue;
}

View file

@ -23,6 +23,8 @@ impl PluginProgEntry {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { false }
pub fn percent(self) -> Option<f32> { None }

View file

@ -23,6 +23,8 @@ impl PreworkProgFetch {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { false }
pub fn percent(self) -> Option<f32> { None }
@ -50,6 +52,8 @@ impl PreworkProgLoad {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { false }
pub fn percent(self) -> Option<f32> { None }
@ -77,6 +81,8 @@ impl PreworkProgSize {
pub fn success(self) -> bool { self.done }
pub fn failed(self) -> bool { false }
pub fn cleaned(self) -> bool { false }
pub fn percent(self) -> Option<f32> { None }

View file

@ -24,6 +24,8 @@ impl ProcessProgBlock {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { self.cleaned }
pub fn percent(self) -> Option<f32> { None }
@ -52,6 +54,8 @@ impl ProcessProgOrphan {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { self.cleaned }
pub fn percent(self) -> Option<f32> { None }
@ -80,6 +84,8 @@ impl ProcessProgBg {
pub fn success(self) -> bool { self.state == Some(true) }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn cleaned(self) -> bool { self.cleaned }
pub fn percent(self) -> Option<f32> { None }

View file

@ -101,6 +101,27 @@ impl TaskProg {
}
}
pub fn failed(self) -> bool {
match self {
// File
Self::FilePaste(p) => p.failed(),
Self::FileLink(p) => p.failed(),
Self::FileHardlink(p) => p.failed(),
Self::FileDelete(p) => p.failed(),
Self::FileTrash(p) => p.failed(),
// Plugin
Self::PluginEntry(p) => p.failed(),
// Prework
Self::PreworkFetch(p) => p.failed(),
Self::PreworkLoad(p) => p.failed(),
Self::PreworkSize(p) => p.failed(),
// Process
Self::ProcessBlock(p) => p.failed(),
Self::ProcessOrphan(p) => p.failed(),
Self::ProcessBg(p) => p.failed(),
}
}
pub fn cleaned(self) -> bool {
match self {
// File

View file

@ -81,7 +81,7 @@ impl Scheduler {
let id = ongoing.add::<FileProgPaste>(format!("Cut {} to {}", from.display(), to.display()));
if to.starts_with(&from) && !to.covariant(&from) {
return self.ops.out(id, FileOutPaste::Deform("Cannot cut directory into itself".to_owned()));
return self.ops.out(id, FileOutPaste::Fail("Cannot cut directory into itself".to_owned()));
}
ongoing.hooks.add_async(id, {
@ -114,9 +114,7 @@ impl Scheduler {
));
if to.starts_with(&from) && !to.covariant(&from) {
return self
.ops
.out(id, FileOutPaste::Deform("Cannot copy directory into itself".to_owned()));
return self.ops.out(id, FileOutPaste::Fail("Cannot copy directory into itself".to_owned()));
}
let file = self.file.clone();
@ -154,7 +152,7 @@ impl Scheduler {
if to.starts_with(&from) && !to.covariant(&from) {
return self
.ops
.out(id, FileOutHardlink::Deform("Cannot hardlink directory into itself".to_owned()));
.out(id, FileOutHardlink::Fail("Cannot hardlink directory into itself".to_owned()));
}
let file = self.file.clone();
@ -212,16 +210,14 @@ impl Scheduler {
pub fn file_download(&self, from: UrlBuf, done: Option<oneshot::Sender<bool>>) {
let mut ongoing = self.ongoing.lock();
let id = self.ongoing.lock().add::<FileProgPaste>(format!("Download {}", from.display()));
let id = ongoing.add::<FileProgPaste>(format!("Download {}", from.display()));
if let Some(tx) = done {
ongoing.hooks.add_sync(id, move |canceled| _ = tx.send(canceled));
}
let Some(to) = from.cache().map(UrlBuf::from) else {
return self
.ops
.out(id, FileOutPaste::Deform("Unable to download non-remote file".to_owned()));
return self.ops.out(id, FileOutPaste::Fail("Cannot download non-remote file".to_owned()));
};
let file = self.file.clone();