use std::error::Error;
use tact_client::{HttpClient, ProtocolVersion, Region};
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt::init();
println!("TACT HTTP Range Request Example");
println!("===============================");
let client = HttpClient::new(Region::US, ProtocolVersion::V1)?;
let cdn_host = "blzddist1-a.akamaihd.net";
let path = "tpr/wow/data";
let test_hash = "a9dcee49ab3f952d69441eb3fd91c159";
println!("\n1. Testing Range Request Support");
println!("================================");
println!("CDN Host: {cdn_host}");
println!("Path: {path}");
println!("Hash: {test_hash}");
match client
.download_file_range(cdn_host, path, test_hash, (0, Some(255)))
.await
{
Ok(response) => {
println!("\n✅ Range request successful!");
let status = response.status();
println!("Status: {status}");
println!("Content-Length: {:?}", response.content_length());
if let Some(content_range) = response.headers().get("content-range") {
println!("Content-Range: {content_range:?}");
}
if let Some(accept_ranges) = response.headers().get("accept-ranges") {
println!("Accept-Ranges: {accept_ranges:?}");
}
let partial_data = response.bytes().await?;
println!(
"Downloaded {} bytes (requested first 256 bytes)",
partial_data.len()
);
if status == 206 {
println!("🎉 Server supports HTTP range requests (206 Partial Content)");
} else if status == 200 {
println!("⚠️ Server returned full file (200 OK) - range requests not supported");
println!("Full file size: {} bytes", partial_data.len());
}
}
Err(e) => {
eprintln!("❌ Range request failed: {e}");
}
}
println!("\n2. Comparing Full vs Partial Download");
println!("====================================");
match client.download_file(cdn_host, path, test_hash).await {
Ok(response) => {
let full_data = response.bytes().await?;
println!("Full file size: {} bytes", full_data.len());
match client
.download_file_range(cdn_host, path, test_hash, (0, Some(127)))
.await
{
Ok(range_response) => {
let range_status = range_response.status();
let partial_data = range_response.bytes().await?;
println!(
"Partial download: {} bytes (requested first 128 bytes)",
partial_data.len()
);
if partial_data.len() <= full_data.len() {
let matches = if range_status == 206 {
partial_data == full_data[..partial_data.len()]
} else {
partial_data == full_data
};
if matches {
println!("✅ Partial data matches beginning of full file");
} else {
println!("❌ Partial data does not match full file!");
}
}
}
Err(e) => eprintln!("Failed to download partial content: {e}"),
}
}
Err(e) => eprintln!("Failed to download full file: {e}"),
}
println!("\n3. Multiple Range Requests");
println!("==========================");
let ranges = [
(0, Some(63)), (64, Some(127)), (128, None), ];
for (i, &range) in ranges.iter().enumerate() {
match client
.download_file_range(cdn_host, path, test_hash, range)
.await
{
Ok(response) => {
let data = response.bytes().await?;
match range {
(start, Some(end)) => {
println!(
"Range {}: bytes {}-{} = {} bytes downloaded",
i + 1,
start,
end,
data.len()
);
}
(start, None) => {
println!(
"Range {}: bytes {}- (to end) = {} bytes downloaded",
i + 1,
start,
data.len()
);
}
}
}
Err(e) => eprintln!("Range {} failed: {}", i + 1, e),
}
}
println!("\n4. Multi-Range Request (Advanced)");
println!("==================================");
let multi_ranges = [(0, Some(31)), (64, Some(95))];
match client
.download_file_multirange(cdn_host, path, test_hash, &multi_ranges)
.await
{
Ok(response) => {
println!("Multi-range request status: {}", response.status());
if let Some(content_type) = response.headers().get("content-type") {
println!("Content-Type: {content_type:?}");
if content_type
.to_str()
.unwrap_or("")
.starts_with("multipart/byteranges")
{
println!("✅ Server supports multi-range requests!");
println!("⚠️ Response contains multipart data that needs special parsing");
} else {
println!("🔍 Single content type - server may not support multi-range");
}
}
let data = response.bytes().await?;
println!("Multi-range response size: {} bytes", data.len());
}
Err(e) => eprintln!("Multi-range request failed: {e}"),
}
println!("\n📋 Range Request Use Cases:");
println!("• Download file headers to check formats before full download");
println!("• Implement pause/resume functionality");
println!("• Stream large files by downloading in chunks");
println!("• Reduce bandwidth when only specific parts are needed");
println!("• Parallel downloading of different file sections");
println!("\n⚠️ Important Notes:");
println!("• Not all CDN servers support range requests");
println!("• Some servers ignore range headers and return full content (200 OK)");
println!("• Multi-range requests are less commonly supported");
println!("• Always check response status code (206 = partial, 200 = full)");
Ok(())
}