feat(download): resume interrupted transfers
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
use super::{
|
||||
Arc, Client, ClientContext, ClientOperation, ConnectionType, DownloadPeer,
|
||||
DownloadStatus, Listen, Peer, PeerRegistry, Receiver, Result, RwLock,
|
||||
RwLockExt, Sender, ServerActor, ServerMessage, Shares, SoulseekRs,
|
||||
TcpStream, error, info, mpsc, thread, trace, warn,
|
||||
Listen, Peer, PeerRegistry, Receiver, Result, RwLock, RwLockExt, Sender,
|
||||
ServerActor, ServerMessage, Shares, SoulseekRs, TcpStream, error, info,
|
||||
mpsc, thread, trace, warn,
|
||||
};
|
||||
|
||||
/// Ceiling on the wait for a login verdict. Generous enough for a slow server
|
||||
@@ -282,27 +282,12 @@ impl Client {
|
||||
own_username,
|
||||
);
|
||||
|
||||
match download_peer.download_file(
|
||||
client_context.clone(),
|
||||
None,
|
||||
None,
|
||||
) {
|
||||
match download_peer.download_file(client_context, None, None) {
|
||||
Ok((download, filename)) => {
|
||||
trace!(
|
||||
"[client] downloaded {} bytes {:?} ",
|
||||
filename, download.size
|
||||
);
|
||||
let _ = download.sender.send(DownloadStatus::Completed);
|
||||
match client_context.write_safe() {
|
||||
Ok(mut ctx) => ctx.update_download_with_status(
|
||||
download.token,
|
||||
DownloadStatus::Completed,
|
||||
),
|
||||
Err(e) => error!(
|
||||
"[client] connect_to_peer F write: {}",
|
||||
e
|
||||
),
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
trace!("[client] failed to download: {}", e);
|
||||
|
||||
@@ -135,52 +135,33 @@ impl Client {
|
||||
}
|
||||
}
|
||||
ClientOperation::DownloadFromPeer(token, peer, allowed) => {
|
||||
let maybe_download = match client_context.read_safe() {
|
||||
Ok(ctx) => {
|
||||
ctx.get_download_by_token(token).cloned()
|
||||
}
|
||||
let maybe_download = match client_context.write_safe() {
|
||||
Ok(mut ctx) => ctx
|
||||
.downloads
|
||||
.claim_for_peer(token, &peer.username),
|
||||
Err(e) => {
|
||||
error!("[client] DownloadFromPeer read: {}", e);
|
||||
error!(
|
||||
"[client] DownloadFromPeer write: {}",
|
||||
e
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let own_username = own_username.clone();
|
||||
let client_context_clone = client_context.clone();
|
||||
|
||||
trace!(
|
||||
"[client] DownloadFromPeer token: {} peer: {:?}",
|
||||
token, peer
|
||||
);
|
||||
let Some(download) = maybe_download else {
|
||||
error!(
|
||||
"Can't find download with token {:?}",
|
||||
token
|
||||
debug!(
|
||||
"[client] transfer token {} is missing, belongs \
|
||||
to another peer, or is already claimed; ignoring",
|
||||
token,
|
||||
);
|
||||
continue;
|
||||
};
|
||||
if matches!(
|
||||
download.status,
|
||||
DownloadStatus::InProgress { .. }
|
||||
| DownloadStatus::Completed
|
||||
| DownloadStatus::Cancelled
|
||||
) {
|
||||
debug!(
|
||||
"[client] transfer token {} already claimed; \
|
||||
ignoring replayed TransferResponse",
|
||||
token
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if let Ok(mut ctx) = client_context.write_safe() {
|
||||
ctx.update_download_with_status(
|
||||
token,
|
||||
DownloadStatus::InProgress {
|
||||
bytes_downloaded: 0,
|
||||
total_bytes: download.size,
|
||||
speed_bytes_per_sec: 0.0,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let own_username = own_username.clone();
|
||||
let client_context = client_context.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let download_peer = DownloadPeer::new(
|
||||
@@ -191,35 +172,12 @@ impl Client {
|
||||
allowed,
|
||||
own_username,
|
||||
);
|
||||
let Some(filename) =
|
||||
download.filename.split('\\').next_back()
|
||||
else {
|
||||
error!(
|
||||
"Cant find filename to save download: {:?}",
|
||||
download.filename
|
||||
);
|
||||
return;
|
||||
};
|
||||
match download_peer.download_file(
|
||||
client_context_clone.clone(),
|
||||
client_context,
|
||||
Some(download.clone()),
|
||||
None,
|
||||
) {
|
||||
Ok((download, filename)) => {
|
||||
let _ = download
|
||||
.sender
|
||||
.send(DownloadStatus::Completed);
|
||||
match client_context_clone.write_safe() {
|
||||
Ok(mut ctx) => ctx
|
||||
.update_download_with_status(
|
||||
download.token,
|
||||
DownloadStatus::Completed,
|
||||
),
|
||||
Err(e) => error!(
|
||||
"[client] download complete write: {}",
|
||||
e
|
||||
),
|
||||
}
|
||||
info!(
|
||||
"Successfully downloaded {} bytes to {}",
|
||||
download.size, filename
|
||||
@@ -227,24 +185,9 @@ impl Client {
|
||||
}
|
||||
Err(DownloadError::Cancelled) => {}
|
||||
Err(e) => {
|
||||
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(reason),
|
||||
),
|
||||
Err(e) => error!(
|
||||
"[client] download failed write: {}",
|
||||
e
|
||||
),
|
||||
}
|
||||
error!(
|
||||
"Failed to download file '{}' from {}:{} (token: {}) - Error: {}",
|
||||
filename,
|
||||
download.filename,
|
||||
peer.host,
|
||||
peer.port,
|
||||
download.token,
|
||||
|
||||
@@ -567,16 +567,17 @@ fn a_replayed_transfer_response_does_not_start_a_second_transfer() {
|
||||
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
listener.set_nonblocking(true).unwrap();
|
||||
let port = u32::from(listener.local_addr().unwrap().port());
|
||||
let download_dir = std::env::temp_dir()
|
||||
.join(format!("soulseek-replayed-transfer-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&download_dir);
|
||||
std::fs::create_dir_all(&download_dir).unwrap();
|
||||
|
||||
let client = Client::new("u", "p");
|
||||
let (sender, _receiver) = mpsc::channel();
|
||||
client.context.write().unwrap().add_download(download(
|
||||
"peer",
|
||||
"f.mp3",
|
||||
9,
|
||||
DownloadStatus::Queued,
|
||||
sender,
|
||||
));
|
||||
let mut queued =
|
||||
download("peer", "f.mp3", 9, DownloadStatus::Queued, sender);
|
||||
queued.download_directory = download_dir.display().to_string();
|
||||
client.context.write().unwrap().add_download(queued);
|
||||
|
||||
let (ops_tx, ops_rx) = mpsc::channel();
|
||||
Client::listen_to_client_operations(
|
||||
@@ -625,6 +626,7 @@ fn a_replayed_transfer_response_does_not_start_a_second_transfer() {
|
||||
connections, 1,
|
||||
"a replayed TransferResponse must not dial the peer again"
|
||||
);
|
||||
let _ = std::fs::remove_dir_all(download_dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user