1pub mod app;
14pub mod keyboard_help;
15pub mod openapi_sync;
16pub mod path_picker;
17pub mod runtime;
18pub mod screens;
19pub mod text_search;
20pub mod theme;
21pub mod utils;
22
23use anyhow::Result;
24use std::time::Duration;
25
26use crate::client::RommClient;
27use crate::config::{openapi_cache_path, should_check_updates, Config};
28use crate::feature_compat::save_sync_compatibility;
29
30use self::app::App;
31use self::openapi_sync::sync_openapi_registry;
32use self::screens::connected_splash::StartupSplash;
33use self::screens::setup_wizard::SetupWizard;
34
35fn install_panic_hook() {
36 let original_hook = std::panic::take_hook();
37 std::panic::set_hook(Box::new(move |panic| {
38 let _ = crossterm::terminal::disable_raw_mode();
39 let _ = crossterm::execute!(
40 std::io::stdout(),
41 crossterm::terminal::LeaveAlternateScreen,
42 crossterm::event::DisableMouseCapture
43 );
44 original_hook(panic);
45 }));
46}
47
48fn startup_splash_for(
49 from_setup_wizard: bool,
50 config: &Config,
51 server_version: &Option<String>,
52) -> Option<StartupSplash> {
53 if from_setup_wizard {
54 return Some(StartupSplash::new(
55 config.base_url.clone(),
56 server_version.clone(),
57 ));
58 }
59 if server_version.is_some() {
60 return Some(StartupSplash::new(
61 config.base_url.clone(),
62 server_version.clone(),
63 ));
64 }
65 None
66}
67
68fn startup_splash_for_launch(
70 from_setup_wizard: bool,
71 config: &Config,
72 server_version: &Option<String>,
73 update_pending: bool,
74) -> Option<StartupSplash> {
75 if update_pending {
76 return None;
77 }
78 startup_splash_for(from_setup_wizard, config, server_version)
79}
80
81async fn run_started(
82 client: RommClient,
83 config: Config,
84 from_setup_wizard: bool,
85 mock_update: bool,
86) -> Result<()> {
87 install_panic_hook();
88 let cache_path = openapi_cache_path()?;
89 let (registry, server_version) = sync_openapi_registry(&client, &cache_path).await?;
90
91 let startup_update = if mock_update {
92 Some(crate::update::UpdateStatus {
93 current_version: format!("{} (dev)", env!("CARGO_PKG_VERSION")),
94 latest_version: "9.9.9-mock".into(),
95 release_tag: "v9.9.9-mock".into(),
96 should_update: true,
97 release_url: "https://github.com/patricksmill/romm-cli".into(),
98 changelog_url: crate::update::changelog_url().to_string(),
99 })
100 } else if should_check_updates() {
101 match tokio::time::timeout(Duration::from_secs(2), crate::update::check_for_update()).await
102 {
103 Ok(Ok(status)) if status.should_update => Some(status),
104 _ => None,
105 }
106 } else {
107 None
108 };
109
110 let splash = startup_splash_for_launch(
111 from_setup_wizard,
112 &config,
113 &server_version,
114 startup_update.is_some(),
115 );
116 let save_sync_compat = save_sync_compatibility(®istry);
117 let mut app = App::new(
118 client,
119 config,
120 save_sync_compat,
121 server_version,
122 splash,
123 startup_update,
124 );
125 app.run().await
126}
127
128pub async fn run(client: RommClient, config: Config, mock_update: bool) -> Result<()> {
130 run_started(client, config, false, mock_update).await
131}
132
133pub async fn run_interactive(verbose: bool, mock_update: bool) -> Result<()> {
135 let (from_wizard, config) = match crate::config::load_config() {
136 Ok(c) => (false, c),
137 Err(_) => (true, SetupWizard::new().run(verbose).await?),
138 };
139 let client = RommClient::new(&config, verbose)?;
140 run_started(client, config, from_wizard, mock_update).await
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::config::{default_theme_id, Config, ExtrasDefaults};
147
148 fn test_config() -> Config {
149 Config {
150 base_url: "http://127.0.0.1:9".into(),
151 download_dir: "/tmp".into(),
152 use_https: false,
153 auth: None,
154 extras_defaults: ExtrasDefaults::default(),
155 save_sync: Default::default(),
156 roms_layout: Default::default(),
157 theme: default_theme_id(),
158 }
159 }
160
161 #[test]
162 fn startup_splash_for_launch_skips_splash_when_update_pending() {
163 let config = test_config();
164 let version = Some("4.0.0".into());
165 assert!(startup_splash_for_launch(false, &config, &version, true).is_none());
166 }
167
168 #[test]
169 fn startup_splash_for_launch_shows_splash_when_no_update() {
170 let config = test_config();
171 let version = Some("4.0.0".into());
172 assert!(startup_splash_for_launch(false, &config, &version, false).is_some());
173 }
174}