Skip to content

Commit 395ced4

Browse files
downloader: Improve File handling and use switch to tokio::fs::File
This is to make sure we don't block the runtime.
1 parent 447be8e commit 395ced4

File tree

1 file changed

+27
-31
lines changed

1 file changed

+27
-31
lines changed

src/downloader.rs

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use reqwest::{Client, Url};
2-
use std::{
2+
use std::{path::PathBuf, sync::Arc};
3+
use tokio::{
34
fs::File,
4-
io::{Seek, SeekFrom, Write},
5-
path::PathBuf,
6-
sync::Arc,
5+
io::AsyncWriteExt,
6+
sync::{mpsc, oneshot, watch, Semaphore},
77
};
8-
use tokio::sync::{mpsc, oneshot, watch, Semaphore};
98

109
use crate::Error;
1110

@@ -36,7 +35,7 @@ pub struct DownloadHandle {
3635
}
3736

3837
impl DownloadHandle {
39-
pub async fn r#await(self) -> Result<std::fs::File, Error> {
38+
pub async fn r#await(self) -> Result<File, Error> {
4039
match self.result.await {
4140
Ok(result) => result,
4241
Err(_) => todo!(),
@@ -173,39 +172,36 @@ async fn dispatcher_thread(
173172
}
174173

175174
async fn download_thread(client: Client, req: &DownloadRequest) -> Result<File, Error> {
176-
let mut resp = client.get(req.url.as_ref()).send().await?;
177-
let total_bytes = resp.content_length();
175+
let mut response = client.get(req.url.as_ref()).send().await?;
176+
let total_bytes = response.content_length();
178177
let mut bytes_downloaded = 0u64;
179-
let mut cancelled = false;
180-
let mut file = File::options()
181-
.read(true)
182-
.write(true)
183-
.create(true)
184-
.open(&req.destination)?;
185-
186-
while let Some(chunk) = resp.chunk().await.transpose() {
187-
cancelled = !req.cancel.is_empty();
188-
if cancelled {
189-
break;
178+
179+
// Create the destination directory if it doesn't exist
180+
if let Some(parent) = req.destination.parent() {
181+
tokio::fs::create_dir_all(parent).await?;
182+
}
183+
let mut file = File::create(&req.destination).await?;
184+
185+
while let Some(chunk) = response.chunk().await.transpose() {
186+
if !req.cancel.is_empty() {
187+
tokio::fs::remove_file(&req.destination).await?;
188+
return Err(Error::Io(std::io::Error::new(
189+
std::io::ErrorKind::Interrupted,
190+
"Download cancelled",
191+
)));
190192
}
191193
let chunk = chunk?;
192-
file.write_all(&chunk)?;
194+
file.write_all(&chunk).await?;
193195
bytes_downloaded += chunk.len() as u64;
194196
let _ = req.status.send(Status::InProgress(DownloadProgress {
195197
bytes_downloaded,
196198
total_bytes,
197199
}));
198200
}
199201

200-
if cancelled {
201-
std::fs::remove_file(&req.destination)?;
202-
Err(Error::Io(std::io::Error::new(
203-
std::io::ErrorKind::Interrupted,
204-
"Download cancelled",
205-
)))
206-
} else {
207-
// Reset the cursor to the beginning of the file
208-
file.seek(SeekFrom::Start(0))?;
209-
Ok(file)
210-
}
202+
// Ensure the data is written to disk
203+
file.sync_all().await?;
204+
// Open a new file handle with RO permissions
205+
let file = File::options().read(true).open(&req.destination).await?;
206+
Ok(file)
211207
}

0 commit comments

Comments
 (0)