From 3bd05ba8dd1adc89f2f6144d7d69d26043e7a7bf Mon Sep 17 00:00:00 2001 From: Ian Mason Date: Sat, 28 Jan 2023 23:29:20 -0800 Subject: [PATCH] Bump to version 4.0.0 Switch from druid to egui Support deletion of builds Auto-updater! Add a test --- Cargo.toml | 8 +- src/among_us_launcher_widget.rs | 205 ------------- src/among_us_version.rs | 45 ++- src/main.rs | 497 ++++++++++++++++++++++---------- src/semver.rs | 2 +- 5 files changed, 391 insertions(+), 366 deletions(-) delete mode 100644 src/among_us_launcher_widget.rs diff --git a/Cargo.toml b/Cargo.toml index 11d171b..cc788ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "town-of-us-updater" -version = "3.0.0" +version = "4.0.0" edition = "2021" build = "src/build.rs" @@ -12,11 +12,13 @@ regex = "1.5" fs_extra = "1.2.0" dirs = "4.0.0" reqwest = {version = "0.11.11", features = ["blocking"]} -iui = "0.3.0" serde_json = "1.0" +md-5 = "0.10.5" tokio = {version="1", features=["full"]} -druid = "0.7.0" registry = "1" +egui = "0.20.1" +eframe = "0.20.1" +rfd = "0.10" [build-dependencies] embed-resource = "1.6" diff --git a/src/among_us_launcher_widget.rs b/src/among_us_launcher_widget.rs deleted file mode 100644 index 7711230..0000000 --- a/src/among_us_launcher_widget.rs +++ /dev/null @@ -1,205 +0,0 @@ -use crate::AmongUsVersion; -use crate::AppData; -use druid::{ - widget::*, BoxConstraints, Color, Env, Event, EventCtx, FileDialogOptions, LayoutCtx, - LifeCycle, LifeCycleCtx, PaintCtx, Selector, Size, UpdateCtx, WidgetExt, WidgetPod, -}; -use std::{fs, io, path::PathBuf}; - -pub const ATTEMPT_INSTALL: Selector = Selector::new("town-of-us-updater.attempt_install"); -pub const DETERMINE_AMONG_US_VERSION: Selector = - Selector::new("town-of-us-updater.determine_among_us_version"); -pub const COPY_FOLDER: Selector = Selector::new("town-of-us-updater.copy_folder"); - -pub struct AmongUsLauncherWidget { - pub root: WidgetPod>, -} - -impl AmongUsLauncherWidget { - pub fn build_widget(&mut self, data: &AppData) { - let mut flex: Flex = Flex::column(); - - match &data.app_state { - crate::GlobalAppState::Initializing(_a) => { - let label = Label::new("Initializing...").with_text_size(24.0).center(); - flex.add_flex_child(label, 1.0); - self.root = WidgetPod::new(flex); - return; - } - _ => {} - } - // Find existing installs, make buttons for them - let install_iter = fs::read_dir(data.installs_path.clone()); - - if let Ok(iter) = install_iter { - let mut collection: Vec> = iter.collect(); - collection.reverse(); - - if collection.is_empty() { - if data.among_us_path.is_empty() { - // We did not find an install path, let's add a button to prompt the user - // to find their install path - let open_button = Button::new("Locate Among Us") - .fix_height(45.0) - .on_click(move |ctx, _: &mut AppData, _| { - ctx.submit_command( - druid::commands::SHOW_OPEN_PANEL.with(FileDialogOptions::new()), - ); - }) - .center(); - flex.add_flex_child(open_button, 1.0); - } else { - let label: druid::widget::Label = - druid::widget::Label::new("We found Among Us but you have no installs"); - flex.add_flex_child(label, 1.0); - } - } else { - // Iterate first to find labels: - - let mut flexbox_array: Vec> = Vec::new(); - let mut auv_array: Vec = Vec::new(); - - for i in &collection { - let existing_ver_smash = i.as_ref().unwrap().file_name(); - let mut ver_smash_split = existing_ver_smash.to_str().unwrap().split('-'); - let among_us_version = AmongUsVersion::from(ver_smash_split.next().unwrap()); - if !auv_array.contains(&among_us_version) { - auv_array.push(among_us_version); - } - } - - auv_array.sort(); - - for among_us_version in &auv_array { - println!("{}", among_us_version); - let label_text = format!("Among Us {}", among_us_version); - let flex: druid::widget::Flex = druid::widget::Flex::column() - .with_flex_child( - druid::widget::Label::new(label_text.as_str()).with_text_size(24.0), - 1.0, - ) - .with_default_spacer(); - flexbox_array.push(flex); - } - - println!("Installs list:"); - - for i in collection { - let existing_ver_smash = i.unwrap().file_name(); - let mut ver_smash_split = existing_ver_smash.to_str().unwrap().split('-'); - let mut blessed_split = data.blessed_version.as_str().split('-'); - let blessed_version = AmongUsVersion::from(blessed_split.next().unwrap()); - let among_us_version = AmongUsVersion::from(ver_smash_split.next().unwrap()); - let tou_version = ver_smash_split.next().unwrap(); - let blessed_tou_version = blessed_split.next().unwrap(); - let button_string: String = format!("Town of Us {}", tou_version); - - for (index, j) in auv_array.iter().enumerate() { - if j == &among_us_version { - let mut clone: PathBuf = PathBuf::from(data.installs_path.clone()); - clone.push(existing_ver_smash.clone()); - - let mut button_label: Label = - Label::new(button_string.as_str()).with_text_size(24.0); - - if j == &blessed_version && tou_version == blessed_tou_version { - button_label.set_text_color(Color::GREEN); - } - - let mut button_row: Flex = Flex::row(); - - let fybutton = druid::widget::Button::from_label(button_label) - .fix_height(45.0) - .center() - .on_click(move |_, _: &mut AppData, _| { - crate::attempt_run_among_us(&clone); - // crate::launch_better_crewlink().unwrap(); - }); - - button_row.add_flex_child(fybutton, 1.0); - - // TODO: Uncomment - // let delete_button = druid::widget::Button::new("Delete") - // .fix_height(45.0) - // .on_click(move |_, _: &mut AppData, _| {}); - - // button_row.add_flex_child(delete_button, 1.0); - - flexbox_array - .get_mut(index) - .unwrap() - .add_flex_child(button_row, 1.0); - - println!("- {}", existing_ver_smash.clone().to_str().unwrap()); - } - } - } - - flexbox_array.reverse(); - - for i in flexbox_array { - flex.add_flex_child(i, 1.0); - } - } - } - self.root = WidgetPod::new(flex); - } -} - -impl Widget for AmongUsLauncherWidget { - fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut AppData, env: &Env) { - // println!("{:?}", event); - // println!("{:?}", data); - match event { - Event::MouseDown(_a) => { - // println!("Mouse Down!"); - self.root.event(ctx, event, data, env); - } - Event::WindowConnected => { - self.build_widget(data); - ctx.children_changed(); - } - Event::KeyDown(evt) => { - if evt.code == druid::Code::F5 { - ctx.submit_command(ATTEMPT_INSTALL); - } - } - _ => { - self.root.event(ctx, event, data, env); - } - } - } - fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &AppData, env: &Env) { - self.root.lifecycle(ctx, event, data, env); - // println!("Lifecycle!") - } - fn update(&mut self, ctx: &mut UpdateCtx, old_data: &AppData, data: &AppData, env: &Env) { - self.root.update(ctx, data, env); - println!("{:?}", data); - if old_data.among_us_path.is_empty() && !data.among_us_path.is_empty() { - ctx.submit_command(DETERMINE_AMONG_US_VERSION); - // println!("Detect Stuff"); - } else if old_data.among_us_version != data.among_us_version { - ctx.submit_command(ATTEMPT_INSTALL); - } - // println!("Update!"); - self.build_widget(data); - ctx.children_changed(); - } - fn layout( - &mut self, - ctx: &mut LayoutCtx, - bc: &BoxConstraints, - data: &AppData, - env: &Env, - ) -> Size { - self.root.layout(ctx, bc, data, env); - // println!("Layout!"); - bc.constrain((400.0, 400.0)) - } - - fn paint(&mut self, ctx: &mut PaintCtx, data: &AppData, env: &Env) { - self.root.paint(ctx, data, env); - // println!("Paint!"); - } -} diff --git a/src/among_us_version.rs b/src/among_us_version.rs index 8ebb5f2..99378c4 100644 --- a/src/among_us_version.rs +++ b/src/among_us_version.rs @@ -1,13 +1,18 @@ -use druid::Data; use std::fmt; -#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug, Data)] +#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)] pub struct AmongUsVersion { year: i32, month: i32, day: i32, } +impl AmongUsVersion { + pub fn as_american_string(&self) -> String { + format!("{}-{}-{}", self.month, self.day, self.year) + } +} + impl fmt::Display for AmongUsVersion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}.{}.{}", self.year, self.month, self.day) @@ -48,3 +53,39 @@ impl From<(i32, i32, i32)> for AmongUsVersion { } } } + +#[test] +fn ordering_test() { + let mut vec = Vec::new(); + vec.push(AmongUsVersion { + year: 2019, + month: 1, + day: 25, + }); + + vec.push(AmongUsVersion { + year: 2022, + month: 12, + day: 25, + }); + + vec.push(AmongUsVersion { + year: 2022, + month: 12, + day: 14, + }); + + vec.push(AmongUsVersion { + year: 2022, + month: 12, + day: 8, + }); + vec.sort(); + assert_eq!(vec[0].year, 2019); + assert_eq!(vec[1].year, 2022); + assert_eq!(vec[1].day, 8); + assert_eq!(vec[2].year, 2022); + assert_eq!(vec[2].day, 14); + assert_eq!(vec[3].year, 2022); + assert_eq!(vec[3].day, 25); +} diff --git a/src/main.rs b/src/main.rs index 79a78dd..85a04f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,15 @@ // Modules -mod among_us_launcher_widget; mod among_us_version; mod semver; // Uses -use among_us_launcher_widget::*; use among_us_version::*; +use md5::{Digest, Md5}; use semver::*; use std::{ - fs, + fs, io, path::{Path, PathBuf}, process, str, }; @@ -23,14 +22,12 @@ use regex::Regex; use registry::Hive; // GUI stuff -use druid::{ - commands, widget::*, AppDelegate, AppLauncher, Data, DelegateCtx, Env, Handled, Target, - WidgetPod, WindowDesc, WindowId, -}; + +use eframe::egui; use reqwest::StatusCode; -#[derive(PartialEq, Eq, Data, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum InitializingState { StartingGUI, DeterminingVersion, @@ -41,7 +38,7 @@ pub enum InitializingState { CopyingZipIn, } -#[derive(PartialEq, Eq, Data, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum GlobalAppState { Initializing(InitializingState), Initialized, @@ -49,9 +46,7 @@ pub enum GlobalAppState { Playing, } -struct Delegate; - -#[derive(Data, Clone, Debug)] +#[derive(Clone, Debug)] pub struct AppData { pub among_us_path: String, pub installs_path: String, @@ -61,6 +56,149 @@ pub struct AppData { pub data_path: String, pub app_state: GlobalAppState, pub blessed_version: String, + pub update_installs_list: bool, + pub installs_last_update_time: std::time::Instant, + pub installs_list: Vec, +} + +impl Default for AppData { + fn default() -> AppData { + AppData { + among_us_path: String::new(), + installs_path: String::new(), + version: SemVer { + major: 0, + minor: 0, + patch: 0, + }, + initialized: false, + among_us_version: AmongUsVersion::default(), + data_path: String::new(), + app_state: GlobalAppState::Initialized, + blessed_version: String::new(), + update_installs_list: true, + installs_last_update_time: std::time::Instant::now(), + installs_list: Vec::new(), + } + } +} + +impl AppData { + fn detect_installs(&mut self) { + let install_iter = fs::read_dir(self.installs_path.clone()); + if let Ok(iter) = install_iter { + self.installs_list = iter + .map(|elem| PathBuf::from(elem.unwrap().file_name())) + .collect(); + } else { + self.installs_list.clear(); + } + self.installs_last_update_time = std::time::Instant::now(); + } + + fn draw_layout(&mut self, ui: &mut egui::Ui) { + let now = std::time::Instant::now(); + if now.duration_since(self.installs_last_update_time) > std::time::Duration::from_secs(10) { + self.detect_installs(); + } + + let mut collection = self.installs_list.clone(); + + if collection.is_empty() { + if ui.button("Locate your Among Us Directory").clicked() { + if let Some(mut path) = rfd::FileDialog::new().pick_file() { + path.pop(); + self.among_us_path = path.display().to_string(); + self.on_path_added(); + } + } + return; + } + + collection.reverse(); + let mut auv_array: Vec = Vec::new(); + + for i in &collection { + let existing_ver_smash = i; + let mut ver_smash_split = existing_ver_smash.to_str().unwrap().split('-'); + let among_us_version = AmongUsVersion::from(ver_smash_split.next().unwrap()); + if !auv_array.contains(&among_us_version) { + auv_array.push(among_us_version); + } + } + + auv_array.sort(); + auv_array.reverse(); + + ui.separator(); + for i in &auv_array { + ui.label( + egui::RichText::new(format!("Among Us {}", i.as_american_string())).size(35.0), + ); + for j in &collection { + let existing_ver_smash = j; + let mut ver_smash_split = existing_ver_smash.to_str().unwrap().split('-'); + let mut blessed_split = self.blessed_version.as_str().split('-'); + let among_us_version = AmongUsVersion::from(ver_smash_split.next().unwrap()); + let tou_version = ver_smash_split.next().unwrap(); + let blessed_version = AmongUsVersion::from(blessed_split.next().unwrap()); + let blessed_tou_version = blessed_split.next().unwrap(); + let button_string: String = format!("Town of Us {}", tou_version); + if i == &among_us_version { + let mut clone: PathBuf = PathBuf::from(self.installs_path.clone()); + clone.push(existing_ver_smash.clone()); + ui.horizontal(|ui| { + if i == &blessed_version && tou_version == blessed_tou_version { + let button_text = egui::RichText::new(button_string.clone()) + .size(25.0) + .color(egui::Color32::GREEN); + if ui.button(button_text).clicked() { + crate::attempt_run_among_us(&clone); + } + } else { + let button_text = egui::RichText::new(button_string.clone()).size(25.0); + if ui.button(button_text).clicked() { + crate::attempt_run_among_us(&clone); + } + } + + if !self.initialized { + ui.set_visible(false); + } + + let button_text = egui::RichText::new("DELETE") + .size(25.0) + .color(egui::Color32::RED); + + if ui.button(button_text).clicked() { + if i != &blessed_version || tou_version != blessed_tou_version { + crate::attempt_delete_among_us(&clone); + self.update_installs_list = true; + } + } + + ui.set_visible(true); + }); + } + } + ui.separator(); + } + } +} + +impl eframe::App for AppData { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + if self.update_installs_list { + self.detect_installs(); + self.update_installs_list = false; + } + egui::TopBottomPanel::bottom("bottom_panel").show(ctx, |ui| { + ui.checkbox(&mut self.initialized, "DELETE MODE"); + }); + egui::CentralPanel::default().show(ctx, |ui| { + self.draw_layout(ui); + }); + } } static AMONG_US_APPID: &str = "945360"; @@ -75,6 +213,10 @@ fn attempt_run_among_us(install_path: &Path) { .unwrap(); } +fn attempt_delete_among_us(install_path: &Path) { + fs::remove_dir_all(install_path).unwrap(); +} + fn unmod_among_us_folder(folder_path: &Path) { println!("Unmodding Among Us..."); let doorstop_path: PathBuf = [folder_path.to_str().unwrap(), "doorstop_config.ini"] @@ -141,130 +283,91 @@ async fn _get_latest_updater_version() -> Result<(String, String), reqwest::Erro Ok((String::from("no"), String::from("yes"))) } -impl AppDelegate for Delegate { - fn window_added( - &mut self, - _id: WindowId, - data: &mut AppData, - _env: &Env, - ctx: &mut DelegateCtx, - ) { - if !data.among_us_path.is_empty() { - ctx.submit_command(DETERMINE_AMONG_US_VERSION); +impl AppData { + fn on_path_added(&mut self) { + if let Some(among_us_version) = + determine_among_us_version(String::from(self.among_us_path.clone())) + { + self.among_us_version = among_us_version.clone(); + println!("AmongUsVersion: {}", among_us_version); } - } - fn command( - &mut self, - _ctx: &mut DelegateCtx, - _target: Target, - cmd: &druid::Command, - data: &mut AppData, - _env: &Env, - ) -> Handled { - // println!("Command!"); - if let Some(file_info) = cmd.get(commands::OPEN_FILE) { - let among_us_folder = file_info.path(); - let mut buf = among_us_folder.to_path_buf(); - buf.pop(); - data.among_us_path = String::from(buf.to_str().unwrap()); - // Pop the selected file off the end of the path - // among_us_folder.pop(); - println!("{}", buf.to_str().unwrap()); - // println!("Handled!"); - //Application::global().quit(); + self.app_state = GlobalAppState::Initializing(InitializingState::DeterminingVersion); + let ver_url: (String, String, bool) = + determine_town_of_us_url(self.among_us_version.to_string().clone()).unwrap(); - return Handled::Yes; - } else if let Some(_a) = cmd.get(among_us_launcher_widget::DETERMINE_AMONG_US_VERSION) { - if let Some(among_us_version) = - determine_among_us_version(String::from(data.among_us_path.clone())) - { - data.among_us_version = among_us_version.clone(); - println!("AmongUsVersion: {}", among_us_version); + let version_smash = format!("{}-{}", self.among_us_version, ver_url.0.clone()); + let new_installed_path: PathBuf = [self.installs_path.as_str(), version_smash.as_str()] + .iter() + .collect(); + + if !Path::exists(&new_installed_path) { + println!("Copying Among Us to cache location..."); + copy_folder_to_target(self.among_us_path.clone(), self.installs_path.clone()); + + let among_us_path: PathBuf = [self.installs_path.as_str(), "Among Us"].iter().collect(); + + if !among_us_path.to_str().unwrap().contains("Among Us") { + process::exit(0); } - } else if let Some(_a) = cmd.get(among_us_launcher_widget::ATTEMPT_INSTALL) { - data.app_state = GlobalAppState::Initializing(InitializingState::DeterminingVersion); - let ver_url: (String, String, bool) = - determine_town_of_us_url(data.among_us_version.to_string().clone()).unwrap(); - let version_smash = format!("{}-{}", data.among_us_version, ver_url.0.clone()); - let new_installed_path: PathBuf = [data.installs_path.as_str(), version_smash.as_str()] + // Un-mod whatever we found if it's modded + unmod_among_us_folder(&among_us_path); + + println!( + "Renaming {} to {}", + among_us_path.to_str().unwrap(), + new_installed_path.to_str().unwrap() + ); + + let mut perms = fs::metadata(among_us_path.clone()).unwrap().permissions(); + perms.set_readonly(false); + fs::set_permissions(among_us_path.clone(), perms).unwrap(); + + fs::rename(among_us_path, new_installed_path.clone()).unwrap(); + let mut download_path: PathBuf = [self.data_path.as_str()].iter().collect(); + let downloaded_filename: &str = ver_url.1.rsplit('/').next().unwrap(); + download_path.push(downloaded_filename); + + if !download_path.exists() { + // println!("{:?}", download_path); + println!( + "Downloading Town of Us... Please be patient! [{}]", + ver_url.1.clone() + ); + let client = reqwest::blocking::Client::builder() + .timeout(None) + .build() + .unwrap(); + let zip_request = client.get(ver_url.1.clone()).build().unwrap(); + let zip = client.execute(zip_request).unwrap().bytes().unwrap(); + fs::write(download_path.clone(), zip).unwrap(); + } + + let opened_zip = fs::File::open(download_path.clone()).unwrap(); + println!("Extracting mod zip file..."); + let mut archive = zip::ZipArchive::new(opened_zip).unwrap(); + archive.extract(self.data_path.clone()).unwrap(); + + fs::remove_file(download_path).unwrap(); + + let mut root_folder_path = String::new(); + for i in archive.file_names() { + root_folder_path = String::from(i.split('/').next().unwrap()); + break; + } + let extracted_path: PathBuf = [self.data_path.as_str(), root_folder_path.as_str(), "."] .iter() .collect(); - - if !Path::exists(&new_installed_path) { - println!("Copying Among Us to cache location..."); - copy_folder_to_target(data.among_us_path.clone(), data.installs_path.clone()); - - let among_us_path: PathBuf = - [data.installs_path.as_str(), "Among Us"].iter().collect(); - - if !among_us_path.to_str().unwrap().contains("Among Us") { - process::exit(0); - } - - // Un-mod whatever we found if it's modded - unmod_among_us_folder(&among_us_path); - - println!( - "Renaming {} to {}", - among_us_path.to_str().unwrap(), - new_installed_path.to_str().unwrap() - ); - - let mut perms = fs::metadata(among_us_path.clone()).unwrap().permissions(); - perms.set_readonly(false); - fs::set_permissions(among_us_path.clone(), perms).unwrap(); - - fs::rename(among_us_path, new_installed_path.clone()).unwrap(); - let mut download_path: PathBuf = [data.data_path.as_str()].iter().collect(); - let downloaded_filename: &str = ver_url.1.rsplit('/').next().unwrap(); - download_path.push(downloaded_filename); - - if !download_path.exists() { - // println!("{:?}", download_path); - println!( - "Downloading Town of Us... Please be patient! [{}]", - ver_url.1.clone() - ); - let client = reqwest::blocking::Client::builder() - .timeout(None) - .build() - .unwrap(); - let zip_request = client.get(ver_url.1.clone()).build().unwrap(); - let zip = client.execute(zip_request).unwrap().bytes().unwrap(); - fs::write(download_path.clone(), zip).unwrap(); - } - - let opened_zip = fs::File::open(download_path.clone()).unwrap(); - println!("Extracting mod zip file..."); - let mut archive = zip::ZipArchive::new(opened_zip).unwrap(); - archive.extract(data.data_path.clone()).unwrap(); - - fs::remove_file(download_path).unwrap(); - - let mut root_folder_path = String::new(); - for i in archive.file_names() { - root_folder_path = String::from(i.split('/').next().unwrap()); - break; - } - let extracted_path: PathBuf = - [data.data_path.as_str(), root_folder_path.as_str(), "."] - .iter() - .collect(); - println!("{}", extracted_path.to_str().unwrap()); - copy_folder_contents_to_target( - extracted_path.to_str().unwrap(), - new_installed_path.to_str().unwrap(), - ); - } - data.initialized = !data.initialized; - data.app_state = GlobalAppState::Initialized; - - return Handled::Yes; + println!("{}", extracted_path.to_str().unwrap()); + copy_folder_contents_to_target( + extracted_path.to_str().unwrap(), + new_installed_path.to_str().unwrap(), + ); } - - Handled::No + self.initialized = !self.initialized; + self.app_state = GlobalAppState::Initialized; + self.update_installs_list = true; } } @@ -281,9 +384,6 @@ fn main() { println!("Blessed Version: {}", blessed_version); - // println!("Updater Version: {}", version); - // get_latest_updater_version().await.unwrap(); - // CREATE PROGRAM DIRECTORY let mut data_path = dirs::data_dir().unwrap(); data_path.push("town-of-us-updater"); @@ -293,6 +393,102 @@ fn main() { installs_path.push("installs"); fs::create_dir(installs_path.clone()).unwrap_or(()); + let mut true_env = false; + for argument in std::env::args() { + if argument == "true" { + true_env = true; + } + } + + if !true_env { + let mut exe_path = data_path.clone(); + if cfg!(windows) { + exe_path.push("town-of-us-updater.exe"); + } else if cfg!(unix) { + exe_path.push("town-of-us-updater"); + } + + let mut updated_exe_hash = String::new(); + + if let Ok(response) = reqwest::blocking::get("https://tou.dormedas.com/release/hash") { + if let Ok(text) = response.text() { + updated_exe_hash = text; + } + } else { + println!("Failed to get hash. Running local version.") + } + + // If we heard back, try to update, otherwise run normally + if !updated_exe_hash.is_empty() { + let mut our_hash = String::new(); + let mut try_continue = false; + match fs::read(&exe_path) { + Ok(bytes) => { + let mut hasher = Md5::new(); + hasher.update(bytes); + let finalized = hasher.finalize(); + our_hash = format!("{finalized:x}"); + try_continue = true; + } + Err(e) => match e.kind() { + io::ErrorKind::NotFound => try_continue = true, + _ => { + println!("{}", e.to_string()); + } + }, + } + + if !our_hash.is_empty() { + println!("{} vs {}", our_hash, updated_exe_hash); + } else { + println!("Local executable didn't exist"); + } + + if try_continue { + if our_hash != updated_exe_hash { + println!("Newer version detected, downloading..."); + let client = reqwest::blocking::Client::builder() + .timeout(None) + .build() + .unwrap(); + let updated_exe_data_req = client + .get("https://tou.dormedas.com/release") + .build() + .unwrap(); + + let updated_exe_data = client.execute(updated_exe_data_req); + + if let Ok(response) = updated_exe_data { + if response.status() == StatusCode::OK { + if let Ok(file_bytes) = response.bytes() { + match fs::write(&exe_path, file_bytes) { + Ok(_) => { + println!("Successfully updated executable"); + } + _ => { + println!("Failed to update executable"); + } + }; + } + } + } + } + + // We can fail to download a good binary, just continue with our current executable + if exe_path.exists() { + process::Command::new(&exe_path) + .arg("true") + .stdout(process::Stdio::null()) + .stderr(process::Stdio::null()) + .spawn() + .unwrap(); + + process::exit(0); + } + } + } + } + let version = env!("CARGO_PKG_VERSION"); let mut among_us_folder = PathBuf::new(); @@ -314,7 +510,7 @@ fn main() { } } - let app_data: AppData = AppData { + let mut app_data: AppData = AppData { among_us_path: String::from(among_us_folder.clone().to_str().unwrap()), installs_path: String::from(installs_path.clone().to_str().unwrap()), version: SemVer::from(version), @@ -323,10 +519,11 @@ fn main() { data_path: String::from(data_path.clone().to_str().unwrap()), app_state: GlobalAppState::Initializing(InitializingState::StartingGUI), blessed_version, + update_installs_list: true, + installs_last_update_time: std::time::Instant::now(), + installs_list: Vec::new(), }; - let mut root_column: druid::widget::Flex = druid::widget::Flex::column(); - // DETERMINE AMONG US VERSION if let Some(among_us_folder_str) = among_us_folder.to_str() { @@ -337,34 +534,24 @@ fn main() { } } - // println!("Checking for updater updates..."); - // let vals: (String, String) = version_check_thread_handle.join().unwrap(); - // TODO: Auto launch latest sanctioned if the user has a setting like that // Auto launch latest experimental as well println!("Launching main window..."); - let _main_menu: druid::MenuDesc = - druid::MenuDesc::empty().append(druid::MenuItem::new( - druid::LocalizedString::new("File"), - druid::Command::new(druid::Selector::new("test"), 0, Target::Auto), - )); - - let widget: AmongUsLauncherWidget = AmongUsLauncherWidget { - root: WidgetPod::new(Flex::column()), - }; - - root_column.add_flex_child(widget, 1.0); launch_better_crewlink().unwrap_or(()); - let main_window = WindowDesc::new(|| root_column) - .title(title_string) - // .menu(main_menu) - .window_size((400.0, 400.0)); - let app_launcher = AppLauncher::with_window(main_window).delegate(Delegate {}); - let _external_handler = app_launcher.get_external_handle(); - app_launcher.launch(app_data).unwrap(); + // let app_launcher = AppLauncher::with_window(main_window).delegate(Delegate {}); + // app_launcher.launch(app_data).unwrap(); + let mut native_options = eframe::NativeOptions::default(); + native_options.min_window_size = Some(egui::vec2(425.0, 400.0)); + native_options.initial_window_size = Some(egui::vec2(425.0, 400.0)); + app_data.detect_installs(); // Initial check since we only update every 10s + eframe::run_native( + title_string.as_str(), + native_options, + Box::new(|_cc| Box::new(app_data)), + ); } fn launch_better_crewlink() -> std::result::Result<(), String> { diff --git a/src/semver.rs b/src/semver.rs index eedbd9f..b168520 100644 --- a/src/semver.rs +++ b/src/semver.rs @@ -5,7 +5,7 @@ // Uses use std::fmt; -#[derive(druid::Data, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] +#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] pub struct SemVer { pub major: i32, pub minor: i32,