|
1 | 1 | use reqwest::{Client, Url};
|
2 |
| -use std::{ |
| 2 | +use std::{path::PathBuf, sync::Arc}; |
| 3 | +use tokio::{ |
3 | 4 | fs::File,
|
4 |
| - io::{Seek, SeekFrom, Write}, |
5 |
| - path::PathBuf, |
6 |
| - sync::Arc, |
| 5 | + io::AsyncWriteExt, |
| 6 | + sync::{mpsc, oneshot, watch, Semaphore}, |
7 | 7 | };
|
8 |
| -use tokio::sync::{mpsc, oneshot, watch, Semaphore}; |
9 | 8 |
|
10 | 9 | use crate::Error;
|
11 | 10 |
|
@@ -36,7 +35,7 @@ pub struct DownloadHandle {
|
36 | 35 | }
|
37 | 36 |
|
38 | 37 | impl DownloadHandle {
|
39 |
| - pub async fn r#await(self) -> Result<std::fs::File, Error> { |
| 38 | + pub async fn r#await(self) -> Result<File, Error> { |
40 | 39 | match self.result.await {
|
41 | 40 | Ok(result) => result,
|
42 | 41 | Err(_) => todo!(),
|
@@ -173,39 +172,36 @@ async fn dispatcher_thread(
|
173 | 172 | }
|
174 | 173 |
|
175 | 174 | 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(); |
178 | 177 | 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 | + ))); |
190 | 192 | }
|
191 | 193 | let chunk = chunk?;
|
192 |
| - file.write_all(&chunk)?; |
| 194 | + file.write_all(&chunk).await?; |
193 | 195 | bytes_downloaded += chunk.len() as u64;
|
194 | 196 | let _ = req.status.send(Status::InProgress(DownloadProgress {
|
195 | 197 | bytes_downloaded,
|
196 | 198 | total_bytes,
|
197 | 199 | }));
|
198 | 200 | }
|
199 | 201 |
|
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) |
211 | 207 | }
|
0 commit comments