1use std::io::{self, Write};
10use std::thread;
11use std::time::{Duration, Instant};
12
13use crossterm::{
14 cursor::MoveTo,
15 execute,
16 style::{Color, Print, ResetColor, SetForegroundColor},
17 terminal::{Clear, ClearType},
18};
19use inkling::{ordering::Geodesic, render::Style, Loader};
20
21fn step(mark: &str, color: Color, msg: &str) {
22 let _ = execute!(
23 io::stdout(),
24 Print(" "),
25 SetForegroundColor(color),
26 Print(mark),
27 ResetColor,
28 Print(format!(" {msg}\r\n"))
29 );
30}
31
32fn pause(ms: u64) {
33 thread::sleep(Duration::from_millis(ms));
34}
35
36fn main() {
37 let args: Vec<String> = std::env::args().skip(1).collect();
38 let rainbow = args.iter().any(|a| a == "rainbow");
39 let geodesic = args.iter().any(|a| a == "geodesic");
40 let art_path = args.iter().find(|a| a.ends_with(".txt")).cloned();
41 let started = Instant::now();
42 let gold = Color::Rgb {
43 r: 232,
44 g: 180,
45 b: 85,
46 };
47
48 let _ = execute!(
50 io::stdout(),
51 Clear(ClearType::All),
52 MoveTo(0, 0),
53 Print("\r\n "),
54 SetForegroundColor(gold),
55 Print("dragonctl"),
56 ResetColor,
57 Print(" v0.2.0\r\n\r\n")
58 );
59
60 step("\u{2713}", Color::Green, "Initializing demo environment");
61 pause(450);
62 step("\u{2713}", Color::Green, "Updating base image index");
63 pause(500);
64 step("\u{2193}", Color::Cyan, "Downloading base image");
65 let _ = execute!(io::stdout(), Print("\r\n"));
66
67 let total: u64 = 48 * 1024 * 1024;
70 let mb = 1024.0 * 1024.0;
71 let schedule: &[(f64, u64)] = &[
72 (0.0, 600),
73 (5.0, 300),
74 (8.0, 250),
75 (8.0, 650),
76 (16.0, 220),
77 (27.0, 180),
78 (38.0, 200),
79 (45.0, 450),
80 (56.0, 200),
81 (67.0, 220),
82 (78.0, 260),
83 (87.0, 320),
84 (93.0, 480),
85 (97.0, 520),
86 (100.0, 300),
87 ];
88
89 let style = if rainbow {
90 Style::rainbow()
91 } else {
92 Style::default()
93 };
94 let mut builder = Loader::builder().total(total).style(style);
95 if geodesic {
96 builder = builder.ordering(Geodesic::default());
97 }
98 if let Some(path) = &art_path {
99 let text = std::fs::read_to_string(path).unwrap_or_else(|e| {
100 eprintln!("could not read {path}: {e}");
101 std::process::exit(1);
102 });
103 builder = builder.art(inkling::Art::parse(&text));
104 }
105 let loader = builder.start();
106 for &(percent, dwell) in schedule {
107 let done = (percent / 100.0 * total as f64) as u64;
108 loader.set(done);
109 loader.set_message(format!(
110 "dragon.iso {:.1} / {:.1} MB",
111 done as f64 / mb,
112 total as f64 / mb
113 ));
114 pause(dwell);
115 }
116 loader.finish();
117
118 let _ = execute!(io::stdout(), Print("\r\n"));
120 step(
121 "\u{2713}",
122 Color::Green,
123 "Verified checksum sha256:a1b2c3d4e5",
124 );
125 pause(400);
126 let _ = execute!(
127 io::stdout(),
128 Print("\r\n "),
129 SetForegroundColor(Color::Green),
130 Print("Done"),
131 ResetColor,
132 Print(format!(
133 " in {:.1}s. dragon.iso (48.0 MB) ready.\r\n\r\n",
134 started.elapsed().as_secs_f64()
135 ))
136 );
137 let _ = io::stdout().flush();
138}