Using KGet as a Rust Library
KGet is both a desktop download manager and a reusable Rust download engine. The library API is intended for apps, CLIs, automations, and future native frontends that need HTTP/HTTPS, FTP, SFTP, WebDAV, magnet links, progress callbacks, resume support, proxy support, and multi-algorithm checksum verification.
| English | Português | Español |
Installation
[dependencies]
Kget = "1.7.0"
# Optional: built-in torrent client
Kget = { version = "1.7.0", features = ["torrent-native"] }
# Optional: async API
Kget = { version = "1.7.0", features = ["async"] }
Inside this repository, examples can use:
[dependencies]
Kget = { path = "." }
Quick Start — Builder API (recommended)
use kget::KgetError;
fn main() -> Result<(), KgetError> {
// Simple download
kget::builder("https://example.com/file.zip")
.output("./downloads/")
.connections(8)
.sha256("abc123def456...")
.download()?;
Ok(())
}
Builder Methods
kget::builder(url) returns a DownloadBuilder. All methods are chainable:
| Method | Description |
|---|---|
.output(path) |
Save to file or directory |
.connections(n) |
Parallel connections (turbo mode) |
.speed_limit(bps) |
Max bytes/sec (global token bucket) |
.proxy(url) |
HTTP or SOCKS5 proxy URL |
.proxy_auth(user, pass) |
Credentials for the proxy |
.quiet(bool) |
Suppress progress output |
.sha256(hash) |
Verify SHA-256 after download |
.sha512(hash) |
Verify SHA-512 after download |
.sha1(hash) |
Verify SHA-1 after download |
.md5(hash) |
Verify MD5 after download |
.blake3(hash) |
Verify BLAKE3 after download |
.verify_from(url) |
Download and parse a GNU/BSD sidecar checksum file |
.header(name, value) |
Add an HTTP header |
.retry(config) |
Custom retry policy (see RetryConfig) |
.range(start, end) |
Request a specific byte range |
Terminal methods:
| Method | Returns | Description |
|---|---|---|
.download() |
Result<DownloadResult, KgetError> |
Download to disk |
.download_to_bytes() |
Result<Vec<u8>, KgetError> |
Download into memory |
.download_to_reader() |
Result<impl Read, KgetError> |
Streaming reader |
.spawn() |
Result<(JoinHandle, Receiver<DownloadEvent>), KgetError> |
Background thread with event channel |
.download_async() |
impl Future<…> |
Async API (feature async) |
DownloadResult
pub struct DownloadResult {
pub path: String,
pub bytes_downloaded: u64,
pub avg_speed_bps: f64,
pub duration: std::time::Duration,
pub connections_used: usize,
pub checksums: ComputedChecksums,
}
Batch Downloads
use kget::KgetError;
let results = kget::batch([
"https://mirror1.example.com/file.iso",
"https://mirror2.example.com/other.tar.gz",
])
.concurrency(4)
.output_dir("./downloads/")
.download_all();
for r in results {
match r.result {
Ok(d) => println!("✓ {} — {:.1} MB/s avg", r.url, d.avg_speed_bps / 1e6),
Err(e) => eprintln!("✗ {}: {}", r.url, e),
}
}
kget::batch([...]) returns a BatchBuilder. .concurrency(n) uses a Rayon
thread pool. Returns Vec<BatchResult>.
Async batch: .download_all_async() (behind --features async).
Event Channel
use kget::{DownloadEvent, KgetError};
let (handle, rx) = kget::builder("https://example.com/large.iso")
.connections(4)
.spawn()?;
for event in rx {
match event {
DownloadEvent::Progress { percent, speed_bps, eta_secs } => {
print!("\r{:.1}% {:.1} MB/s eta {}s", percent, speed_bps / 1e6, eta_secs.unwrap_or(0));
}
DownloadEvent::Status(msg) => eprintln!("[status] {msg}"),
DownloadEvent::Completed { path, bytes, avg_speed_bps, .. } => {
println!("\nSaved {bytes} bytes to {path} ({:.1} MB/s avg)", avg_speed_bps / 1e6);
}
DownloadEvent::Error(e) => eprintln!("Error: {e}"),
}
}
handle.join().ok();
# Ok::<(), KgetError>(())
Typed Errors
pub enum KgetError {
Network(reqwest::Error),
Io(std::io::Error),
ChecksumMismatch { algorithm: String, expected: String, got: String },
Protocol(String),
Cancelled,
NotFound(String),
SidecarError(String),
Other(String),
}
KgetError implements std::error::Error + Display. It has From impls for
reqwest::Error, std::io::Error, and Box<dyn Error + Send + Sync>.
Permanent errors (Cancelled, NotFound, ChecksumMismatch) are never
retried regardless of the RetryConfig.
Checksums
use kget::checksum::{compute_checksum, ChecksumAlgorithm};
let hash = compute_checksum(ChecksumAlgorithm::Blake3, std::path::Path::new("file.bin"))?;
println!("BLAKE3: {hash}");
# Ok::<(), Box<dyn std::error::Error>>(())
Supported algorithms: Sha256, Sha512, Sha1, Md5, Blake3.
Sidecar verification (.sha256sum, .md5, etc.):
kget::builder("https://example.com/release.tar.gz")
.verify_from("https://example.com/release.tar.gz.sha256sum")
.download()?;
# Ok::<(), kget::KgetError>(())
.verify_from() downloads the sidecar file, detects the algorithm by hash
length, and verifies after download. Supports GNU (<hash> <file>) and BSD
(SHA256 (file) = hash) formats.
Retry Configuration
use kget::RetryConfig;
kget::builder("https://example.com/file.zip")
.retry(RetryConfig {
max_attempts: 5,
backoff: kget::Backoff::Exponential { base_ms: 200, max_ms: 30_000 },
retry_on_status: vec![503, 429],
})
.download()?;
# Ok::<(), kget::KgetError>(())
Default: 3 attempts, exponential backoff starting at 500 ms, retries 5xx and connection errors only. 4xx responses fail immediately.
ResumePolicy
AdvancedDownloader exposes a set_resume_policy() method to control whether
the interactive ISO-integrity prompt is shown:
use kget::{AdvancedDownloader, ResumePolicy, Optimizer, ProxyConfig};
let mut dl = AdvancedDownloader::new(
"https://example.com/image.iso".to_string(),
"image.iso".to_string(),
true,
ProxyConfig::default(),
Optimizer::new(),
)?;
dl.set_resume_policy(ResumePolicy::AlwaysResume); // never block on stdin
dl.download()?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
| Variant | Behavior |
|---|---|
Ask (default) |
Prompts via stdin in interactive terminal sessions |
AlwaysResume |
Skips prompt, proceeds without asking |
AlwaysRestart |
Skips prompt, restarts from scratch |
Library callers should always set AlwaysResume or AlwaysRestart to avoid
blocking in non-interactive contexts.
Advanced Parallel Download
use kget::{AdvancedDownloader, Optimizer, ProxyConfig};
let mut downloader = AdvancedDownloader::new(
"https://example.com/large.iso".to_string(),
"large.iso".to_string(),
false, // quiet
ProxyConfig::default(),
Optimizer::new(),
)?; // new() returns Result — propagate with ?
downloader.set_resume_policy(kget::ResumePolicy::AlwaysResume);
downloader.set_progress_callback(|progress| {
print!("\r{:.1}%", progress * 100.0);
});
downloader.set_expected_sha256("expected_lowercase_sha256_hash");
downloader.download()?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
AdvancedDownloader splits the file into byte ranges and downloads them in
parallel via rayon. The global TokenBucket throttle (if configured) enforces
the aggregate speed limit across all threads.
Basic Single-Stream Download
use kget::{download, DownloadOptions, Optimizer, ProxyConfig};
let options = DownloadOptions {
output_path: Some("file.zip".to_string()),
..Default::default()
};
download(
"https://example.com/file.zip",
ProxyConfig::default(),
Optimizer::new(),
options,
None,
)?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
Download with Expected SHA-256
use kget::{download, DownloadOptions, Optimizer, ProxyConfig};
let options = DownloadOptions {
output_path: Some("image.iso".to_string()),
expected_sha256: Some("expected_lowercase_sha256_hash".to_string()),
..Default::default()
};
download(
"https://example.com/image.iso",
ProxyConfig::default(),
Optimizer::new(),
options,
Some(&|status| println!("{status}")),
)?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
In-Memory Download
let bytes: Vec<u8> = kget::builder("https://example.com/data.json")
.download_to_bytes()?;
println!("Got {} bytes", bytes.len());
# Ok::<(), kget::KgetError>(())
FTP Download
use kget::ftp::FtpDownloader;
use kget::{Optimizer, ProxyConfig};
let dl = FtpDownloader::new(
"ftp://ftp.gnu.org/gnu/emacs/emacs-28.2.tar.gz".to_string(),
"emacs-28.2.tar.gz".to_string(),
false,
ProxyConfig::default(),
Optimizer::new(),
);
dl.download()?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
SFTP Download
use kget::sftp::SftpDownloader;
use kget::{Optimizer, ProxyConfig};
// Password embedded in the URL
let dl = SftpDownloader::new(
"sftp://user:pass@server.example.com/path/to/file.tar.gz".to_string(),
"file.tar.gz".to_string(),
false,
ProxyConfig::default(),
Optimizer::new(),
);
dl.download()?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
Authentication priority:
- Password from URL (
sftp://user:pass@host/path) - Running SSH agent
- Default key files (
~/.ssh/id_ed25519,~/.ssh/id_rsa,~/.ssh/id_ecdsa)
Host keys are verified against ~/.ssh/known_hosts; mismatches hard-error.
WebDAV Download
use kget::webdav::WebDavDownloader;
use kget::{Optimizer, ProxyConfig};
let dl = WebDavDownloader::new(
"webdavs://user:pass@nas.local/backups/db.tar.gz".to_string(),
"db.tar.gz".to_string(),
false,
ProxyConfig::default(),
Optimizer::new(),
);
dl.download()?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
WebDavDownloader rewrites webdav:// → http:// and webdavs:// →
https://, extracts credentials, and injects HTTP Basic Authorization.
Compatible with Synology, Nextcloud, Apache WebDAV, and any RFC 4918 server.
Auto-detected from URL scheme — kget::is_webdav_url(url) is re-exported from
lib.rs.
yt-dlp Integration
use kget::ytdlp::{download_video, VideoQuality, is_video_url};
if is_video_url("https://www.youtube.com/watch?v=dQw4w9WgXcQ") {
download_video(
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
VideoQuality::Quality720p,
"./downloads",
None, // optional status callback
)?;
}
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
VideoQuality variants: Best, Quality1080p, Quality720p, Quality480p,
Quality360p, Audio. Requires yt-dlp (or youtube-dl) installed on PATH.
Magnet Links
use kget::{download_magnet, Optimizer, ProxyConfig, TorrentCallbacks};
use std::sync::Arc;
let callbacks = TorrentCallbacks {
status: Some(Arc::new(|message| println!("{message}"))),
progress: Some(Arc::new(|progress| println!("{:.1}%", progress * 100.0))),
};
download_magnet(
"magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567",
"./downloads",
true,
ProxyConfig::default(),
Optimizer::new(),
callbacks,
)?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
Build with torrent-native for the built-in torrent client. Without it, KGet
falls back to the platform’s default external magnet handler.
Metalink Downloads
use kget::metalink::download_metalink;
use kget::{Optimizer, ProxyConfig};
download_metalink(
"ubuntu-24.04.meta4", // local file or https:// URL
"~/Downloads",
false,
ProxyConfig::default(),
Optimizer::new(),
)?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
download_metalink parses the RFC 5854 manifest, sorts mirrors by priority
(lowest first), tries each in order, and verifies SHA-256 after a successful
download. A corrupted mirror (hash mismatch) is deleted and the next mirror is
tried automatically.
Parse the manifest yourself:
use kget::metalink::{parse, is_metalink};
if is_metalink("release.meta4") {
let doc = parse(&std::fs::read_to_string("release.meta4")?)?;
for file in &doc.files {
println!("{}: {} mirror(s)", file.name, file.urls.len());
if let Some((kind, hash)) = file.best_hash() {
println!(" hash ({kind}): {hash}");
}
}
}
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
Download History
use kget::queue::{DownloadHistory, EntryStatus, HistoryEntry};
let mut history = DownloadHistory::load();
let entry = HistoryEntry::new(
"https://example.com/file.iso",
"/home/user/Downloads",
Some("expected_sha256_hex"),
);
history.record(entry, EntryStatus::Completed, None);
history.save()?;
for e in history.recent(10) {
println!("{} {} {}", e.created_at_display(), e.status, e.filename);
}
history.clear_completed();
history.save()?;
# Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
History is stored at:
- macOS:
~/Library/Application Support/kget/history.json - Linux:
~/.config/kget/history.json - Windows:
%APPDATA%\kget\history.json
Async API
Behind --features async:
#[tokio::main]
async fn main() -> Result<(), kget::KgetError> {
kget::builder("https://example.com/file.zip")
.output("./downloads/")
.connections(4)
.download_async()
.await?;
Ok(())
}
Both .download_async() and .download_all_async() use
tokio::task::spawn_blocking internally and never block the executor.
Library Guarantees
- Library calls never prompt through
stdinwhenResumePolicyis set. - Progress and status are exposed through callbacks and event channels.
- Files are streamed to disk instead of loaded fully into memory (except
.download_to_bytes()). - Output filenames are validated: rejects null bytes, path traversal, >255-byte names, and Windows reserved device names.
- SHA256 helpers return errors on expected-hash mismatches; never silently accept corrupt files.
- Only 5xx and connection errors are retried; 4xx fails immediately.
See examples/lib_usage.rs for a larger cookbook.