feat(tui): surface the failure reason on failed downloads
Carry a human-readable reason on DownloadStatus::Failed so it flows through the existing status channel to the TUI. The download Info pane now shows an Error line for a failed download (connect failure, peer disconnect, truncated transfer, peer-reported upload failure, or the underlying transfer error). Failures without a known reason render as before.
This commit is contained in:
@@ -374,7 +374,7 @@ fn download_without_a_connection_resolves_failed() {
|
||||
.expect("download() should return a handle");
|
||||
assert!(matches!(
|
||||
receiver.recv_timeout(Duration::from_secs(1)),
|
||||
Ok(DownloadStatus::Failed)
|
||||
Ok(DownloadStatus::Failed(_))
|
||||
));
|
||||
}
|
||||
|
||||
@@ -398,7 +398,7 @@ fn fail_queued_downloads_notifies_receiver_and_store() {
|
||||
|
||||
Client::fail_queued_downloads(&client.context, "peer");
|
||||
|
||||
assert!(matches!(receiver.try_recv(), Ok(DownloadStatus::Failed)));
|
||||
assert!(matches!(receiver.try_recv(), Ok(DownloadStatus::Failed(_))));
|
||||
assert!(matches!(
|
||||
client
|
||||
.context
|
||||
@@ -407,7 +407,7 @@ fn fail_queued_downloads_notifies_receiver_and_store() {
|
||||
.get_download_by_token(7)
|
||||
.unwrap()
|
||||
.status,
|
||||
DownloadStatus::Failed
|
||||
DownloadStatus::Failed(_)
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1056,10 +1056,18 @@ impl Client {
|
||||
};
|
||||
|
||||
if failed {
|
||||
let _ = download.sender.send(DownloadStatus::Failed);
|
||||
self.context
|
||||
.write_safe()?
|
||||
.update_download_with_status(token, DownloadStatus::Failed);
|
||||
let reason = if peer_registered {
|
||||
"Peer rejected the download request"
|
||||
} else {
|
||||
"Could not connect to the peer"
|
||||
};
|
||||
let _ = download
|
||||
.sender
|
||||
.send(DownloadStatus::Failed(Some(reason.to_string())));
|
||||
self.context.write_safe()?.update_download_with_status(
|
||||
token,
|
||||
DownloadStatus::Failed(Some(reason.to_string())),
|
||||
);
|
||||
}
|
||||
|
||||
Ok((download, download_receiver))
|
||||
@@ -1088,8 +1096,12 @@ impl Client {
|
||||
.map(|d| (d.token, d.sender.clone()))
|
||||
.collect();
|
||||
for (token, sender) in doomed {
|
||||
let _ = sender.send(DownloadStatus::Failed);
|
||||
context.update_download_with_status(token, DownloadStatus::Failed);
|
||||
let reason = Some("Peer disconnected".to_string());
|
||||
let _ = sender.send(DownloadStatus::Failed(reason.clone()));
|
||||
context.update_download_with_status(
|
||||
token,
|
||||
DownloadStatus::Failed(reason),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1142,9 +1154,12 @@ impl Client {
|
||||
match client_context.write_safe() {
|
||||
Ok(mut context) => {
|
||||
for token in failed_tokens {
|
||||
context
|
||||
.downloads
|
||||
.update_status(token, DownloadStatus::Failed);
|
||||
context.downloads.update_status(
|
||||
token,
|
||||
DownloadStatus::Failed(Some(
|
||||
"Peer reported the upload failed".to_string(),
|
||||
)),
|
||||
);
|
||||
context.downloads.remove(token);
|
||||
}
|
||||
}
|
||||
@@ -1326,9 +1341,12 @@ impl Client {
|
||||
);
|
||||
}
|
||||
Err(e) => {
|
||||
let _ = download.sender.send(DownloadStatus::Failed);
|
||||
let reason = Some(
|
||||
e.to_string(),
|
||||
);
|
||||
let _ = download.sender.send(DownloadStatus::Failed(reason.clone()));
|
||||
match client_context_clone.write_safe() {
|
||||
Ok(mut ctx) => ctx.update_download_with_status(download.token, DownloadStatus::Failed),
|
||||
Ok(mut ctx) => ctx.update_download_with_status(download.token, DownloadStatus::Failed(reason)),
|
||||
Err(e) => error!("[client] download failed write: {}", e),
|
||||
}
|
||||
error!(
|
||||
|
||||
@@ -149,7 +149,9 @@ pub fn collect_failed_tokens(
|
||||
d.username == username && filename.is_none_or(|f| d.filename == *f)
|
||||
})
|
||||
.map(|d| {
|
||||
let _ = d.sender.send(DownloadStatus::Failed);
|
||||
let _ = d.sender.send(DownloadStatus::Failed(Some(
|
||||
"Peer reported the upload failed".to_string(),
|
||||
)));
|
||||
d.token
|
||||
})
|
||||
.collect()
|
||||
@@ -301,7 +303,7 @@ mod tests {
|
||||
assert_eq!(tokens, vec![1]);
|
||||
assert!(matches!(
|
||||
rx_match.try_recv().unwrap(),
|
||||
DownloadStatus::Failed
|
||||
DownloadStatus::Failed(_)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ fn handle_file_connection(
|
||||
match context.client_context.write_safe() {
|
||||
Ok(mut ctx) => ctx.update_download_with_status(
|
||||
failure_token,
|
||||
DownloadStatus::Failed,
|
||||
DownloadStatus::Failed(Some(e.to_string())),
|
||||
),
|
||||
Err(e) => {
|
||||
error!(
|
||||
|
||||
@@ -114,7 +114,7 @@ impl Download {
|
||||
matches!(
|
||||
self.status,
|
||||
DownloadStatus::Completed
|
||||
| DownloadStatus::Failed
|
||||
| DownloadStatus::Failed(_)
|
||||
| DownloadStatus::TimedOut
|
||||
)
|
||||
}
|
||||
@@ -159,7 +159,8 @@ pub enum DownloadStatus {
|
||||
total_bytes: u64,
|
||||
},
|
||||
Completed,
|
||||
Failed,
|
||||
/// Failed, optionally with a human-readable reason.
|
||||
Failed(Option<String>),
|
||||
TimedOut,
|
||||
}
|
||||
impl Transfer {
|
||||
|
||||
@@ -614,7 +614,7 @@ fn a_file_downloads_from_a_peer_over_p_and_f_connections() {
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
Ok(DownloadStatus::Failed | DownloadStatus::TimedOut) => {
|
||||
Ok(DownloadStatus::Failed(_) | DownloadStatus::TimedOut) => {
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
@@ -862,7 +862,7 @@ fn a_file_downloads_from_a_peer_via_direct_connection() {
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
Ok(DownloadStatus::Failed | DownloadStatus::TimedOut) => break,
|
||||
Ok(DownloadStatus::Failed(_) | DownloadStatus::TimedOut) => break,
|
||||
_ => {}
|
||||
}
|
||||
if client
|
||||
@@ -1021,7 +1021,7 @@ fn a_file_downloads_from_a_firewalled_peer_via_server_broker() {
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
Ok(DownloadStatus::Failed | DownloadStatus::TimedOut) => break,
|
||||
Ok(DownloadStatus::Failed(_) | DownloadStatus::TimedOut) => break,
|
||||
_ => {}
|
||||
}
|
||||
if client
|
||||
@@ -1122,7 +1122,7 @@ fn two_real_clients_search_and_download() {
|
||||
completed = true;
|
||||
break;
|
||||
}
|
||||
Ok(DownloadStatus::Failed | DownloadStatus::TimedOut) => break,
|
||||
Ok(DownloadStatus::Failed(_) | DownloadStatus::TimedOut) => break,
|
||||
_ => {}
|
||||
}
|
||||
if leecher
|
||||
|
||||
Reference in New Issue
Block a user