Features
- Multithreaded download
- Breakpoint resume
- Download speed limit
- Download speed tracking
- Modify at download time
- max parallel connection count
- max download speed
- chunk size
Required minimum dependency
http-downloader = { version = "0.1" }
url = { version = "2" }
tokio = { version = "1", features = ["rt", "macros"] }
A simple http downloader
terminal ui:https://github.com/ycysdf/http-downloader-tui
cargo futures
Some features are not enabled by default
[features]
default = ["tracing"]
async-graphql = ["dep:async-graphql"]
all-extensions = ["status-tracker", "speed-limiter", "speed-tracker", "breakpoint-resume", "tracing", "bson-file-archiver"]
status-tracker = ["tracing"]
speed-tracker = ["tracing"]
speed-limiter = ["tracing"]
breakpoint-resume = ["tracing"]
bson-file-archiver = ["breakpoint-resume", "tracing", "serde", "bson", "url/serde"]
Example
use std::num::{NonZeroU8, NonZeroUsize};
use std::path::PathBuf;
use std::time::Duration;
use anyhow::Result;
use tracing::info;
use url::Url;
use http_downloader::{
breakpoint_resume::DownloadBreakpointResumeExtension,
HttpDownloaderBuilder,
speed_limiter::DownloadSpeedLimiterExtension,
speed_tracker::DownloadSpeedTrackerExtension,
status_tracker::DownloadStatusTrackerExtension,
};
use http_downloader::bson_file_archiver::{ArchiveFilePath, BsonFileArchiverBuilder};
#[tokio::main]
async fn main() -> Result<()> {
{
tracing_subscriber::fmt::init();
}
let save_dir = PathBuf::from("C:/download");
let test_url = Url::parse("http://mirror.hk.leaseweb.net/speedtest/1000mb.bin")?;
let (downloader, (status_state, speed_state, speed_limiter, ..)) =
HttpDownloaderBuilder::new(test_url, save_dir)
.chunk_size(NonZeroUsize::new(1024 * 1024 * 10).unwrap()) .download_connection_count(NonZeroU8::new(3).unwrap()) .build((
DownloadStatusTrackerExtension { log: true },
DownloadSpeedTrackerExtension { log: true },
DownloadSpeedLimiterExtension {
byte_count_per: None
},
DownloadBreakpointResumeExtension {
download_archiver_builder: BsonFileArchiverBuilder::new(ArchiveFilePath::Suffix("bson".to_string()))
}
));
info!("Start download,开始下载");
let finished_future = downloader.start().await?;
let _status = status_state.status(); let _status_receiver = status_state.status_receiver; let _byte_per_second = speed_state.download_speed(); let _speed_receiver = speed_state.receiver;
tokio::spawn({
let mut downloaded_len_receiver = downloader.downloaded_len_receiver().clone();
async move {
let total_len = downloader.total_size().await;
if let Some(total_len) = total_len {
info!("Total size: {:.2} Mb",total_len.get() as f64 / 1024_f64/ 1024_f64);
}
while downloaded_len_receiver.changed().await.is_ok() {
let progress = *downloaded_len_receiver.borrow();
if let Some(total_len) = total_len {
info!("Download Progress: {} %,{}/{}",progress*100/total_len,progress,total_len);
}
tokio::time::sleep(Duration::from_millis(1000)).await;
}
}
});
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(2)).await;
info!("Start speed limit,开始限速");
speed_limiter.change_speed(Some(1024 * 1024 * 2)).await;
tokio::time::sleep(Duration::from_secs(4)).await;
info!("Remove the download speed limit,解除速度限制");
speed_limiter.change_speed(None).await;
});
info!("Wait for download to end,等待下载结束");
let dec = finished_future.await?;
info!("Downloading end cause: {:?}", dec);
Ok(())
}