modde_sources/wabbajack/
cdn.rs1use std::collections::HashMap;
6use std::path::Path;
7
8use anyhow::Result;
9use reqwest::Client;
10
11use modde_core::manifest::wabbajack::DownloadDirective;
12
13use crate::common::ensure_parent;
14use crate::error::{SourceError, SourceResult};
15use crate::traits::{DownloadHandle, DownloadSource, ProgressCallback, VerifiedFile};
16
17use super::catalog::download_authored_file_to_path;
18use super::preflight::preflight_authored_files;
19
20pub struct WabbajackCdnSource {
22 client: Client,
23}
24
25impl WabbajackCdnSource {
26 #[must_use]
27 pub const fn new(client: Client) -> Self {
28 Self { client }
29 }
30
31 pub async fn preflight_archives(
32 &self,
33 archives: &[modde_core::manifest::wabbajack::ArchiveEntry],
34 ) -> Result<()> {
35 preflight_authored_files(&self.client, archives).await
36 }
37}
38
39impl DownloadSource for WabbajackCdnSource {
40 fn can_handle(&self, directive: &DownloadDirective) -> bool {
41 matches!(directive, DownloadDirective::WabbajackCdn { .. })
42 }
43
44 async fn resolve(&self, directive: &DownloadDirective) -> SourceResult<DownloadHandle> {
45 let DownloadDirective::WabbajackCdn { url, hash } = directive else {
46 return Err(SourceError::other(anyhow::anyhow!(
47 "not a WabbajackCdn directive"
48 )));
49 };
50
51 Ok(DownloadHandle {
52 url: url.clone(),
53 candidate_urls: Vec::new(),
54 headers: HashMap::new(),
55 expected_hash: *hash,
56 size_hint: None,
57 })
58 }
59
60 async fn download_with_progress(
61 &self,
62 handle: DownloadHandle,
63 dest: &Path,
64 progress: ProgressCallback,
65 ) -> SourceResult<VerifiedFile> {
66 ensure_parent(dest).await?;
67 download_authored_file_to_path(
68 &self.client,
69 &handle.url,
70 dest,
71 Some(handle.expected_hash),
72 Some(&progress),
73 )
74 .await
75 .map_err(SourceError::other)?;
76 Ok(VerifiedFile {
77 path: dest.to_path_buf(),
78 hash: handle.expected_hash,
79 })
80 }
81}