fix(peer): forward UploadFailed to the download store

The code 46 handler parsed the filename and only logged it, so a queued
download whose peer reported an upload failure never received
DownloadStatus::Failed and hung until the caller's own timeout.

The handler now sends PeerMessage::UploadFailed through the dispatcher
and the actor stamps the peer's username on it before forwarding
ClientOperation::UploadFailed into the existing failure path. The
variant's username field stays for API compatibility; the wire message
cannot name anyone but the connected peer, so the actor supplies it.

Fixes #30
This commit is contained in:
Michel de Graaf
2026-08-13 12:39:42 +02:00
parent 77f36b1e98
commit d30ca757bc
3 changed files with 145 additions and 4 deletions
+22 -3
View File
@@ -282,8 +282,8 @@ impl PeerActor {
PeerMessage::ProcessRead => {
self.process_read();
}
PeerMessage::UploadFailed(username, filename) => {
self.handle_upload_failed(username, filename);
PeerMessage::UploadFailed(_, filename) => {
self.handle_upload_failed(filename);
}
}
}
@@ -452,7 +452,8 @@ impl PeerActor {
}
}
fn handle_upload_failed(&self, username: String, filename: String) {
fn handle_upload_failed(&self, filename: String) {
let username = self.peer_username();
if let Err(e) = self
.client_channel
.send(ClientOperation::UploadFailed(username, filename))
@@ -973,6 +974,24 @@ mod tests {
}
}
#[test]
fn an_upload_failed_message_reaches_the_client_as_this_peer() {
let (mut actor, rx, _far_end) = connected_actor();
actor.handle_message(PeerMessage::UploadFailed(
String::new(),
"song.mp3".to_string(),
));
match rx.try_recv() {
Ok(ClientOperation::UploadFailed(username, filename)) => {
assert_eq!(username, "bob");
assert_eq!(filename, "song.mp3");
}
other => panic!("expected UploadFailed, got {other:?}"),
}
}
#[test]
fn tick_reaps_a_peer_idle_past_the_deadline() {
let (mut actor, rx, _far_end) = connected_actor();
@@ -10,8 +10,31 @@ impl MessageHandler<PeerMessage> for UploadFailedHandler {
fn get_code(&self) -> u8 {
46
}
fn handle(&self, message: &mut Message, _sender: Sender<PeerMessage>) {
fn handle(&self, message: &mut Message, sender: Sender<PeerMessage>) {
let filename = message.read_string();
info!("Upload failed for {}", filename);
let _ = sender.send(PeerMessage::UploadFailed(String::new(), filename));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::message::framed;
#[test]
fn the_failed_filename_is_forwarded() {
let (tx, rx) = std::sync::mpsc::channel();
let mut message = framed(|m| {
m.write_string("@@share\\gone.mp3");
});
UploadFailedHandler.handle(&mut message, tx);
match rx.try_recv() {
Ok(PeerMessage::UploadFailed(_, filename)) => {
assert_eq!(filename, "@@share\\gone.mp3");
}
other => panic!("unexpected: {other:?}"),
}
}
}