diff --git a/libs/hbb_common/src/fs.rs b/libs/hbb_common/src/fs.rs index dd8a7530e..8477c82ff 100644 --- a/libs/hbb_common/src/fs.rs +++ b/libs/hbb_common/src/fs.rs @@ -215,6 +215,8 @@ pub struct TransferJob { transferred: u64, enable_overwrite_detection: bool, file_confirmed: bool, + // indicating the last file is skipped + file_skipped: bool, file_is_waiting: bool, default_overwrite_strategy: Option, } @@ -541,25 +543,50 @@ impl TransferJob { pub fn set_file_confirmed(&mut self, file_confirmed: bool) { log::info!("id: {}, file_confirmed: {}", self.id, file_confirmed); self.file_confirmed = file_confirmed; + self.file_skipped = false; } pub fn set_file_is_waiting(&mut self, file_is_waiting: bool) { self.file_is_waiting = file_is_waiting; } + #[inline] pub fn file_is_waiting(&self) -> bool { self.file_is_waiting } + #[inline] pub fn file_confirmed(&self) -> bool { self.file_confirmed } - pub fn skip_current_file(&mut self) -> bool { + /// Indicating whether the last file is skipped + #[inline] + pub fn file_skipped(&self) -> bool { + self.file_skipped + } + + /// Indicating whether the whole task is skipped + #[inline] + pub fn job_skipped(&self) -> bool { + self.file_skipped() && self.files.len() == 1 + } + + /// Get job error message, useful for getting status when job had finished + pub fn job_error(&self) -> Option { + if self.job_skipped() { + return Some("skipped".to_string()); + } + None + } + + pub fn set_file_skipped(&mut self) -> bool { + log::debug!("skip file {} in job {}", self.file_num, self.id); self.file.take(); self.set_file_confirmed(false); self.set_file_is_waiting(false); self.file_num += 1; + self.file_skipped = true; true } @@ -571,7 +598,7 @@ impl TransferJob { Some(file_transfer_send_confirm_request::Union::Skip(s)) => { if s { log::debug!("skip file id:{}, file_num:{}", r.id, r.file_num); - self.skip_current_file(); + self.set_file_skipped(); } else { self.set_file_confirmed(true); } @@ -719,7 +746,10 @@ pub async fn handle_read_jobs( Ok(None) => { if !job.enable_overwrite_detection || (!job.file_confirmed && !job.file_is_waiting) { - finished.push(job.id()); + // for getting error detail, we do not remove this job, we will handle it in io loop + if job.job_error().is_none() { + finished.push(job.id()); + } stream.send(&new_done(job.id(), job.file_num())).await?; } else { // waiting confirmation. diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 16f91d89d..d7468ea9a 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -499,7 +499,7 @@ impl Remote { } let mut msg = Message::new(); let mut file_action = FileAction::new(); - file_action.set_send_confirm(FileTransferSendConfirmRequest { + let req = FileTransferSendConfirmRequest { id, file_num, union: if need_override { @@ -508,7 +508,9 @@ impl Remote { Some(file_transfer_send_confirm_request::Union::Skip(true)) }, ..Default::default() - }); + }; + job.confirm(&req); + file_action.set_send_confirm(req); msg.set_file_action(file_action); allow_err!(peer.send(&msg).await); } @@ -862,28 +864,30 @@ impl Remote { match fs::is_write_need_confirmation(&write_path, &digest) { Ok(res) => match res { DigestCheckResult::IsSame => { - let msg= new_send_confirm(FileTransferSendConfirmRequest { + let req = FileTransferSendConfirmRequest { id: digest.id, file_num: digest.file_num, union: Some(file_transfer_send_confirm_request::Union::Skip(true)), ..Default::default() - }); + }; + job.confirm(&req); + let msg = new_send_confirm(req); allow_err!(peer.send(&msg).await); } DigestCheckResult::NeedConfirm(digest) => { if let Some(overwrite) = overwrite_strategy { - let msg = new_send_confirm( - FileTransferSendConfirmRequest { - id: digest.id, - file_num: digest.file_num, - union: Some(if overwrite { - file_transfer_send_confirm_request::Union::OffsetBlk(0) - } else { - file_transfer_send_confirm_request::Union::Skip(true) - }), - ..Default::default() - }, - ); + let req = FileTransferSendConfirmRequest { + id: digest.id, + file_num: digest.file_num, + union: Some(if overwrite { + file_transfer_send_confirm_request::Union::OffsetBlk(0) + } else { + file_transfer_send_confirm_request::Union::Skip(true) + }), + ..Default::default() + }; + job.confirm(&req); + let msg = new_send_confirm(req); allow_err!(peer.send(&msg).await); } else { self.handler.override_file_confirm( @@ -895,14 +899,14 @@ impl Remote { } } DigestCheckResult::NoSuchFile => { - let msg = new_send_confirm( - FileTransferSendConfirmRequest { + let req = FileTransferSendConfirmRequest { id: digest.id, file_num: digest.file_num, union: Some(file_transfer_send_confirm_request::Union::OffsetBlk(0)), ..Default::default() - }, - ); + }; + job.confirm(&req); + let msg = new_send_confirm(req); allow_err!(peer.send(&msg).await); } }, @@ -915,6 +919,7 @@ impl Remote { } } Some(file_response::Union::Block(block)) => { + log::debug!("recv block: {}", block.blk_id); if let Some(job) = fs::get_job(block.id, &mut self.write_jobs) { if let Err(_err) = job.write(block).await { // to-do: add "skip" for writing job @@ -923,11 +928,18 @@ impl Remote { } } Some(file_response::Union::Done(d)) => { + let mut err: Option = None; if let Some(job) = fs::get_job(d.id, &mut self.write_jobs) { job.modify_time(); + err = job.job_error(); fs::remove_job(d.id, &mut self.write_jobs); } - self.handle_job_status(d.id, d.file_num, None); + if let Some(job) = fs::get_job(d.id, &mut self.read_jobs) { + job.modify_time(); + err = job.job_error(); + fs::remove_job(d.id, &mut self.read_jobs); + } + self.handle_job_status(d.id, d.file_num, err); } Some(file_response::Union::Error(e)) => { self.handle_job_status(e.id, e.file_num, Some(e.error)); @@ -976,7 +988,8 @@ impl Remote { self.handler.ui_handler.switch_display(&s); self.video_sender.send(MediaData::Reset).ok(); if s.width > 0 && s.height > 0 { - self.handler.set_display(s.x, s.y, s.width, s.height, s.cursor_embeded); + self.handler + .set_display(s.x, s.y, s.width, s.height, s.cursor_embeded); } } Some(misc::Union::CloseReason(c)) => { diff --git a/src/flutter.rs b/src/flutter.rs index a2c307f5a..6924bada3 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -210,10 +210,10 @@ impl InvokeUiSession for FlutterHandler { ); } - fn job_done(&self, id: i32, file_num: i32) { + fn job_done(&self, id: i32, file_num: i32, skipped: bool) { self.push_event( "job_done", - vec![("id", &id.to_string()), ("file_num", &file_num.to_string())], + vec![("id", &id.to_string()), ("file_num", &file_num.to_string()), ("skipped", skipped)], ); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 1b49f6c4a..c429d9539 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "在只允许密码连接并且只用固定密码的情况下才允许隐藏"), ("wayland_experiment_tip", ""), ("Right click to select tabs", "右键选择选项卡"), + ("Skipped", "已跳过"), ].iter().cloned().collect(); } diff --git a/src/ui/file_transfer.tis b/src/ui/file_transfer.tis index 451117403..f69f6d323 100644 --- a/src/ui/file_transfer.tis +++ b/src/ui/file_transfer.tis @@ -245,7 +245,13 @@ class JobTable: Reactor.Component { var percent = job.total_size == 0 ? 100 : (100. * job.finished_size / job.total_size).toInteger(); // (100. * i / (n || 1)).toInteger(); if (job.finished) percent = '100'; if (percent) res += ", " + percent + "%"; - if (job.finished) res = translate("Finished") + " " + res; + if (job.finished) { + if (job.err == "skipped") { + res = translate("Skipped") + " " + res; + } else { + res = translate("Finished") + " " + res; + } + } if (job.speed) res += ", " + getSize(0, job.speed) + "/s"; return res; } @@ -268,9 +274,10 @@ class JobTable: Reactor.Component { if (file_num < job.file_num) return; job.file_num = file_num; var n = job.num_entries || job.entries.length; - job.finished = job.file_num >= n - 1 || err == "cancel"; + job.finished = job.file_num >= n - 1 || err == "cancel" || err == "skipped"; job.finished_size = finished_size; job.speed = speed || 0; + job.err = err; this.updateJob(job); if (job.type == "del-dir") { if (job.finished) {