Skip to content

Commit

Permalink
feat: add auto updater (#4)
Browse files Browse the repository at this point in the history
Closes #4
  • Loading branch information
The-Noah committed Jul 11, 2024
1 parent 81a0104 commit 2815a6f
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = ["Noah Dunbar <[email protected]>"]

[dependencies]
notify = "6.1.1"
reqwest = { version = "0.12.5", features = ["blocking"] }
reqwest = { version = "0.12.5", features = ["blocking", "json"] }
serde = { version = "1.0.203", features = ["derive"] }
serde-xml-rs = "0.6.0"

Expand Down
53 changes: 44 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::{fs, sync::mpsc};
use std::{fs, sync::mpsc, thread, time::Duration};

use notify::{Config, RecommendedWatcher, Watcher};

mod steam;
mod update_handler;

fn main() {
let args: Vec<String> = std::env::args().collect();
Expand All @@ -13,21 +14,33 @@ fn main() {
run();
} else {
hide_console_window();
watch();

if update_handler::update() {
let args = args.to_vec();
thread::spawn(move || {
std::process::Command::new(std::env::current_exe().unwrap()).args(args).status().unwrap();
});

// Ensure the new process has time to start
thread::sleep(Duration::from_secs(2));
} else {
watch();
}
}
} else {
match args[0].as_str() {
"help" | "--help" | "-h" => {
println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
println!("{} {}", env!("CARGO_PKG_NAME"), update_handler::get_current_version());
println!();
println!("Usage:");
println!(" {} [command]", env!("CARGO_PKG_NAME"));
println!();
println!("Commands:");
println!(" help Display this help message.");
println!(" debug Display debug information.");
println!(" run Run the program.");
println!(" watch Run the program in watch mode.");
println!(" help Display this help message.");
println!(" debug Display debug information.");
println!(" run Run the program.");
println!(" watch Run the program in watch mode.");
println!(" update Download any available updates.");
println!();
println!("Defaults:");
println!(" When executed inside a console, the run command is executed.");
Expand All @@ -36,8 +49,9 @@ fn main() {
"debug" => {
let steam_id = steam::get_id();
let steam_id3 = steam_id.map(steam::id_to_id3);
let latest_version = update_handler::get_latest_version();

println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
println!("{} {}", env!("CARGO_PKG_NAME"), update_handler::get_current_version());
println!();
println!("Steam ID: {}", if let Some(steam_id) = steam_id { steam_id.to_string() } else { "Not found".to_string() });
println!("Steam screenshots directory: {}", steam::get_screenshots_directory().display());
Expand All @@ -49,9 +63,21 @@ fn main() {
0
}
);
if let Ok(latest_version) = latest_version {
println!("Update available: {}", if update_handler::get_current_version() != latest_version { "Yes" } else { "No" });
if update_handler::get_current_version() != latest_version {
println!("Current version: v{}", env!("CARGO_PKG_VERSION"));
println!("Latest version: {}", latest_version);
}
} else {
print!("Failed to check for updates");
}
}
"run" => run(),
"watch" => watch(),
"update" => {
update_handler::update();
}
_ => println!("Invalid command."),
}
}
Expand Down Expand Up @@ -157,7 +183,16 @@ fn has_console_window() -> bool {

#[cfg(target_os = "windows")]
fn hide_console_window() {
use windows::Win32::System::Console::FreeConsole;
use windows::Win32::{
Foundation::HANDLE,
System::Console::{FreeConsole, SetStdHandle, STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
};

unsafe {
SetStdHandle(STD_INPUT_HANDLE, HANDLE(std::ptr::null_mut())).unwrap();
SetStdHandle(STD_OUTPUT_HANDLE, HANDLE(std::ptr::null_mut())).unwrap();
SetStdHandle(STD_ERROR_HANDLE, HANDLE(std::ptr::null_mut())).unwrap();
}

unsafe { FreeConsole().unwrap() };
}
Expand Down
86 changes: 86 additions & 0 deletions src/update_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use reqwest::{header::USER_AGENT, Method};
use serde::Deserialize;

#[derive(Debug, Deserialize, PartialEq)]
struct Release {
tag_name: String,
assets: Vec<Asset>,
}

#[derive(Debug, Deserialize, PartialEq)]
struct Asset {
name: String,
browser_download_url: String,
}

pub fn get_current_version() -> String {
format!("v{}", env!("CARGO_PKG_VERSION"))
}

pub fn get_latest_version() -> Result<String, reqwest::Error> {
let releases = get_releases()?;

Ok(releases[0].tag_name.clone())
}

#[cfg(not(debug_assertions))]
pub fn update() -> bool {
use std::{
fs::{self, File},
io::Write,
};

fn get_latest_version_executable_url() -> Result<String, reqwest::Error> {
let releases = get_releases()?;

let asset = releases[0].assets.iter().find(|asset| asset.name == "steam-screenshot-organizer.exe").unwrap();

Ok(asset.browser_download_url.clone())
}

let current_version = get_current_version();
let latest_version = get_latest_version().unwrap();

if current_version == latest_version {
println!("Already up to date");
return false;
}

let executable_url = get_latest_version_executable_url().unwrap();
let executable = reqwest::blocking::get(&executable_url).unwrap().bytes().unwrap();

let old_exe_path = std::env::current_dir()
.unwrap()
.join(format!("{}.bak", std::env::current_exe().unwrap().file_stem().unwrap().to_str().unwrap()));

if old_exe_path.exists() {
fs::remove_file(&old_exe_path).expect("Failed to delete old version");
}

fs::rename(std::env::current_exe().unwrap(), &old_exe_path).expect("Failed to rename current version");

let mut file = File::create(std::env::current_exe().unwrap()).unwrap();
file.write_all(&executable).unwrap();

if old_exe_path.exists() {
fs::remove_file(&old_exe_path).expect("Failed to delete old version");
}

println!("Updated to version {}", latest_version);

true
}

#[cfg(debug_assertions)]
pub fn update() -> bool {
false
}

fn get_releases() -> Result<Vec<Release>, reqwest::Error> {
let client = reqwest::blocking::Client::new();
client
.request(Method::GET, "https://api.github.com/repos/The-Noah/steam-screenshot-organizer/releases")
.header(USER_AGENT, "steam-screenshot-manager")
.send()?
.json::<Vec<Release>>()
}

0 comments on commit 2815a6f

Please sign in to comment.