2023-06-10 09:33:16 +02:00
|
|
|
mod http;
|
2023-06-10 12:38:21 +02:00
|
|
|
use std::{fs, path::PathBuf};
|
|
|
|
|
|
|
|
#[derive(serde::Deserialize, serde::Serialize)]
|
|
|
|
struct CdnFile {
|
|
|
|
name: String,
|
|
|
|
size: u32,
|
|
|
|
hash: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Game<'a> {
|
|
|
|
engine: &'a str,
|
|
|
|
client: &'a str,
|
|
|
|
references: &'a [&'a str],
|
|
|
|
}
|
2023-06-10 09:33:16 +02:00
|
|
|
|
|
|
|
const MASTER: &str = "https://master.alterware.dev";
|
2023-06-11 16:16:29 +02:00
|
|
|
const GAMES: [Game; 3] = [
|
2023-06-10 12:38:21 +02:00
|
|
|
Game {
|
|
|
|
engine: "iw4",
|
|
|
|
client: "iw4-sp",
|
|
|
|
references: &["iw4sp.exe", "iw4mp.exe"],
|
|
|
|
},
|
|
|
|
Game {
|
|
|
|
engine: "iw5",
|
|
|
|
client: "iw5-mod",
|
|
|
|
references: &["iw5sp.exe", "iw5mp.exe", "iw5mp_server.exe"],
|
|
|
|
},
|
2023-06-11 16:16:29 +02:00
|
|
|
Game {
|
|
|
|
engine: "iw6",
|
|
|
|
client: "iw6-mod",
|
|
|
|
references: &["iw6sp64_ship.exe", "iw6mp64_ship.exe"],
|
|
|
|
},
|
2023-06-10 12:38:21 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
fn file_get_sha1(path: &PathBuf) -> String {
|
|
|
|
let mut sha1 = sha1_smol::Sha1::new();
|
|
|
|
sha1.update(&fs::read(path).unwrap());
|
|
|
|
sha1.digest().to_string()
|
|
|
|
}
|
2023-06-10 09:33:16 +02:00
|
|
|
|
2023-06-11 16:16:29 +02:00
|
|
|
fn update(game: &Game) {
|
2023-06-10 12:38:21 +02:00
|
|
|
let cdn_info: Vec<CdnFile> = serde_json::from_str(&http::get_body_string(
|
2023-06-10 13:31:48 +02:00
|
|
|
format!(
|
|
|
|
"{}/files.json?{}",
|
|
|
|
MASTER,
|
|
|
|
rand::Rng::gen_range(&mut rand::thread_rng(), 0..1000)
|
|
|
|
)
|
|
|
|
.as_str(),
|
2023-06-10 12:38:21 +02:00
|
|
|
))
|
|
|
|
.unwrap();
|
|
|
|
|
2023-06-11 16:16:29 +02:00
|
|
|
let mut files_to_update: Vec<CdnFile> = Vec::new();
|
2023-06-10 12:38:21 +02:00
|
|
|
for file in cdn_info {
|
2023-06-11 16:16:29 +02:00
|
|
|
if file.name.starts_with(game.engine) {
|
|
|
|
files_to_update.push(file);
|
2023-06-10 12:38:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-11 16:16:29 +02:00
|
|
|
for file in files_to_update {
|
|
|
|
let file_path = PathBuf::from(&file.name.replace(&format!("{}/", game.engine), ""));
|
|
|
|
if file_path.exists() {
|
|
|
|
let sha1_local = file_get_sha1(&file_path).to_lowercase();
|
|
|
|
let sha1_remote = file.hash.to_lowercase();
|
|
|
|
if sha1_local != sha1_remote {
|
|
|
|
println!(
|
|
|
|
"Updating {}...\nLocal hash: {}\nRemote hash: {}",
|
|
|
|
file_path.display(),
|
|
|
|
sha1_local,
|
|
|
|
sha1_remote
|
|
|
|
);
|
|
|
|
http::download_file(
|
|
|
|
&format!(
|
|
|
|
"{}/{}?{}",
|
|
|
|
MASTER,
|
|
|
|
file.name,
|
|
|
|
rand::Rng::gen_range(&mut rand::thread_rng(), 0..1000)
|
|
|
|
),
|
|
|
|
&file_path,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
println!("Downloading {}...", file_path.display());
|
|
|
|
if let Some(parent) = file_path.parent() {
|
|
|
|
if !parent.exists() {
|
|
|
|
fs::create_dir_all(parent).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
http::download_file(
|
|
|
|
&format!(
|
|
|
|
"{}/{}?{}",
|
|
|
|
MASTER,
|
|
|
|
file.name,
|
|
|
|
rand::Rng::gen_range(&mut rand::thread_rng(), 0..1000)
|
|
|
|
),
|
|
|
|
&file_path,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn launch(file_path: &PathBuf) {
|
|
|
|
println!("Launching {}...", file_path.display());
|
|
|
|
std::process::Command::new(file_path)
|
|
|
|
.spawn()
|
|
|
|
.unwrap()
|
|
|
|
.wait()
|
|
|
|
.unwrap();
|
2023-06-10 12:38:21 +02:00
|
|
|
}
|
|
|
|
|
2023-06-10 09:33:16 +02:00
|
|
|
fn main() {
|
|
|
|
let args: Vec<String> = std::env::args().collect();
|
2023-06-10 12:38:21 +02:00
|
|
|
let mut game: String = String::new();
|
2023-06-10 09:33:16 +02:00
|
|
|
if args.len() > 1 {
|
|
|
|
game = String::from(&args[1]);
|
|
|
|
} else {
|
2023-06-10 12:38:21 +02:00
|
|
|
'main: for g in GAMES.iter() {
|
|
|
|
for r in g.references.iter() {
|
|
|
|
if std::path::Path::new(r).exists() {
|
|
|
|
game = String::from(g.client);
|
|
|
|
break 'main;
|
|
|
|
}
|
|
|
|
}
|
2023-06-10 09:33:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-10 12:38:21 +02:00
|
|
|
for g in GAMES.iter() {
|
|
|
|
if g.client == game {
|
2023-06-11 16:16:29 +02:00
|
|
|
update(&g);
|
|
|
|
launch(&PathBuf::from(format!("{}.exe", g.client)));
|
2023-06-10 12:38:21 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-06-10 09:33:16 +02:00
|
|
|
}
|
|
|
|
}
|