Skip to content

Draft: Download manager #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open

Draft: Download manager #7

wants to merge 31 commits into from

Conversation

cyberphantom52
Copy link
Contributor

@cyberphantom52 cyberphantom52 commented Jul 20, 2025

Implements #6

TODO:

  • Retry with backoff
  • Cancel Download
  • Pause/Resume
  • Callbacks (Do we even need these)
  • Timeouts
  • Better progress tracking
  • DownloadManager stats(e.g active/queued/failed/completed downloads, total data downloaded)
  • ...

Copy link
Member

@mirkobrombin mirkobrombin Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the status channel being created but never updated to InProgress, Completed, or Failed (am I wrong?)
There are also more things that are missing but I imagine this is still a WIP.

Good job for the moment <3

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not even be working :). I just wanted to put it out so the design can evolve with comments.

progress: progress_tx,
};

let _ = self.queue.try_send(req);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the try_send safe to be ignored here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, i just need a new error type to represent the error here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roger!

Comment on lines +11 to +12
#[error("Oneshot: {0}")]
Oneshot(#[from] tokio::sync::oneshot::error::RecvError),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like having to add this specific error type.

Comment on lines 101 to 111
pub fn set_max_parallel_downloads(&self, limit: usize) {
let current = self.semaphore.available_permits();
if limit > current {
self.semaphore.add_permits(limit - current);
} else if limit < current {
let to_remove = current - limit;
for _ in 0..to_remove {
let _ = self.semaphore.try_acquire();
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On looking carefully, This has a race condition so this needs to be reimplemented.

edfloreshz and others added 2 commits July 20, 2025 18:31
- added missing impl for GPTK
- fixed warnings and clippy
This fixes a bug where if we didn't store the handle to the download somewhere it would automatically cancel the download
}
}

async fn dispatcher_thread(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dispatch and download threads can outlive the DownloadManager itself. Is this desirable or should we keep track of the threads to manage their lifecycles?

Comment on lines 107 to 130
loop {
tokio::select! {
_ = req.cancel.cancelled() => {
drop(file); // Manually drop the file handle to ensure that deletion doesn't fail
tokio::fs::remove_file(&req.destination).await?;
return Err(Error::Download(DownloadError::Cancelled));
}
chunk = response.chunk() => {
match chunk {
Ok(Some(chunk)) => {
file.write_all(&chunk).await?;
bytes_downloaded += chunk.len() as u64;
update_progress(bytes_downloaded, total_bytes);
}
Ok(None) => break,
Err(e) => {
drop(file); // Manually drop the file handle to ensure that deletion doesn't fail
tokio::fs::remove_file(&req.destination).await?;
return Err(Error::Reqwest(e))
},
}
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The manual drop, remove_file, req.status.send, req.result.send are error prone, do we have any ideas how to automatically do these

manager
}

pub fn download(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename this method to something like new_request_builder since it now returns a download request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants