| 1 | //! Exercises the real deploy chain end to end: resolve, manifest, download, |
| 2 | //! checksum, extract. Run manually; it talks to Roblox's servers. |
| 3 | |
| 4 | use nox_roblox::deploy::{install_package, latest, manifest, Binary, Event}; |
| 5 | use std::time::Instant; |
| 6 | |
| 7 | fn main() { |
| 8 | let channel = std::env::args().nth(1).unwrap_or_else(|| "LIVE".into()); |
| 9 | println!("http backend: {}", nox_net::backend_name()); |
| 10 | |
| 11 | let t = Instant::now(); |
| 12 | let v = match latest(Binary::Player, &channel) { |
| 13 | Ok(v) => v, |
| 14 | Err(e) => { |
| 15 | eprintln!("resolve failed: {e}"); |
| 16 | std::process::exit(1); |
| 17 | } |
| 18 | }; |
| 19 | println!("resolved in {:?}", t.elapsed()); |
| 20 | println!(" version {}", v.version); |
| 21 | println!(" upload {}", v.upload); |
| 22 | |
| 23 | let t = Instant::now(); |
| 24 | let m = match manifest(&v.upload, &channel) { |
| 25 | Ok(m) => m, |
| 26 | Err(e) => { |
| 27 | eprintln!("manifest failed: {e}"); |
| 28 | std::process::exit(1); |
| 29 | } |
| 30 | }; |
| 31 | let list = m.installable(); |
| 32 | println!( |
| 33 | "manifest in {:?}: {} packages, {} installable, {:.1} MB packed, {:.1} MB unpacked", |
| 34 | t.elapsed(), |
| 35 | m.packages.len(), |
| 36 | list.len(), |
| 37 | m.total_packed() as f64 / 1e6, |
| 38 | m.total_unpacked() as f64 / 1e6 |
| 39 | ); |
| 40 | for p in m.packages.iter() { |
| 41 | let dest = nox_roblox::package_dir(&p.name).unwrap_or("<skipped>"); |
| 42 | println!(" {:<40} {:>10} -> {}", p.name, p.packed, dest); |
| 43 | } |
| 44 | |
| 45 | let smallest = list.iter().min_by_key(|p| p.packed).expect("packages"); |
| 46 | println!("\ndownloading smallest package: {} ({} bytes)", smallest.name, smallest.packed); |
| 47 | let dir = std::env::temp_dir().join("nox-livecheck"); |
| 48 | let _ = std::fs::remove_dir_all(&dir); |
| 49 | std::fs::create_dir_all(&dir).unwrap(); |
| 50 | |
| 51 | let t = Instant::now(); |
| 52 | let mut last = 0u64; |
| 53 | let mut sink = |e: Event| { |
| 54 | if let Event::PackageBytes { done, total } = e { |
| 55 | if done - last > 200_000 { |
| 56 | last = done; |
| 57 | println!(" {done} / {total}"); |
| 58 | } |
| 59 | } |
| 60 | true |
| 61 | }; |
| 62 | match install_package(&v.upload, &channel, smallest, &dir, &mut sink) { |
| 63 | Ok(files) => { |
| 64 | println!("verified md5 and extracted {files} files in {:?}", t.elapsed()); |
| 65 | let sub = nox_roblox::package_dir(&smallest.name).unwrap(); |
| 66 | let target = if sub.is_empty() { dir.clone() } else { dir.join(sub.trim_end_matches('/')) }; |
| 67 | println!("into {}", target.display()); |
| 68 | let mut shown = 0; |
| 69 | let mut stack = vec![target.clone()]; |
| 70 | while let Some(d) = stack.pop() { |
| 71 | let Ok(rd) = std::fs::read_dir(&d) else { continue }; |
| 72 | for e in rd.flatten() { |
| 73 | if e.path().is_dir() { |
| 74 | stack.push(e.path()); |
| 75 | } else if shown < 8 { |
| 76 | shown += 1; |
| 77 | let rel = e.path().strip_prefix(&target).unwrap().to_path_buf(); |
| 78 | println!(" {} ({} bytes)", rel.display(), e.metadata().map(|m| m.len()).unwrap_or(0)); |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | println!("total on disk: {} bytes", nox_roblox::deploy::directory_size(&dir)); |
| 83 | } |
| 84 | Err(e) => { |
| 85 | eprintln!("install failed: {e}"); |
| 86 | std::process::exit(1); |
| 87 | } |
| 88 | } |
| 89 | } |