diff --git a/Cargo.toml b/Cargo.toml index f7d9237..ff0cb12 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shticker_book_unwritten" -version = "0.2.0" +version = "0.3.0" authors = ["Dr. Jonathan Helianthicus Doe, IV "] edition = "2018" description = "Minimal CLI launcher for the Toontown Rewritten MMORPG" diff --git a/img/shticker_book_unwritten.svg b/img/shticker_book_unwritten.svg index c30eff0..a850b5c 100644 --- a/img/shticker_book_unwritten.svg +++ b/img/shticker_book_unwritten.svg @@ -29,8 +29,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.70710678" - inkscape:cx="419.71809" - inkscape:cy="577.92742" + inkscape:cx="228.36795" + inkscape:cy="369.35229" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" @@ -49,7 +49,7 @@ image/svg+xml - + @@ -419,6 +419,11 @@ id="path977" d="m 125.80613,280.78875 c -3.2071,-1.42129 -6.40678,-2.85634 -9.66346,-4.16489 -2.01534,-0.85158 -4.05987,-1.63981 -6.03602,-2.58069 -1.72133,-0.86302 -3.4431,-1.72495 -5.1581,-2.60054 -1.38706,-0.77946 -2.77283,-1.55852 -4.17016,-2.31898 -1.086635,-0.54927 -2.127326,-1.18727 -3.177,-1.80397 -0.914325,-0.42854 -1.818012,-0.87459 -2.689613,-1.38765 -0.750234,-0.43318 -1.251575,-1.1794 -1.975533,-1.63927 -0.802352,-0.54549 -1.66637,-1.0031 -2.538031,-1.42852 -1.099429,-0.53452 -2.158979,-1.13825 -3.163234,-1.83569 -0.770779,-0.49097 -1.620968,-0.8423 -2.434463,-1.25683 -1.008833,-0.45111 -1.972035,-0.98819 -2.909168,-1.57223 -0.775452,-0.54613 -1.642306,-0.8408 -2.521244,-1.1595 -1.107442,-0.50748 -2.206905,-1.02316 -3.321388,-1.51394 -1.059879,-0.53082 -2.093905,-1.10897 -3.133202,-1.67791 -0.882028,-0.39956 -1.823071,-0.63 -2.715752,-1.01148 -0.892288,-0.45534 -1.791898,-0.88405 -2.718879,-1.26556 -0.923335,-0.47499 -1.854115,-0.92502 -2.747428,-1.45579 -1.012013,-0.55148 -1.993236,-1.16528 -2.945516,-1.81471 -0.981067,-0.61405 -1.962243,-1.22413 -2.925123,-1.86681 -0.893455,-0.64834 -1.82868,-1.23548 -2.756781,-1.83224 -0.868881,-0.52245 -1.678918,-1.12286 -2.490353,-1.7281 -0.652828,-0.51747 -1.35001,-0.97779 -2.063568,-1.40798 -0.95033,-0.61587 -1.813237,-1.35025 -2.727225,-2.01444 -0.954445,-0.70391 -1.908786,-1.40526 -2.865608,-2.10609 -1.002007,-0.60181 -1.93322,-1.30876 -2.892313,-1.97484 -0.982799,-0.50284 -1.738586,-1.31429 -2.596907,-1.983 -0.996498,-0.51601 -1.855213,-1.24226 -2.764779,-1.88859 -0.977615,-0.6677 -1.818344,-1.50421 -2.71381,-2.27276 -0.839881,-0.78114 -1.606331,-1.62547 -2.454042,-2.40104 -0.86201,-0.66394 -1.781146,-1.25532 -2.710888,-1.82025 -0.879495,-0.6137 -1.849634,-1.07059 -2.765733,-1.62127 -0.879201,-0.46019 -1.751684,-0.9337 -2.609861,-1.43535 -1.051949,-0.48812 -1.978517,-1.17752 -2.935289,-1.81974 -0.451358,-0.27161 -0.874105,-0.58445 -1.296006,-0.89866 -2.418585,-1.8149 0.148072,-5.23529 2.566658,-3.42039 v 0 c 0.363927,0.27613 0.734237,0.54234 1.126491,0.77779 0.877068,0.59732 1.731657,1.22485 2.701738,1.67241 0.886127,0.52201 1.793493,0.99859 2.6968,1.48774 0.882867,0.58439 1.898183,0.96915 2.749727,1.61141 1.157563,0.71394 2.315322,1.44184 3.363518,2.31176 0.814032,0.74528 1.562483,1.54718 2.352931,2.31139 0.799839,0.68725 1.546959,1.43848 2.416461,2.03943 0.970915,0.69856 1.912442,1.43252 2.952348,2.03079 0.768816,0.62684 1.470886,1.34042 2.360103,1.80609 0.988773,0.68683 1.951626,1.40939 2.980045,2.03742 0.95913,0.70279 1.914889,1.4071 2.872863,2.11141 0.811948,0.60258 1.591265,1.24774 2.429857,1.81428 0.822127,0.51035 1.640546,1.03401 2.398837,1.63636 0.725691,0.54996 1.453748,1.08664 2.239179,1.5527 0.944293,0.6127 1.902106,1.20608 2.812801,1.86907 0.975646,0.65397 1.975014,1.26502 2.966392,1.89476 0.877433,0.60613 1.791163,1.16362 2.726931,1.67438 0.709851,0.43225 1.460222,0.77056 2.186101,1.17293 0.962282,0.40157 1.906212,0.83756 2.832402,1.31458 0.958855,0.49242 2.101506,0.57057 3.022198,1.16415 0.930391,0.51304 1.861865,1.02305 2.803646,1.51495 1.026039,0.45571 2.049614,0.91012 3.056634,1.40731 1.157972,0.42471 2.297758,0.85891 3.328712,1.5543 0.831376,0.52568 1.69323,0.98828 2.591154,1.39131 0.983279,0.5107 2.023534,0.92221 2.936341,1.55976 0.818478,0.58273 1.698821,1.05815 2.598846,1.5013 1.072361,0.53268 2.138487,1.09401 3.123308,1.77765 0.59395,0.43746 1.158716,0.92554 1.673683,1.44343 0.869201,0.51551 1.78376,0.92989 2.684394,1.38457 1.007688,0.59456 2.007638,1.20795 3.052858,1.73365 1.36399,0.74336 2.71955,1.49974 4.07067,2.2665 1.68157,0.85999 3.37136,1.70361 5.059,2.55149 1.88886,0.91062 3.85852,1.64363 5.78448,2.47005 3.13557,1.26122 6.23742,2.60128 9.29716,4.03662 2.89628,0.86886 1.66749,4.96482 -1.22879,4.09596 z" inkscape:connector-curvature="0" /> + - + diff --git a/img/shticker_book_unwritten_256x256.png b/img/shticker_book_unwritten_256x256.png index efe563d..041542f 100644 Binary files a/img/shticker_book_unwritten_256x256.png and b/img/shticker_book_unwritten_256x256.png differ diff --git a/src/command.rs b/src/command.rs index c72edd6..8b4e292 100644 --- a/src/command.rs +++ b/src/command.rs @@ -35,6 +35,7 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( config: &mut Config, config_path: P, client: &reqwest::Client, + quiet: bool, maybe_usernames: Option, detach: bool, ) -> Result<(), Error> { @@ -45,17 +46,20 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( config, &config_path, client, + quiet, [username].iter().copied(), )? { if !detach { children.push(c); } - println!("Game launched successfully!"); + if !quiet { + println!("Game launched successfully!"); + } } } - if !detach { + if !detach && !quiet { println!(); } }; @@ -64,11 +68,13 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( return Ok(()); } - println!(concat!( - "Welcome to ", - crate_name!(), - "! Type help or ? to get a list of commands.", - )); + if !quiet { + println!(concat!( + "Welcome to ", + crate_name!(), + "! Type help or ? to get a list of commands.", + )); + } let mut command_buf = String::with_capacity(0x10); 'outer: loop { @@ -92,14 +98,14 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( None => (), Some("help") | Some("?") => { help(); - check_children(&mut children)?; + check_children(quiet, &mut children)?; }, Some("about") => { about(); - check_children(&mut children)?; + check_children(quiet, &mut children)?; }, Some("quit") | Some("exit") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; if children.is_empty() { break; } else if children.len() == 1 { @@ -137,9 +143,9 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( } }, Some("update") | Some("up") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; if children.is_empty() { - update::update(config, client)? + update::update(config, client, quiet)? } else if children.len() == 1 { println!( "There's still a game instance running, can't update \ @@ -155,28 +161,30 @@ pub fn enter_command_mode<'a, P: AsRef, U: Iterator>( }, Some("login") | Some("play") | Some("launch") => { if let Some(c) = - login::login(config, &config_path, client, argv)? + login::login(config, &config_path, client, quiet, argv)? { children.push(c); - println!("Game launched successfully!"); + if !quiet { + println!("Game launched successfully!"); + } } - check_children(&mut children)?; + check_children(quiet, &mut children)?; }, Some("instances") | Some("running") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; display_instances(&children); }, Some("kill") | Some("close") => { - check_children(&mut children)?; - kill_instance(&mut children, argv.next())?; + check_children(quiet, &mut children)?; + kill_instance(quiet, &mut children, argv.next())?; }, Some("accounts") | Some("logins") => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; display_accounts(config, &children)?; }, _ => { - check_children(&mut children)?; + check_children(quiet, &mut children)?; println!( "Unrecognized command. Type help or ? to get a list of \ commands.", @@ -280,6 +288,7 @@ fn display_instances(instances: &[(String, process::Child, time::Instant)]) { } fn kill_instance( + quiet: bool, children: &mut Vec<(String, process::Child, time::Instant)>, arg: Option<&str>, ) -> Result<(), Error> { @@ -316,7 +325,9 @@ fn kill_instance( let pid = child.id(); let uptime_sec = timestamp.elapsed().as_secs(); - println!("Killing instance..."); + if !quiet { + println!("Killing instance..."); + } if let Err(ioe) = child.kill() { if ioe.kind() != io::ErrorKind::InvalidInput { @@ -324,18 +335,25 @@ fn kill_instance( } } - println!("Joining instance's thread..."); + if !quiet { + println!("Joining instance's thread..."); + } child.wait().map_err(Error::ThreadJoinError)?; - println!("Successfully killed {}'s instance with pid {},", name, pid); - let secs = uptime_sec % 60; - let minutes = (uptime_sec / 60) % 60; - let hours = uptime_sec / (60 * 60); - println!( - "which had an approximate uptime of {}h {:02}m {:02}s.", - hours, minutes, secs, - ); + if !quiet { + println!( + "Successfully killed {}'s instance with pid {},", + name, pid + ); + let secs = uptime_sec % 60; + let minutes = (uptime_sec / 60) % 60; + let hours = uptime_sec / (60 * 60); + println!( + "which had an approximate uptime of {}h {:02}m {:02}s.", + hours, minutes, secs, + ); + } children.remove(i); } else { @@ -381,6 +399,7 @@ fn display_accounts( /// Naïve implementation because, let's be real, how many instances of the game /// are you really going to run concurrently? fn check_children( + quiet: bool, children: &mut Vec<(String, process::Child, time::Instant)>, ) -> Result<(), Error> { let mut i = 0; @@ -388,15 +407,20 @@ fn check_children( if let Some(exit_status) = child.try_wait().map_err(Error::ThreadJoinError)? { - if exit_status.success() { - println!("{}'s instance exited normally.", username); - } else if let Some(exit_code) = exit_status.code() { - println!( - "{}'s instance exited abnormally. Exit code: {}", - username, exit_code, - ); - } else { - println!("{}'s instance was killed by a signal.", username); + if !quiet { + if exit_status.success() { + println!("{}'s instance exited normally.", username); + } else if let Some(exit_code) = exit_status.code() { + println!( + "{}'s instance exited abnormally. Exit code: {}", + username, exit_code, + ); + } else { + println!( + "{}'s instance was killed by a signal.", + username, + ); + } } children.remove(i); diff --git a/src/config.rs b/src/config.rs index c3b907d..b477215 100644 --- a/src/config.rs +++ b/src/config.rs @@ -44,6 +44,7 @@ pub fn get_config( config_path: Option<&str>, install_path: Option<&str>, cache_path: Option<&str>, + quiet: bool, ) -> Result<(Config, PathBuf), Error> { let inject_arg_values = |c| { let c = if let Some(ip) = install_path { @@ -96,6 +97,10 @@ pub fn get_config( } }; + if !quiet { + println!("Using {} as the config path...", config_path.display()); + } + match File::open(&config_path) { Ok(f) => serde_json::from_reader(f) .map_err(Error::DeserializeError) @@ -129,6 +134,10 @@ pub fn get_config( }, } } else { + if !quiet { + println!("Not using any config file..."); + } + Ok(( Config { install_dir: PathBuf::from(install_path.ok_or_else( diff --git a/src/login.rs b/src/login.rs index 5c7e5ab..cf79105 100644 --- a/src/login.rs +++ b/src/login.rs @@ -22,6 +22,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( config: &mut Config, config_path: P, client: &reqwest::Client, + quiet: bool, argv: A, ) -> Result, Error> { let (mut maybe_username, mut nosave) = (None, false); @@ -44,7 +45,9 @@ pub fn login<'a, P: AsRef, A: Iterator>( let (username, password) = if let Some(username) = maybe_username { if let Some(password) = config.accounts.get(username).and_then(|val| { if let serde_json::Value::String(p) = val { - println!("Using saved password..."); + if !quiet { + println!("Using saved password..."); + } Some(p) } else { @@ -72,7 +75,9 @@ pub fn login<'a, P: AsRef, A: Iterator>( let password = if let Some(password) = config.accounts.get(&username_buf).and_then(|val| { if let serde_json::Value::String(p) = val { - println!("Using saved password..."); + if !quiet { + println!("Using saved password..."); + } Some(p) } else { @@ -95,9 +100,11 @@ pub fn login<'a, P: AsRef, A: Iterator>( let mut params = BTreeMap::new(); params.insert("username", username); params.insert("password", password); - if let Some(response_json) = - handle_login_negotiation(client, post_to_login_api(client, ¶ms)?)? - { + if let Some(response_json) = handle_login_negotiation( + client, + quiet, + post_to_login_api(client, ¶ms)?, + )? { let username = if username_buf.is_empty() { username.to_owned() } else { @@ -112,7 +119,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( let old_acc = config.add_account(username.clone(), password); commit_config(config, config_path)?; - if old_acc.is_none() { + if !quiet && old_acc.is_none() { println!("New account saved in config!"); } } @@ -142,7 +149,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( "Expected \"gameserver\" key with String value", ))?; - launch(config, play_cookie, game_server) + launch(config, quiet, play_cookie, game_server) .map(|c| Some((username, c, Instant::now()))) } else { Ok(None) @@ -151,6 +158,7 @@ pub fn login<'a, P: AsRef, A: Iterator>( fn handle_login_negotiation( client: &reqwest::Client, + quiet: bool, mut response_json: serde_json::Value, ) -> Result, Error> { loop { @@ -172,11 +180,14 @@ fn handle_login_negotiation( match success { "true" => { - println!("Authentication success!"); + if !quiet { + println!("Authentication success!"); + } return Ok(Some(response_json)); }, - "delayed" => response_json = enqueue(client, &response_json)?, + "delayed" => + response_json = enqueue(client, quiet, &response_json)?, "partial" => response_json = if let Some(rj) = do_2fa(client, &response_json)? { @@ -260,6 +271,7 @@ fn do_2fa( fn enqueue( client: &reqwest::Client, + quiet: bool, response_json: &serde_json::Value, ) -> Result { let eta = response_json @@ -272,21 +284,23 @@ fn enqueue( .ok_or(Error::BadLoginResponse( "Expected \"eta\" key with a String or Number value", ))?; - println!( - "Waiting in queue... ETA: {}, position in line: {}", - eta, - response_json - .get("position") - .and_then(|val| match val { - serde_json::Value::String(s) => s.parse().ok(), - serde_json::Value::Number(n) => n.as_u64(), - _ => None, - }) - .ok_or(Error::BadLoginResponse( - "Expected \"position\" key with a String or unsigned Number \ - value", - ))?, - ); + if !quiet { + println!( + "Waiting in queue... ETA: {}, position in line: {}", + eta, + response_json + .get("position") + .and_then(|val| match val { + serde_json::Value::String(s) => s.parse().ok(), + serde_json::Value::Number(n) => n.as_u64(), + _ => None, + }) + .ok_or(Error::BadLoginResponse( + "Expected \"position\" key with a String or unsigned \ + Number value", + ))?, + ); + } let queue_token = response_json .get("queueToken") @@ -330,10 +344,13 @@ fn post_to_login_api( fn launch, T: AsRef>( config: &Config, + quiet: bool, play_cookie: S, game_server: T, ) -> Result { - println!("Launching the game..."); + if !quiet { + println!("Launching the game..."); + } process::Command::new("./TTREngine") .current_dir(&config.install_dir) diff --git a/src/main.rs b/src/main.rs index 63c03a4..01c66b8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ fn run() -> Result<(), Error> { .long("config") .aliases(&["conf", "configuration"]) .value_name("CONFIG_FILE") - .help("Configuration JSON file to use") + .help("Configuration JSON file to use.") .long_help(concat!( "Configuration JSON file to use. Defaults to \ \"$XDG_CONFIG_HOME\"/", @@ -56,7 +56,7 @@ fn run() -> Result<(), Error> { Arg::with_name("no-config") .long("no-config") .aliases(&["no-conf", "no-configuration"]) - .help("Don't read or write any config files") + .help("Don't read or write any config files.") .takes_value(false) .requires_all(&["install-dir", "cache-dir"]) .conflicts_with("config"), @@ -66,7 +66,7 @@ fn run() -> Result<(), Error> { .short("i") .long("install-dir") .value_name("INSTALL_DIR") - .help("Directory of TTR installation") + .help("Directory of TTR installation.") .long_help( "The directory of the TTR installation, which will be \ automatically created if it doesn't already exist. \ @@ -81,7 +81,7 @@ fn run() -> Result<(), Error> { .short("a") .long("cache-dir") .value_name("CACHE_DIR") - .help("Directory for caching game file downloads") + .help("Directory for caching game file downloads.") .long_help( "Directory for caching game file downloads, which will \ be created if it doesn't already exist. Overrides the \ @@ -96,7 +96,7 @@ fn run() -> Result<(), Error> { Arg::with_name("no-auto-update") .short("n") .long("no-auto-update") - .help("Suppress auto-update behavior") + .help("Suppress auto-update behavior.") .long_help( "Suppresses auto-updating, although you can still decide \ to update via the \"update\"/\"up\" command.", @@ -107,7 +107,7 @@ fn run() -> Result<(), Error> { Arg::with_name("username") .short("u") .long("username") - .help("Username(s) to immediately login with") + .help("Username(s) to immediately login with.") .long_help( "If this option is supplied, then after (possibly) \ auto-updating, the game will be launched with these \ @@ -125,7 +125,7 @@ fn run() -> Result<(), Error> { .long("detach") .help( "Exit after auto-updating (and possibly launching, if -u \ - is supplied)", + is supplied).", ) .long_help( "After auto-updating (unless -n was supplied), and after \ @@ -138,13 +138,26 @@ fn run() -> Result<(), Error> { ) .takes_value(false), ) + .arg( + Arg::with_name("quiet") + .short("q") + .long("quiet") + .help( + "Don't output anything unless necessary or explicitly \ + requested.", + ) + .takes_value(false), + ) .get_matches(); + let quiet = arg_matches.is_present("quiet"); + let (mut config, config_path) = config::get_config( arg_matches.is_present("no-config"), arg_matches.value_of("config"), arg_matches.value_of("install-dir"), arg_matches.value_of("cache-dir"), + quiet, )?; let client = ClientBuilder::new() @@ -152,15 +165,18 @@ fn run() -> Result<(), Error> { .map_err(Error::HttpClientCreateError)?; if !arg_matches.is_present("no-auto-update") { - update::update(&config, &client)?; + update::update(&config, &client, quiet)?; - println!(); + if !quiet { + println!(); + } } command::enter_command_mode( &mut config, &config_path, &client, + quiet, arg_matches.values_of("username"), arg_matches.is_present("detach"), ) diff --git a/src/update.rs b/src/update.rs index 23da5dd..e9d6c74 100644 --- a/src/update.rs +++ b/src/update.rs @@ -13,7 +13,11 @@ use std::{ pub const BUFFER_SIZE: usize = 0x20_00; pub const DEFAULT_ARCH: &str = "linux2"; -pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { +pub fn update( + config: &Config, + client: &reqwest::Client, + quiet: bool, +) -> Result<(), Error> { ensure_dir(&config.install_dir)?; ensure_dir(&config.cache_dir)?; @@ -27,12 +31,14 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { let mut install_dir = config.install_dir.clone(); for (i, (file_name, file_obj)) in manifest_map.iter().enumerate() { - println!( - "[{:2}/{}] Checking for updates for {}", - i + 1, - manifest_map.len(), - file_name, - ); + if !quiet { + println!( + "[{:2}/{}] Checking for updates for {}", + i + 1, + manifest_map.len(), + file_name, + ); + } let file_map = if let serde_json::Value::Object(m) = file_obj { m @@ -69,14 +75,19 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { } if !supported_by_this_arch { - println!( - " Not supported by this OS & architecture, skipping..." - ); + if !quiet { + println!( + " Not supported by this OS & architecture, \ + skipping..." + ); + } continue; } - println!(" Checking to see if file already exists..."); + if !quiet { + println!(" Checking to see if file already exists..."); + } install_dir.push(file_name); @@ -84,10 +95,12 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { Ok(f) => Some(f), Err(ioe) => match ioe.kind() { io::ErrorKind::NotFound => { - println!( - " File doesn't exist, downloading from \ - scratch..." - ); + if !quiet { + println!( + " File doesn't exist, downloading from \ + scratch..." + ); + } let mut file_buf = [0u8; BUFFER_SIZE]; let compressed_file_name = file_map @@ -138,6 +151,7 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { &mut file_buf, config, client, + quiet, compressed_file_name, file_name, &compressed_sha, @@ -156,6 +170,7 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { update_existing_file( config, client, + quiet, f, file_map, file_name, @@ -168,7 +183,9 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { #[cfg(unix)] { - println!("Making sure TTREngine is executable..."); + if !quiet { + println!("Making sure TTREngine is executable..."); + } install_dir.push("TTREngine"); let mut ttrengine_perms = fs::metadata(&install_dir) @@ -181,14 +198,20 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { .permissions(); let ttrengine_mode = ttrengine_perms.mode(); if (ttrengine_mode & 0o100) == 0 { - println!("TTREngine isn't executable, setting executable bit..."); + if !quiet { + println!( + "TTREngine isn't executable, setting executable bit..." + ); + } ttrengine_perms.set_mode(ttrengine_mode | 0o700); fs::set_permissions(&install_dir, ttrengine_perms) .map_err(Error::PermissionsSetError)?; - println!("TTREngine is now executable!"); - } else { + if !quiet { + println!("TTREngine is now executable!"); + } + } else if !quiet { println!("TTREngine is already executable!"); } } @@ -199,12 +222,15 @@ pub fn update(config: &Config, client: &reqwest::Client) -> Result<(), Error> { fn update_existing_file, P: AsRef>( config: &Config, client: &reqwest::Client, + quiet: bool, mut already_existing_file: File, file_map: &serde_json::Map, file_name: S, full_file_path: P, ) -> Result<(), Error> { - println!(" File exists, checking SHA1 hash..."); + if !quiet { + println!(" File exists, checking SHA1 hash..."); + } let mut file_buf = [0u8; BUFFER_SIZE]; let initial_sha = @@ -223,20 +249,24 @@ fn update_existing_file, P: AsRef>( })?; if initial_sha == manifest_sha { - println!(" SHA1 hash matches!"); + if !quiet { + println!(" SHA1 hash matches!"); + } return Ok(()); } - print!(" SHA1 hash mismatch:\n Local: "); - for b in initial_sha.iter() { - print!("{:02x}", b); - } - print!("\n Manifest: "); - for b in manifest_sha.iter() { - print!("{:02x}", b); + if !quiet { + print!(" SHA1 hash mismatch:\n Local: "); + for b in initial_sha.iter() { + print!("{:02x}", b); + } + print!("\n Manifest: "); + for b in manifest_sha.iter() { + print!("{:02x}", b); + } + println!("\n Checking for a patch..."); } - println!("\n Checking for a patch..."); let patches_map = file_map .get("patches") @@ -278,7 +308,9 @@ fn update_existing_file, P: AsRef>( ) })?; - println!(" Found a patch! Downloading it..."); + if !quiet { + println!(" Found a patch! Downloading it..."); + } let mut extracted_patch_file_name = String::with_capacity(patch_file_name.len() + ".extracted".len()); @@ -289,6 +321,7 @@ fn update_existing_file, P: AsRef>( &mut file_buf, config, client, + quiet, patch_file_name, &extracted_patch_file_name, &patch_map @@ -320,11 +353,15 @@ fn update_existing_file, P: AsRef>( 5, )?; - println!(" Applying patch..."); + if !quiet { + println!(" Applying patch..."); + } patch::patch_file(&extracted_patch_file_name, full_file_path)?; - println!(" File patched successfully!"); + if !quiet { + println!(" File patched successfully!"); + } did_patch = true; @@ -332,7 +369,9 @@ fn update_existing_file, P: AsRef>( } if !did_patch { - println!(" No patches found, downloading from scratch..."); + if !quiet { + println!(" No patches found, downloading from scratch..."); + } let compressed_file_name = file_map .get("dl") @@ -362,6 +401,7 @@ fn update_existing_file, P: AsRef>( &mut file_buf, config, client, + quiet, compressed_file_name, file_name, &compressed_sha, @@ -456,6 +496,7 @@ fn download_file, T: AsRef>( buf: &mut [u8], config: &Config, client: &reqwest::Client, + quiet: bool, compressed_file_name: S, decompressed_file_name: T, compressed_sha: &[u8; 20], @@ -490,12 +531,14 @@ fn download_file, T: AsRef>( }; for i in 1..=max_tries { - println!( - " Downloading {} [attempt {}/{}]", - compressed_file_name.as_ref(), - i, - max_tries, - ); + if !quiet { + println!( + " Downloading {} [attempt {}/{}]", + compressed_file_name.as_ref(), + i, + max_tries, + ); + } let mut dl_resp = client .get(&dl_uri) @@ -518,53 +561,67 @@ fn download_file, T: AsRef>( .map_err(Error::CopyIntoFileError)?; } - println!( - " Checking SHA1 hash of {}", - compressed_file_name.as_ref(), - ); + if !quiet { + println!( + " Checking SHA1 hash of {}", + compressed_file_name.as_ref(), + ); + } let dled_sha = sha_of_file_by_path(&compressed_file_path, buf)?; if &dled_sha != compressed_sha { - print!(" SHA1 hash mismatch:\n Local: "); - for b in dled_sha.iter() { - print!("{:02x}", b); - } - print!("\n Manifest: "); - for b in compressed_sha.iter() { - print!("{:02x}", b); + if !quiet { + print!(" SHA1 hash mismatch:\n Local: "); + for b in dled_sha.iter() { + print!("{:02x}", b); + } + print!("\n Manifest: "); + for b in compressed_sha.iter() { + print!("{:02x}", b); + } + println!("\n Re-downloading..."); } - println!("\n Re-downloading..."); continue; } - println!(" SHA1 hash matches! Extracting..."); + if !quiet { + println!(" SHA1 hash matches! Extracting..."); + } decompress_file(buf, &compressed_file_path, &decompressed_file_path)?; - println!(" Checking SHA1 hash of extracted file..."); + if !quiet { + println!(" Checking SHA1 hash of extracted file..."); + } let extracted_sha = sha_of_file_by_path(&decompressed_file_path, buf)?; if &extracted_sha != decompressed_sha { - print!(" SHA1 hash mismatch:\n Local: "); - for b in extracted_sha.iter() { - print!("{:02x}", b); - } - print!("\n Manifest: "); - for b in decompressed_sha.iter() { - print!("{:02x}", b); + if !quiet { + print!(" SHA1 hash mismatch:\n Local: "); + for b in extracted_sha.iter() { + print!("{:02x}", b); + } + print!("\n Manifest: "); + for b in decompressed_sha.iter() { + print!("{:02x}", b); + } + println!("\n Re-downloading..."); } - println!("\n Re-downloading..."); continue; } - println!(" SHA1 hash matches!"); + if !quiet { + println!(" SHA1 hash matches!"); + } break; } - println!(" Deleting compressed version..."); + if !quiet { + println!(" Deleting compressed version..."); + } let mut loc = if to_cache { config.cache_dir.clone() @@ -574,10 +631,12 @@ fn download_file, T: AsRef>( loc.push(compressed_file_name.as_ref()); fs::remove_file(&loc).map_err(Error::RemoveFileError)?; - println!( - " {} all done downloading!", - decompressed_file_name.as_ref(), - ); + if !quiet { + println!( + " {} all done downloading!", + decompressed_file_name.as_ref(), + ); + } Ok(()) }