Crates.io | ngdp-cdn |
lib.rs | ngdp-cdn |
version | 0.4.3 |
created_at | 2025-06-28 14:46:40.7416+00 |
updated_at | 2025-08-11 12:09:23.949988+00 |
description | CDN client with parallel downloads and fallback support for Blizzard's NGDP |
homepage | https://github.com/wowemulation-dev/cascette-rs |
repository | https://github.com/wowemulation-dev/cascette-rs |
max_upload_size | |
id | 1729896 |
size | 174,654 |
CDN client for downloading NGDP (Next Generation Distribution Pipeline) content from Blizzard's CDN servers.
Add this to your Cargo.toml
:
[dependencies]
ngdp-cdn = "0.3"
use ngdp_cdn::CdnClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create a CDN client
let client = CdnClient::new()?;
// Download content by hash
let response = client.download(
"blzddist1-a.akamaihd.net",
"tpr/wow",
"2e9c1e3b5f5a0c9d9e8f1234567890ab",
).await?;
let content = response.bytes().await?;
println!("Downloaded {} bytes", content.len());
Ok(())
}
use ngdp_cdn::CdnClient;
let client = CdnClient::builder()
.max_retries(5)
.initial_backoff_ms(200)
.max_backoff_ms(30_000)
.connect_timeout(60)
.request_timeout(300)
.pool_max_idle_per_host(50)
.build()?;
The crate provides CdnClientWithFallback
which automatically tries multiple CDN hosts
when downloads fail. It prioritizes Blizzard's official CDN servers first, then falls
back to community mirrors only if all primary servers fail.
use ngdp_cdn::CdnClientWithFallback;
// Create with default backup CDNs (arctium.tools and reliquaryhq.com)
let client = CdnClientWithFallback::new()?;
// Add Blizzard CDNs from Ribbit response (these are tried first)
client.add_primary_cdns(vec![
"blzddist1-a.akamaihd.net",
"level3.blizzard.com",
"blzddist2-a.akamaihd.net",
]);
// Download process:
// 1. Try blzddist1-a.akamaihd.net
// 2. Try level3.blizzard.com
// 3. Try blzddist2-a.akamaihd.net
// 4. Try cdn.arctium.tools (community backup)
// 5. Try tact.mirror.reliquaryhq.com (community backup)
let response = client.download("tpr/wow", "content_hash").await?;
By default, the fallback client includes two backup CDN servers that are only used after all Blizzard CDNs have been exhausted:
http://cdn.arctium.tools/
https://tact.mirror.reliquaryhq.com/
These are community-maintained mirrors that provide access to game content when official servers are unavailable.
If you'd like to suggest changes to the default community backup CDNs (add new ones, update existing ones, or remove inactive ones), please file a ticket on our GitHub Issues page.
When suggesting a community CDN, please include:
let client = CdnClientWithFallback::builder()
.add_primary_cdn("primary.example.com")
.add_primary_cdn("secondary.example.com")
.use_default_backups(false) // Disable default backup CDNs
.configure_base_client(|builder| {
builder
.max_retries(5)
.initial_backoff_ms(200)
})
.build()?;
NGDP CDN URLs follow a specific pattern for content addressing:
http://{cdn_host}/{path}/{hash[0:2]}/{hash[2:4]}/{hash}
For example:
2e9c1e3b5f5a0c9d9e8f1234567890ab
blzddist1-a.akamaihd.net
tpr/wow
http://blzddist1-a.akamaihd.net/tpr/wow/2e/9c/2e9c1e3b5f5a0c9d9e8f1234567890ab
The crate provides specific error types for CDN operations:
use ngdp_cdn::Error;
match client.download(host, path, hash).await {
Ok(response) => {
// Process response
}
Err(Error::ContentNotFound { hash }) => {
println!("Content {} not found on CDN", hash);
}
Err(Error::RateLimited { retry_after_secs }) => {
println!("Rate limited, retry after {} seconds", retry_after_secs);
}
Err(e) => {
println!("Other error: {}", e);
}
}
This crate is designed to work with other NGDP components:
ribbit-client
to get CDN configurationtact-client
to get content manifestsngdp-cdn
to download the actual content// Example workflow with automatic fallback
let ribbit = ribbit_client::RibbitClient::new(Region::US);
let cdns = ribbit.get_product_cdns("wow").await?;
let tact = tact_client::HttpClient::new(Region::US)?;
let versions = tact.get_versions_parsed("wow").await?;
// Use fallback client for automatic CDN failover
let cdn_client = ngdp_cdn::CdnClientWithFallback::new()?;
// Add all CDN hosts from Ribbit response as primary
for cdn_entry in &cdns {
cdn_client.add_primary_cdns(&cdn_entry.hosts);
}
// Download will automatically try all CDNs (primary + backup)
let content = cdn_client.download(&cdns[0].path, &content_hash).await?;
This project is dual-licensed under either:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
This crate is part of the cascette-rs
project, providing tools for World of Warcraft
emulation development.