pacenotes_installer\selftest/
download_check.rs1pub struct DownloadSelfTest {
5 game: String,
6 server: String,
7 token: Option<String>,
8 out: Option<std::path::PathBuf>,
9 largest: bool,
10}
11
12impl DownloadSelfTest {
13 pub fn from_args() -> Option<DownloadSelfTest> {
14 let mut arguments = std::env::args().skip(1);
15 let mut game = None;
16 let mut server = None;
17 let mut token = None;
18 let mut out = None;
19 let mut largest = false;
20 while let Some(argument) = arguments.next() {
21 match argument.as_str() {
22 "--selftest-download" => game = arguments.next(),
23 "--server" => server = arguments.next(),
24 "--token" => token = arguments.next(),
25 "--out" => out = arguments.next().map(std::path::PathBuf::from),
26 "--largest" => largest = true,
27 _ => {}
28 }
29 }
30 game.map(|game| DownloadSelfTest {
31 game,
32 server: server.unwrap_or_else(|| crate::DEFAULT_SERVER.to_string()),
33 token,
34 out,
35 largest,
36 })
37 }
38
39 pub fn run(&self) -> i32 {
41 let (exit_code, report) = match self.pick_package() {
42 Ok(package) => self.download(&package),
43 Err(message) => (
44 1,
45 format!("RESULT: FAIL\nSTAGE: manifest\nMESSAGE: {message}\n"),
46 ),
47 };
48 super::report::deliver(self.out.as_deref(), &report, exit_code)
49 }
50
51 fn pick_package(&self) -> Result<pacenotes_shared::PackageInfo, String> {
52 let cancel = std::sync::atomic::AtomicBool::new(false);
53 let api = crate::api::Api::new(&self.server, self.token.clone());
54 let manifest = api
55 .fetch_manifest(&self.game, &cancel)
56 .map_err(|e| e.message)?;
57 let mut packages: Vec<_> = manifest
58 .packages
59 .into_iter()
60 .filter(|package| package.game == self.game)
61 .collect();
62 packages.sort_by_key(|package| package.size);
63 let picked = if self.largest {
64 packages.pop()
65 } else {
66 packages.into_iter().next()
67 };
68 picked.ok_or_else(|| format!("no packages for game {}", self.game))
69 }
70
71 fn download(&self, package: &pacenotes_shared::PackageInfo) -> (i32, String) {
73 let cancel = std::sync::atomic::AtomicBool::new(false);
74 let api = crate::api::Api::new(&self.server, self.token.clone());
75 let root = std::env::temp_dir().join(format!("pacenotes-selftest-{}", std::process::id()));
76 let mut cache = pacenotes_installer::cache::Cache::open(&root);
77
78 let started = std::time::Instant::now();
79 let mut bytes_read = 0u64;
80 let mut progress = |read: u64, _: Option<u64>| bytes_read = read;
81 let mut retries = 0;
82 let outcome = crate::package_download::download_retrying(
83 &api,
84 package,
85 &mut cache,
86 &mut progress,
87 &cancel,
88 &mut |_, _| retries += 1,
89 );
90 let millis = started.elapsed().as_millis();
92
93 let result = match outcome {
94 Ok(()) => (
95 0,
96 format!(
97 "RESULT: OK\nPACKAGE: {}\nSIZE: {}\nREAD: {bytes_read}\nSHA256: {}\nVERIFIED: yes\n\
98 PAYLOAD_ON_DISK: {}\nINDEXED: {}\nRETRIES: {retries}\nMILLIS: {millis}\n",
99 package.download_path(),
100 package.size,
101 package.sha256,
102 cache.has_payload(&package.sha256),
103 cache.get(&package.download_path()).is_some(),
104 ),
105 ),
106 Err(e) => (
107 1,
108 format!(
109 "RESULT: FAIL\nSTAGE: download\nPACKAGE: {}\nSIZE: {}\nRETRIES: {retries}\nMESSAGE: {}\n",
110 package.download_path(),
111 package.size,
112 e.message
113 ),
114 ),
115 };
116 let _ = std::fs::remove_dir_all(&root);
117 result
118 }
119}