Added async login and switched some functions
This commit is contained in:
parent
ea35090634
commit
5b56b91035
|
|
@ -812,6 +812,16 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.16"
|
||||
|
|
@ -902,6 +912,12 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
|
|
@ -1198,6 +1214,15 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
|
|
@ -1261,7 +1286,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syntax_bootstrapper"
|
||||
version = "1.2.0"
|
||||
version = "1.2.1"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"colored",
|
||||
|
|
@ -1273,6 +1298,8 @@ dependencies = [
|
|||
"reqwest",
|
||||
"term_size",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"winreg 0.51.0",
|
||||
"winres",
|
||||
"zip-extract",
|
||||
|
|
@ -1321,6 +1348,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
|
|
@ -1435,22 +1472,59 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
|||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.31"
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
|
||||
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1503,6 +1577,12 @@ dependencies = [
|
|||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ tokio = { version = "1.32.0", features=["full"]}
|
|||
futures-util = "0.3.28"
|
||||
md5 = "0.7.0"
|
||||
zip-extract = "0.1.2"
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = "0.3.17"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winreg = "0.51.0"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
.d8888b. Y88b d88P 888b 888 88888888888 d8888 Y88b d88P
|
||||
d88P Y88b Y88b d88P 8888b 888 888 d88888 Y88b d88P
|
||||
Y88b. Y88o88P 88888b 888 888 d88P888 Y88o88P
|
||||
\"Y888b. Y888P 888Y88b 888 888 d88P 888 Y888P
|
||||
\"Y88b. 888 888 Y88b888 888 d88P 888 d888b
|
||||
\"888 888 888 Y88888 888 d88P 888 d88888b
|
||||
Y88b d88P 888 888 Y8888 888 d8888888888 d88P Y88b
|
||||
\"Y8888P\" 888 888 Y888 888 d88P 888 d88P Y88b
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
pub const FILES_TO_DOWNLOAD: [[&str; 2]; 17] = [
|
||||
["SyntaxApp.zip", "./"],
|
||||
["NPSyntaxProxy.zip", "./"],
|
||||
["SyntaxProxy.zip", "./"],
|
||||
["Libraries.zip", "./"],
|
||||
["redist.zip", "./"],
|
||||
["content-textures.zip", "./content/textures"],
|
||||
["content-textures2.zip", "./content/textures"],
|
||||
["content-textures3.zip", "./content/textures"],
|
||||
["content-terrain.zip", "./content/terrain"],
|
||||
["content-fonts.zip", "./content/fonts"],
|
||||
["content-sounds.zip", "./content/sounds"],
|
||||
["content-scripts.zip", "./content/scripts"],
|
||||
["content-sky.zip", "./content/sky"],
|
||||
["content-music.zip", "./content/music"],
|
||||
["content-particles.zip", "./content/particles"],
|
||||
["2018client.zip", "./Client2018"],
|
||||
["2020client.zip", "./Client2020"],
|
||||
];
|
||||
547
src/main.rs
547
src/main.rs
|
|
@ -1,159 +1,83 @@
|
|||
use colored::*;
|
||||
use std::path::PathBuf;
|
||||
use reqwest::Client;
|
||||
use dirs::data_local_dir;
|
||||
use futures_util::StreamExt;
|
||||
use md5;
|
||||
use metadata::LevelFilter;
|
||||
use reqwest::Client;
|
||||
use std::path::PathBuf;
|
||||
use tokio::task::JoinSet;
|
||||
use zip_extract;
|
||||
|
||||
mod constants;
|
||||
mod util;
|
||||
|
||||
use constants::*;
|
||||
|
||||
use tracing::*;
|
||||
use util::*;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::io::prelude::*;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::os::unix::fs::FileExt;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::prelude::FileExt;
|
||||
#[cfg(target_os = "windows")]
|
||||
use winreg::enums::*;
|
||||
#[cfg(target_os = "windows")]
|
||||
use winreg::RegKey;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::io::prelude::*;
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::os::unix::fs::FileExt;
|
||||
|
||||
fn info( message : &str ) {
|
||||
let time = chrono::Local::now().format("%H:%M:%S").to_string();
|
||||
println!("[{}] [{}] {}", time.bold().blue(), "INFO".bold().green(), message);
|
||||
}
|
||||
|
||||
fn error( message : &str ) {
|
||||
let time = chrono::Local::now().format("%H:%M:%S").to_string();
|
||||
println!("[{}] [{}] {}", time.bold().blue(), "ERROR".bold().red(), message);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug( message : &str ) {
|
||||
let time = chrono::Local::now().format("%H:%M:%S").to_string();
|
||||
println!("[{}] [{}] {}", time.bold().blue(), "DEBUG".bold().yellow(), message);
|
||||
}
|
||||
|
||||
const DEBUG: bool = true;
|
||||
#[cfg(debug_assertions)]
|
||||
const MAX_TRACING_LEVEL: LevelFilter = LevelFilter::DEBUG;
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn debug( message : &str ) {}
|
||||
const DEBUG: bool = false;
|
||||
#[cfg(not(debug_assertions))]
|
||||
const MAX_TRACING_LEVEL: LevelFilter = LevelFilter::ERROR;
|
||||
|
||||
pub async fn http_get( client: &Client ,url: &str ) -> Result<String, reqwest::Error> {
|
||||
debug(&format!("{} {}", "GET".green(), url.bright_blue()));
|
||||
let response = client.get(url).send().await;
|
||||
if (response.is_err()) {
|
||||
debug(&format!("Failed to fetch {}", url.bright_blue()));
|
||||
return Err(response.err().unwrap());
|
||||
}
|
||||
let response_body = response.unwrap().text().await.unwrap();
|
||||
Ok(response_body)
|
||||
}
|
||||
|
||||
pub async fn download_file( client: &Client, url: &str, path: &PathBuf ) {
|
||||
debug(&format!("{} {}", "GET".green(), url.bright_blue()));
|
||||
let response = client.get(url).send().await.unwrap();
|
||||
let content_length = response.content_length().unwrap();
|
||||
debug(&format!("Content Length: {}", content_length));
|
||||
|
||||
let time = chrono::Local::now().format("%H:%M:%S").to_string();
|
||||
let pg_bar_str = " {spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})";
|
||||
let progress_bar = indicatif::ProgressBar::new(content_length);
|
||||
let progress_style = indicatif::ProgressStyle::default_bar()
|
||||
.template(
|
||||
format!("{}\n{}",
|
||||
format!(
|
||||
"[{}] [{}] {}",
|
||||
time.bold().blue(),
|
||||
"INFO".bold().green(),
|
||||
&format!("Downloading {}", &url.bright_blue())
|
||||
),
|
||||
pg_bar_str).as_str()
|
||||
)
|
||||
.unwrap().progress_chars("#>-");
|
||||
progress_bar.set_style(progress_style);
|
||||
progress_bar.set_message("Downloading File");
|
||||
|
||||
let file = std::fs::File::create(path).unwrap();
|
||||
let mut downloaded: u64 = 0;
|
||||
let mut stream = response.bytes_stream();
|
||||
|
||||
while let Some(item) = stream.next().await {
|
||||
let chunk = item.or(Err(format!("Error while downloading file"))).unwrap();
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
file.seek_write(chunk.as_ref(), downloaded).unwrap();
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
file.write_at(chunk.as_ref(), downloaded).unwrap();
|
||||
}
|
||||
let new = std::cmp::min(downloaded + (chunk.len() as u64), content_length);
|
||||
downloaded = new;
|
||||
progress_bar.set_position(new);
|
||||
}
|
||||
progress_bar.finish();
|
||||
info(format!("Finished downloading {}", url.green()).as_str());
|
||||
}
|
||||
|
||||
pub async fn download_file_prefix( client: &Client, url: &str, path_prefix : &PathBuf ) -> PathBuf {
|
||||
let path = path_prefix.join(generate_md5(url).await);
|
||||
download_file(client, url, &path).await;
|
||||
return path;
|
||||
}
|
||||
|
||||
pub async fn generate_md5( input : &str ) -> String {
|
||||
let hashed_input = md5::compute(input.as_bytes());
|
||||
return format!("{:x}", hashed_input);
|
||||
}
|
||||
|
||||
pub async fn create_folder_if_not_exists( path: &PathBuf ) {
|
||||
if !path.exists() {
|
||||
info(&format!("Creating folder {}", path.to_str().unwrap().bright_blue()));
|
||||
std::fs::create_dir_all(path).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_installation_directory() -> PathBuf {
|
||||
return PathBuf::from(data_local_dir().unwrap().to_str().unwrap()).join("Syntax");
|
||||
}
|
||||
const ASCII_ART: &str = include_str!("./ascii.txt");
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
||||
// Clear the terminal before printing the startup text
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
std::process::Command::new("cmd")
|
||||
.args(&["/c", "cls"])
|
||||
.spawn()
|
||||
.expect("cls command failed to start")
|
||||
.wait()
|
||||
.expect("failed to wait");
|
||||
.args(&["/c", "cls"])
|
||||
.spawn()
|
||||
.expect("cls command failed to start")
|
||||
.wait()
|
||||
.expect("failed to wait");
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
std::process::Command::new("clear").spawn().unwrap();
|
||||
}
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_max_level(MAX_TRACING_LEVEL)
|
||||
.pretty()
|
||||
.init();
|
||||
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let base_url : &str = "www.syntax.eco";
|
||||
let mut setup_url : &str = "setup.syntax.eco";
|
||||
let fallback_setup_url : &str = "d2f3pa9j0u8v6f.cloudfront.net";
|
||||
let mut bootstrapper_filename :&str = "SyntaxPlayerLauncher.exe";
|
||||
let base_url: &str = "www.syntax.eco";
|
||||
let mut setup_url: &str = "setup.syntax.eco";
|
||||
let fallback_setup_url: &str = "d2f3pa9j0u8v6f.cloudfront.net";
|
||||
let mut bootstrapper_filename: &str = "SyntaxPlayerLauncher.exe";
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
bootstrapper_filename = "SyntaxPlayerLinuxLauncher";
|
||||
}
|
||||
let build_date = include_str!(concat!(env!("OUT_DIR"), "/build_date.txt"));
|
||||
let startup_text = format!("
|
||||
.d8888b. Y88b d88P 888b 888 88888888888 d8888 Y88b d88P
|
||||
d88P Y88b Y88b d88P 8888b 888 888 d88888 Y88b d88P
|
||||
Y88b. Y88o88P 88888b 888 888 d88P888 Y88o88P
|
||||
\"Y888b. Y888P 888Y88b 888 888 d88P 888 Y888P
|
||||
\"Y88b. 888 888 Y88b888 888 d88P 888 d888b
|
||||
\"888 888 888 Y88888 888 d88P 888 d88888b
|
||||
Y88b d88P 888 888 Y8888 888 d8888888888 d88P Y88b
|
||||
\"Y8888P\" 888 888 Y888 888 d88P 888 d88P Y88b
|
||||
|
||||
{} | Build Date: {} | Version: {}", base_url ,build_date, env!("CARGO_PKG_VERSION"));
|
||||
let startup_text = ASCII_ART.to_owned();
|
||||
|
||||
let bootstrapper_info = format!(
|
||||
"{} | Build Date: {} | Version: {}",
|
||||
base_url,
|
||||
build_date,
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
);
|
||||
|
||||
// Format the startup text to be centered
|
||||
let mut terminal_width = 80;
|
||||
|
|
@ -161,51 +85,80 @@ async fn main() {
|
|||
terminal_width = w;
|
||||
}
|
||||
if terminal_width < 80 {
|
||||
print!("{}\n", format!("SYNTAX Bootstrapper | {} | Build Date: {} | Version: {}", base_url, build_date, env!("CARGO_PKG_VERSION")).to_string().magenta().cyan().italic().on_black()); // Fallback message
|
||||
print!(
|
||||
"{}\n",
|
||||
format!(
|
||||
"SYNTAX Bootstrapper | {} | Build Date: {} | Version: {}",
|
||||
base_url,
|
||||
build_date,
|
||||
env!("CARGO_PKG_VERSION")
|
||||
)
|
||||
.to_string()
|
||||
.magenta()
|
||||
.cyan()
|
||||
.italic()
|
||||
.on_black()
|
||||
); // Fallback message
|
||||
} else {
|
||||
let startup_text_lines = startup_text.lines().collect::<Vec<&str>>();
|
||||
//println!("{}", startup_text.bold().blue().on_black());
|
||||
|
||||
|
||||
// print all lines except the last one
|
||||
for line in &startup_text_lines[0..startup_text_lines.len() - 1] {
|
||||
for line in startup_text_lines {
|
||||
let spaces = (terminal_width - line.len()) / 2;
|
||||
let formatted_line = format!("{}{}", " ".repeat(spaces), line);
|
||||
println!("{}", formatted_line.bright_magenta().italic().on_black());
|
||||
}
|
||||
|
||||
// print last line as a different color
|
||||
let last_line = startup_text_lines[startup_text_lines.len() - 1];
|
||||
let spaces = (terminal_width - last_line.len()) / 2;
|
||||
let last_line = format!("{}{}", " ".repeat(spaces), last_line);
|
||||
println!("{}\n", last_line.magenta().cyan().italic().on_black());
|
||||
println!(
|
||||
"{}\n",
|
||||
bootstrapper_info.magenta().cyan().italic().on_black()
|
||||
);
|
||||
}
|
||||
|
||||
let http_client: Client = reqwest::Client::builder()
|
||||
.no_gzip()
|
||||
.build()
|
||||
.unwrap();
|
||||
debug(format!("Setup Server: {} | Base Server: {}", setup_url.bright_blue(), base_url.bright_blue()).as_str());
|
||||
debug("Fetching latest client version from setup server");
|
||||
|
||||
let latest_client_version : String;
|
||||
let latest_client_version_response = http_get(&http_client ,&format!("https://{}/version", setup_url)).await;
|
||||
let http_client: Client = reqwest::Client::builder().no_gzip().build().unwrap();
|
||||
debug!(
|
||||
"Setup Server: {} | Base Server: {}",
|
||||
setup_url.bright_blue(),
|
||||
base_url.bright_blue()
|
||||
);
|
||||
|
||||
debug!("Fetching latest client version from setup server");
|
||||
|
||||
let latest_client_version: String;
|
||||
let latest_client_version_response =
|
||||
http_get(&http_client, &format!("https://{}/version", setup_url)).await;
|
||||
match latest_client_version_response {
|
||||
Ok(latest_client_version_result) => {
|
||||
debug(&format!("Latest Client Version: {}", latest_client_version_result.bright_blue()));
|
||||
debug!(
|
||||
"Latest Client Version: {}",
|
||||
latest_client_version_result.bright_blue()
|
||||
);
|
||||
latest_client_version = latest_client_version_result;
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
error(&format!("Failed to fetch latest client version from setup server: [{}], attempting to fallback to {}", e.to_string().bright_red(), fallback_setup_url.bright_blue()));
|
||||
let fallback_client_version_response = http_get(&http_client ,&format!("https://{}/version", fallback_setup_url)).await;
|
||||
error!("Failed to fetch latest client version from setup server: [{}], attempting to fallback to {}", e.to_string().bright_red(), fallback_setup_url.bright_blue());
|
||||
let fallback_client_version_response = http_get(
|
||||
&http_client,
|
||||
&format!("https://{}/version", fallback_setup_url),
|
||||
)
|
||||
.await;
|
||||
match fallback_client_version_response {
|
||||
Ok(fallback_client_version_result) => {
|
||||
info(&format!("Successfully fetched latest client version from fallback setup server: {}", fallback_setup_url.bright_blue()));
|
||||
debug(&format!("Latest Client Version: {}", fallback_client_version_result.bright_blue()));
|
||||
info!(
|
||||
"Successfully fetched latest client version from fallback setup server: {}",
|
||||
fallback_setup_url.bright_blue()
|
||||
);
|
||||
debug!(
|
||||
"Latest Client Version: {}",
|
||||
fallback_client_version_result.bright_blue()
|
||||
);
|
||||
latest_client_version = fallback_client_version_result;
|
||||
setup_url = fallback_setup_url;
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
error(&format!("Failed to fetch latest client version from fallback setup server: {}, are you connected to the internet?", e));
|
||||
error!("Failed to fetch latest client version from fallback setup server: {}, are you connected to the internet?", e);
|
||||
std::thread::sleep(std::time::Duration::from_secs(10));
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
|
@ -214,35 +167,58 @@ async fn main() {
|
|||
}
|
||||
|
||||
// Wait for the latest client version to be fetched
|
||||
info(&format!("Latest Client Version: {}", latest_client_version.cyan().underline()));
|
||||
debug(&format!("Setup Server: {}", setup_url.cyan().underline()));
|
||||
info!(
|
||||
"Latest Client Version: {}",
|
||||
latest_client_version.cyan().underline()
|
||||
);
|
||||
debug!("Setup Server: {}", setup_url.cyan().underline());
|
||||
|
||||
let installation_directory = get_installation_directory();
|
||||
debug(&format!("Installation Directory: {}", installation_directory.to_str().unwrap().bright_blue()));
|
||||
debug!(
|
||||
"Installation Directory: {}",
|
||||
installation_directory.to_str().unwrap().bright_blue()
|
||||
);
|
||||
create_folder_if_not_exists(&installation_directory).await;
|
||||
|
||||
let versions_directory = installation_directory.join("Versions");
|
||||
debug(&format!("Versions Directory: {}", versions_directory.to_str().unwrap().bright_blue()));
|
||||
debug!(
|
||||
"Versions Directory: {}",
|
||||
versions_directory.to_str().unwrap().bright_blue()
|
||||
);
|
||||
create_folder_if_not_exists(&versions_directory).await;
|
||||
|
||||
let temp_downloads_directory = installation_directory.join("Downloads");
|
||||
debug(&format!("Temp Downloads Directory: {}", temp_downloads_directory.to_str().unwrap().bright_blue()));
|
||||
debug!(
|
||||
"Temp Downloads Directory: {}",
|
||||
temp_downloads_directory.to_str().unwrap().bright_blue()
|
||||
);
|
||||
create_folder_if_not_exists(&temp_downloads_directory).await;
|
||||
|
||||
let current_version_directory = versions_directory.join(format!("{}", latest_client_version));
|
||||
debug(&format!("Current Version Directory: {}", current_version_directory.to_str().unwrap().bright_blue()));
|
||||
debug!(
|
||||
"Current Version Directory: {}",
|
||||
current_version_directory.to_str().unwrap().bright_blue()
|
||||
);
|
||||
create_folder_if_not_exists(¤t_version_directory).await;
|
||||
|
||||
let latest_bootstrapper_path = current_version_directory.join(bootstrapper_filename);
|
||||
// Is the program currently running from the latest version directory?
|
||||
let current_exe_path = std::env::current_exe().unwrap();
|
||||
// If the current exe path is not in the current version directory, then we need to run the latest bootstrapper ( download if needed )
|
||||
if !current_exe_path.starts_with(¤t_version_directory) {
|
||||
if !current_exe_path.starts_with(¤t_version_directory) && !DEBUG {
|
||||
// Check if the latest bootstrapper is downloaded
|
||||
if !latest_bootstrapper_path.exists() {
|
||||
info("Downloading the latest bootstrapper and restarting");
|
||||
info!("Downloading the latest bootstrapper and restarting");
|
||||
// Download the latest bootstrapper
|
||||
download_file(&http_client, &format!("https://{}/{}-{}", setup_url, latest_client_version, bootstrapper_filename), &latest_bootstrapper_path).await;
|
||||
download_to_file(
|
||||
&http_client,
|
||||
&format!(
|
||||
"https://{}/{}-{}",
|
||||
setup_url, latest_client_version, bootstrapper_filename
|
||||
),
|
||||
&latest_bootstrapper_path,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
// Run the latest bootstrapper ( with the same arguments passed to us ) and exit
|
||||
#[cfg(target_os = "windows")]
|
||||
|
|
@ -250,12 +226,20 @@ async fn main() {
|
|||
let mut command = std::process::Command::new(latest_bootstrapper_path.clone());
|
||||
command.args(&args[1..]);
|
||||
match command.spawn() {
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
debug(&format!("Bootstrapper errored with error {}", e));
|
||||
debug!(&format!("Bootstrapper errored with error {}", e));
|
||||
info("Found bootstrapper was corrupted! Downloading...");
|
||||
std::fs::remove_file(latest_bootstrapper_path.clone()).unwrap();
|
||||
download_file(&http_client, &format!("https://{}/{}-{}", setup_url, latest_client_version, bootstrapper_filename), &latest_bootstrapper_path).await;
|
||||
download_file(
|
||||
&http_client,
|
||||
&format!(
|
||||
"https://{}/{}-{}",
|
||||
setup_url, latest_client_version, bootstrapper_filename
|
||||
),
|
||||
&latest_bootstrapper_path,
|
||||
)
|
||||
.await;
|
||||
command.spawn().expect("Bootstrapper is still corrupted.");
|
||||
std::thread::sleep(std::time::Duration::from_secs(20));
|
||||
}
|
||||
|
|
@ -264,9 +248,13 @@ async fn main() {
|
|||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
// Make sure the latest bootstrapper is executable
|
||||
std::process::Command::new("chmod").arg("+x").arg(latest_bootstrapper_path.to_str().unwrap()).spawn().unwrap();
|
||||
std::process::Command::new("chmod")
|
||||
.arg("+x")
|
||||
.arg(latest_bootstrapper_path.to_str().unwrap())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
info("We need permission to run the latest bootstrapper");
|
||||
info!("We need permission to run the latest bootstrapper");
|
||||
let mut command = std::process::Command::new(latest_bootstrapper_path);
|
||||
command.args(&args[1..]);
|
||||
command.spawn().unwrap();
|
||||
|
|
@ -275,13 +263,13 @@ async fn main() {
|
|||
}
|
||||
|
||||
// Looks like we are running from the latest version directory, so we can continue with the update process
|
||||
// Check for "AppSettings.xml" in the current version directory
|
||||
// Check for "AppSettings.xml" in the current version directory
|
||||
// If it doesent exist, then we got either a fresh directory or a corrupted installation
|
||||
// So delete the every file in the current version directory except for the Bootstrapper itself
|
||||
let app_settings_path = current_version_directory.join("AppSettings.xml");
|
||||
let client_executable_path = current_version_directory.join("SyntaxPlayerBeta.exe");
|
||||
if !app_settings_path.exists() || !client_executable_path.exists() {
|
||||
info("Downloading the latest client files, this may take a while.");
|
||||
info!("Downloading the latest client files, this may take a while.");
|
||||
for entry in std::fs::read_dir(¤t_version_directory).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
|
|
@ -294,117 +282,70 @@ async fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
let VersionURLPrefix = format!("https://{}/{}-", setup_url, latest_client_version);
|
||||
let SyntaxAppZip : PathBuf = download_file_prefix(&http_client, format!("{}SyntaxApp.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let NPSyntaxProxyZip : PathBuf = download_file_prefix(&http_client, format!("{}NPSyntaxProxy.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let SyntaxProxyZip : PathBuf = download_file_prefix(&http_client, format!("{}SyntaxProxy.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let LibrariesZip : PathBuf = download_file_prefix(&http_client, format!("{}Libraries.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let RedistZip : PathBuf = download_file_prefix(&http_client, format!("{}redist.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let version_url_prefix = format!("https://{}/{}-", setup_url, latest_client_version);
|
||||
|
||||
let ContentTexturesZip : PathBuf = download_file_prefix(&http_client, format!("{}content-textures.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentTextures2Zip : PathBuf = download_file_prefix(&http_client, format!("{}content-textures2.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentTextures3Zip : PathBuf = download_file_prefix(&http_client, format!("{}content-textures3.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentTerrainZip : PathBuf = download_file_prefix(&http_client, format!("{}content-terrain.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentFontsZip : PathBuf = download_file_prefix(&http_client, format!("{}content-fonts.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentSoundsZip : PathBuf = download_file_prefix(&http_client, format!("{}content-sounds.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentScriptsZip : PathBuf = download_file_prefix(&http_client, format!("{}content-scripts.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentSkyZip : PathBuf = download_file_prefix(&http_client, format!("{}content-sky.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentMusicZip : PathBuf = download_file_prefix(&http_client, format!("{}content-music.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let ContentParticles : PathBuf = download_file_prefix(&http_client, format!("{}content-particles.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
/* Use a joisnet to run multiple async functions at once */
|
||||
|
||||
let ShadersZip : PathBuf = download_file_prefix(&http_client, format!("{}shaders.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let mut set = JoinSet::new();
|
||||
|
||||
let Client2018Zip : PathBuf = download_file_prefix(&http_client, format!("{}2018client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
let Client2020Zip : PathBuf = download_file_prefix(&http_client, format!("{}2020client.zip", VersionURLPrefix).as_str(), &temp_downloads_directory).await;
|
||||
info("Download finished, extracting files.");
|
||||
|
||||
fn extract_to_dir( zip_file : &PathBuf, target_dir : &PathBuf ) {
|
||||
let zip_file_cursor = std::fs::File::open(zip_file).unwrap();
|
||||
zip_extract::extract(zip_file_cursor, target_dir, false).unwrap();
|
||||
for [value, _] in FILES_TO_DOWNLOAD {
|
||||
set.spawn(download_and_extract(
|
||||
value.to_string(),
|
||||
version_url_prefix.clone(),
|
||||
current_version_directory.clone(),
|
||||
));
|
||||
}
|
||||
extract_to_dir(&SyntaxAppZip, ¤t_version_directory);
|
||||
extract_to_dir(&NPSyntaxProxyZip, ¤t_version_directory);
|
||||
extract_to_dir(&SyntaxProxyZip, ¤t_version_directory);
|
||||
extract_to_dir(&LibrariesZip, ¤t_version_directory);
|
||||
extract_to_dir(&RedistZip, ¤t_version_directory);
|
||||
|
||||
let content_directory = current_version_directory.join("content");
|
||||
let platform_content_directory = current_version_directory.join("PlatformContent");
|
||||
let shaders_directory = current_version_directory.join("shaders");
|
||||
while let Some(value) = set.join_next().await {
|
||||
value.unwrap()
|
||||
}
|
||||
|
||||
create_folder_if_not_exists(&content_directory).await;
|
||||
create_folder_if_not_exists(&platform_content_directory).await;
|
||||
create_folder_if_not_exists(&shaders_directory).await;
|
||||
info!("Binary installed");
|
||||
|
||||
let fonts_directory = content_directory.join("fonts");
|
||||
let music_directory = content_directory.join("music");
|
||||
let particles_directory = content_directory.join("particles");
|
||||
let sky_directory = content_directory.join("sky");
|
||||
let sounds_directory = content_directory.join("sounds");
|
||||
let textures_directory = content_directory.join("textures");
|
||||
let scripts_directory = content_directory.join("scripts");
|
||||
/* Convert to async due to this being a slow function */
|
||||
|
||||
create_folder_if_not_exists(&fonts_directory).await;
|
||||
create_folder_if_not_exists(&music_directory).await;
|
||||
create_folder_if_not_exists(&particles_directory).await;
|
||||
create_folder_if_not_exists(&sky_directory).await;
|
||||
create_folder_if_not_exists(&sounds_directory).await;
|
||||
create_folder_if_not_exists(&textures_directory).await;
|
||||
|
||||
extract_to_dir(&ContentTexturesZip, &textures_directory);
|
||||
extract_to_dir(&ContentTextures2Zip, &textures_directory);
|
||||
extract_to_dir(&ContentFontsZip, &fonts_directory);
|
||||
extract_to_dir(&ContentSoundsZip, &sounds_directory);
|
||||
extract_to_dir(&ContentSkyZip, &sky_directory);
|
||||
extract_to_dir(&ContentMusicZip, &music_directory);
|
||||
extract_to_dir(&ContentParticles, &particles_directory);
|
||||
extract_to_dir(&ContentScriptsZip, &scripts_directory);
|
||||
|
||||
let platform_pc_directory = platform_content_directory.join("pc");
|
||||
create_folder_if_not_exists(&platform_pc_directory).await;
|
||||
let terrain_directory = platform_pc_directory.join("terrain");
|
||||
let textures_directory = platform_pc_directory.join("textures");
|
||||
create_folder_if_not_exists(&terrain_directory).await;
|
||||
create_folder_if_not_exists(&textures_directory).await;
|
||||
|
||||
extract_to_dir(&ContentTerrainZip, &terrain_directory);
|
||||
extract_to_dir(&ContentTextures3Zip, &textures_directory);
|
||||
extract_to_dir(&ShadersZip, &shaders_directory);
|
||||
|
||||
let client_2018_directory = current_version_directory.join("Client2018");
|
||||
create_folder_if_not_exists(&client_2018_directory).await;
|
||||
extract_to_dir(&Client2018Zip, &client_2018_directory);
|
||||
|
||||
let client_2020_directory = current_version_directory.join("Client2020");
|
||||
create_folder_if_not_exists(&client_2020_directory).await;
|
||||
extract_to_dir(&Client2020Zip, &client_2020_directory);
|
||||
|
||||
info("Finished extracting files, cleaning up.");
|
||||
std::fs::remove_dir_all(&temp_downloads_directory).unwrap();
|
||||
// Redacted for lagging vscode
|
||||
|
||||
// Install the syntax-player scheme in the registry
|
||||
info("Installing syntax-player scheme");
|
||||
info!("Installing syntax-player scheme");
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let hkey_current_user = RegKey::predef(HKEY_CURRENT_USER);
|
||||
let hkey_classes_root : RegKey = hkey_current_user.open_subkey("Software\\Classes").unwrap();
|
||||
let hkey_classes_root: RegKey =
|
||||
hkey_current_user.open_subkey("Software\\Classes").unwrap();
|
||||
let hkey_syntax_player = hkey_classes_root.create_subkey("syntax-player").unwrap().0;
|
||||
let hkey_syntax_player_shell = hkey_syntax_player.create_subkey("shell").unwrap().0;
|
||||
let hkey_syntax_player_shell_open = hkey_syntax_player_shell.create_subkey("open").unwrap().0;
|
||||
let hkey_syntax_player_shell_open_command = hkey_syntax_player_shell_open.create_subkey("command").unwrap().0;
|
||||
let hkey_syntax_player_shell_open =
|
||||
hkey_syntax_player_shell.create_subkey("open").unwrap().0;
|
||||
let hkey_syntax_player_shell_open_command = hkey_syntax_player_shell_open
|
||||
.create_subkey("command")
|
||||
.unwrap()
|
||||
.0;
|
||||
let defaulticon = hkey_syntax_player.create_subkey("DefaultIcon").unwrap().0;
|
||||
hkey_syntax_player_shell_open_command.set_value("", &format!("\"{}\" \"%1\"", current_exe_path.to_str().unwrap())).unwrap();
|
||||
defaulticon.set_value("", &format!("\"{}\",0", current_exe_path.to_str().unwrap())).unwrap();
|
||||
hkey_syntax_player.set_value("", &format!("URL: Syntax Protocol")).unwrap();
|
||||
hkey_syntax_player_shell_open_command
|
||||
.set_value(
|
||||
"",
|
||||
&format!("\"{}\" \"%1\"", current_exe_path.to_str().unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
defaulticon
|
||||
.set_value("", &format!("\"{}\",0", current_exe_path.to_str().unwrap()))
|
||||
.unwrap();
|
||||
hkey_syntax_player
|
||||
.set_value("", &format!("URL: Syntax Protocol"))
|
||||
.unwrap();
|
||||
hkey_syntax_player.set_value("URL Protocol", &"").unwrap();
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
// Linux support
|
||||
// We have to write a .desktop file to ~/.local/share/applications
|
||||
let desktop_file_path = dirs::data_local_dir().unwrap().join("applications").join("syntax-player.desktop");
|
||||
let desktop_file_path = dirs::data_local_dir()
|
||||
.unwrap()
|
||||
.join("applications")
|
||||
.join("syntax-player.desktop");
|
||||
let desktop_file = format!(
|
||||
"[Desktop Entry]
|
||||
"[Desktop Entry]
|
||||
Name=Syntax Launcher
|
||||
Exec={} %u
|
||||
Terminal=true
|
||||
|
|
@ -414,31 +355,37 @@ Icon={}
|
|||
StartupWMClass=SyntaxLauncher
|
||||
Categories=Game;
|
||||
Comment=Syntax Launcher
|
||||
", current_exe_path.to_str().unwrap(), current_exe_path.to_str().unwrap());
|
||||
",
|
||||
current_exe_path.to_str().unwrap(),
|
||||
current_exe_path.to_str().unwrap()
|
||||
);
|
||||
std::fs::write(desktop_file_path, desktop_file).unwrap();
|
||||
// We also have to write a mimeapps.list file to ~/.config
|
||||
let mimeapps_list_path = dirs::config_dir().unwrap().join("mimeapps.list");
|
||||
let mimeapps_list = format!(
|
||||
"[Default Applications]
|
||||
"[Default Applications]
|
||||
x-scheme-handler/syntax-player=syntax-player.desktop
|
||||
");
|
||||
"
|
||||
);
|
||||
std::fs::write(mimeapps_list_path, mimeapps_list).unwrap();
|
||||
// We also have to write a mimeapps.list file to ~/.local/share
|
||||
let mimeapps_list_path = dirs::data_local_dir().unwrap().join("mimeapps.list");
|
||||
let mimeapps_list = format!(
|
||||
"[Default Applications]
|
||||
"[Default Applications]
|
||||
x-scheme-handler/syntax-player=syntax-player.desktop
|
||||
");
|
||||
"
|
||||
);
|
||||
std::fs::write(mimeapps_list_path, mimeapps_list).unwrap();
|
||||
}
|
||||
|
||||
// Write the AppSettings.xml file
|
||||
let app_settings_xml = format!(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
||||
<Settings>
|
||||
<ContentFolder>content</ContentFolder>
|
||||
<BaseUrl>https://{}</BaseUrl>
|
||||
</Settings>", base_url
|
||||
</Settings>",
|
||||
base_url
|
||||
);
|
||||
std::fs::write(app_settings_path, app_settings_xml).unwrap();
|
||||
|
||||
|
|
@ -456,17 +403,25 @@ x-scheme-handler/syntax-player=syntax-player.desktop
|
|||
|
||||
// Parse the arguments passed to the bootstrapper
|
||||
// Looks something like "syntax-player://1+launchmode:play+gameinfo:TICKET+placelauncherurl:https://www.syntax.eco/Game/placelauncher.ashx?placeId=660&t=TICKET+k:l"
|
||||
debug(&format!("Arguments Passed: {}", args.join(" ").bright_blue()));
|
||||
debug!("Arguments Passed: {}", args.join(" ").bright_blue());
|
||||
if args.len() == 1 {
|
||||
// Just open the website
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
std::process::Command::new("cmd").arg("/c").arg("start").arg("https://www.syntax.eco/games").spawn().unwrap();
|
||||
std::process::Command::new("cmd")
|
||||
.arg("/c")
|
||||
.arg("start")
|
||||
.arg("https://www.syntax.eco/games")
|
||||
.spawn()
|
||||
.unwrap();
|
||||
std::process::exit(0);
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
std::process::Command::new("xdg-open").arg("https://www.syntax.eco/games").spawn().unwrap();
|
||||
std::process::Command::new("xdg-open")
|
||||
.arg("https://www.syntax.eco/games")
|
||||
.spawn()
|
||||
.unwrap();
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -479,30 +434,29 @@ x-scheme-handler/syntax-player=syntax-player.desktop
|
|||
let mut authentication_ticket = String::new();
|
||||
let mut join_script = String::new();
|
||||
let mut client_year = String::new();
|
||||
|
||||
|
||||
for arg in main_args {
|
||||
let mut arg_split = arg.split(":");
|
||||
let key = arg_split.next().unwrap();
|
||||
let value =
|
||||
if arg_split.clone().count() > 0 {
|
||||
arg_split.collect::<Vec<&str>>().join(":")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
debug(&format!("{}: {}", key.bright_blue(), value.bright_blue()));
|
||||
let value = if arg_split.clone().count() > 0 {
|
||||
arg_split.collect::<Vec<&str>>().join(":")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
debug!("{}: {}", key.bright_blue(), value.bright_blue());
|
||||
match key {
|
||||
"launchmode" => {
|
||||
launch_mode = value.to_string();
|
||||
},
|
||||
}
|
||||
"gameinfo" => {
|
||||
authentication_ticket = value.to_string();
|
||||
},
|
||||
}
|
||||
"placelauncherurl" => {
|
||||
join_script = value.to_string();
|
||||
},
|
||||
}
|
||||
"clientyear" => {
|
||||
client_year = value.to_string();
|
||||
},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -514,18 +468,22 @@ x-scheme-handler/syntax-player=syntax-player.desktop
|
|||
let wine_path_file = installation_directory.join("winepath.txt");
|
||||
if wine_path_file.exists() {
|
||||
let custom_wine = std::fs::read_to_string(wine_path_file).unwrap();
|
||||
info(&format!("Using custom wine binary: {}", custom_wine.bright_blue()));
|
||||
info!("Using custom wine binary: {}", custom_wine.bright_blue());
|
||||
} else {
|
||||
info("No custom wine binary specified, using default wine command");
|
||||
info(format!("If you want to use a custom wine binary, please create a file at {} with the path to the wine binary", wine_path_file.to_str().unwrap()).as_str());
|
||||
info!("No custom wine binary specified, using default wine command");
|
||||
info!("If you want to use a custom wine binary, please create a file at {} with the path to the wine binary", wine_path_file.to_str().unwrap());
|
||||
}
|
||||
}
|
||||
let client_executable_path : PathBuf;
|
||||
debug(&client_year.to_string());
|
||||
let client_executable_path: PathBuf;
|
||||
debug!("{}", &client_year.to_string());
|
||||
if client_year == "2018" {
|
||||
client_executable_path = current_version_directory.join("Client2018").join("SyntaxPlayerBeta.exe");
|
||||
client_executable_path = current_version_directory
|
||||
.join("Client2018")
|
||||
.join("SyntaxPlayerBeta.exe");
|
||||
} else if client_year == "2020" {
|
||||
client_executable_path = current_version_directory.join("Client2020").join("SyntaxPlayerBeta.exe");
|
||||
client_executable_path = current_version_directory
|
||||
.join("Client2020")
|
||||
.join("SyntaxPlayerBeta.exe");
|
||||
} else {
|
||||
client_executable_path = current_version_directory.join("SyntaxPlayerBeta.exe");
|
||||
}
|
||||
|
|
@ -534,17 +492,25 @@ x-scheme-handler/syntax-player=syntax-player.desktop
|
|||
let app_settings_path = current_version_directory.join("AppSettings.xml");
|
||||
std::fs::remove_file(app_settings_path).unwrap();
|
||||
|
||||
error("Failed to run SyntaxPlayerBeta.exe, is your antivirus removing it? The bootstrapper will attempt to redownload the client on next launch.");
|
||||
error!("Failed to run SyntaxPlayerBeta.exe, is your antivirus removing it? The bootstrapper will attempt to redownload the client on next launch.");
|
||||
std::thread::sleep(std::time::Duration::from_secs(20));
|
||||
std::process::exit(0);
|
||||
}
|
||||
match launch_mode.as_str() {
|
||||
"play" => {
|
||||
info("Launching SYNTAX");
|
||||
info!("Launching SYNTAX");
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
{
|
||||
let mut command = std::process::Command::new(client_executable_path);
|
||||
command.args(&["--play","--authenticationUrl", format!("https://{}/Login/Negotiate.ashx", base_url).as_str(), "--authenticationTicket", authentication_ticket.as_str(), "--joinScriptUrl", format!("{}",join_script.as_str()).as_str()]);
|
||||
command.args(&[
|
||||
"--play",
|
||||
"--authenticationUrl",
|
||||
format!("https://{}/Login/Negotiate.ashx", base_url).as_str(),
|
||||
"--authenticationTicket",
|
||||
authentication_ticket.as_str(),
|
||||
"--joinScriptUrl",
|
||||
format!("{}", join_script.as_str()).as_str(),
|
||||
]);
|
||||
command.spawn().unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_secs(5));
|
||||
std::process::exit(0);
|
||||
|
|
@ -553,18 +519,27 @@ x-scheme-handler/syntax-player=syntax-player.desktop
|
|||
{
|
||||
// We have to launch the game through wine
|
||||
let mut command = std::process::Command::new(custom_wine);
|
||||
command.args(&[client_executable_path.to_str().unwrap(), "--play","--authenticationUrl", format!("https://{}/Login/Negotiate.ashx", base_url).as_str(), "--authenticationTicket", authentication_ticket.as_str(), "--joinScriptUrl", format!("{}",join_script.as_str()).as_str()]);
|
||||
command.args(&[
|
||||
client_executable_path.to_str().unwrap(),
|
||||
"--play",
|
||||
"--authenticationUrl",
|
||||
format!("https://{}/Login/Negotiate.ashx", base_url).as_str(),
|
||||
"--authenticationTicket",
|
||||
authentication_ticket.as_str(),
|
||||
"--joinScriptUrl",
|
||||
format!("{}", join_script.as_str()).as_str(),
|
||||
]);
|
||||
// We must wait for the game to exit before exiting the bootstrapper
|
||||
let mut child = command.spawn().unwrap();
|
||||
child.wait().unwrap();
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
std::process::exit(0);
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
error("Unknown launch mode, exiting.");
|
||||
error!("Unknown launch mode, exiting.");
|
||||
std::thread::sleep(std::time::Duration::from_secs(10));
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
Move all generic functions into this area
|
||||
*/
|
||||
use colored::*;
|
||||
use dirs::data_local_dir;
|
||||
use futures_util::StreamExt;
|
||||
use md5;
|
||||
use reqwest::Client;
|
||||
use reqwest::ClientBuilder;
|
||||
use std::io::Cursor;
|
||||
use std::path::PathBuf;
|
||||
use tokio::fs;
|
||||
use tokio::fs::create_dir_all;
|
||||
use zip_extract;
|
||||
|
||||
use crate::constants::*;
|
||||
use tracing::*;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::io::prelude::*;
|
||||
/*
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
use std::os::unix::fs::FileExt;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::os::windows::prelude::FileExt;
|
||||
*/
|
||||
#[cfg(target_os = "windows")]
|
||||
use winreg::enums::*;
|
||||
#[cfg(target_os = "windows")]
|
||||
use winreg::RegKey;
|
||||
|
||||
pub async fn http_get(client: &Client, url: &str) -> Result<String, reqwest::Error> {
|
||||
debug!("{} {}", "GET".green(), url.bright_blue());
|
||||
let response = client.get(url).send().await;
|
||||
if response.is_err() {
|
||||
debug!("Failed to fetch {}", url.bright_blue());
|
||||
return Err(response.err().unwrap());
|
||||
}
|
||||
let response_body = response.unwrap().text().await.unwrap();
|
||||
Ok(response_body)
|
||||
}
|
||||
|
||||
pub async fn download_file(client: &Client, url: &str) -> Vec<u8> {
|
||||
debug!("{} {}", "GET".green(), url.bright_blue());
|
||||
let response = client.get(url).send().await.unwrap();
|
||||
/* Why through over a visual bug? */
|
||||
let content_length = response.content_length().or(Some(0)).unwrap();
|
||||
debug!("Content Length: {}", content_length);
|
||||
|
||||
let time = chrono::Local::now().format("%H:%M:%S").to_string();
|
||||
let pg_bar_str =
|
||||
" {spinner:.green} [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})";
|
||||
let progress_bar = indicatif::ProgressBar::new(content_length);
|
||||
let progress_style = indicatif::ProgressStyle::default_bar()
|
||||
.template(
|
||||
format!(
|
||||
"{}\n{}",
|
||||
format!(
|
||||
"[{}] [{}] {}",
|
||||
time.bold().blue(),
|
||||
"INFO".bold().green(),
|
||||
&format!("Downloading {}", &url.bright_blue())
|
||||
),
|
||||
pg_bar_str
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
.unwrap()
|
||||
.progress_chars("#>-");
|
||||
progress_bar.set_style(progress_style);
|
||||
progress_bar.set_message("Downloading File");
|
||||
|
||||
let mut buffer: Vec<u8> = vec![];
|
||||
let mut downloaded: u64 = 0;
|
||||
let mut stream = response.bytes_stream();
|
||||
|
||||
while let Some(item) = stream.next().await {
|
||||
let chunk = item
|
||||
.or(Err(format!("Error while downloading file")))
|
||||
.unwrap();
|
||||
|
||||
buffer.write_all(chunk.as_ref()).unwrap();
|
||||
let new = std::cmp::min(downloaded + (chunk.len() as u64), content_length);
|
||||
downloaded = new;
|
||||
progress_bar.set_position(new);
|
||||
}
|
||||
progress_bar.finish();
|
||||
info!("Finished downloading {}", url.green());
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
pub async fn download_to_file(client: &Client, url: &str, path: &PathBuf) {
|
||||
let bytes = download_file(client, url).await;
|
||||
fs::write(path, bytes).await.unwrap();
|
||||
}
|
||||
|
||||
pub async fn download_file_prefix<T: Into<String>>(client: &Client, url: T) -> Vec<u8> {
|
||||
let string: String = url.into();
|
||||
let buffer = download_file(client, &string).await;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*
|
||||
pub async fn generate_md5(input: &str) -> String {
|
||||
let hashed_input = md5::compute(input.as_bytes());
|
||||
return format!("{:x}", hashed_input);
|
||||
}*/
|
||||
pub async fn create_folder_if_not_exists(path: &PathBuf) {
|
||||
if !path.exists() {
|
||||
info!("Creating folder {}", path.to_str().unwrap().bright_blue());
|
||||
fs::create_dir_all(path).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_installation_directory() -> PathBuf {
|
||||
return PathBuf::from(data_local_dir().unwrap().to_str().unwrap()).join("Syntax");
|
||||
}
|
||||
|
||||
/* Why was this in the main function i will never know */
|
||||
pub async fn extract_to_dir(zip_file: &Vec<u8>, target_dir: &PathBuf) {
|
||||
let zip_file_cursor = Cursor::new(zip_file);
|
||||
zip_extract::extract(zip_file_cursor, target_dir, false).unwrap();
|
||||
}
|
||||
|
||||
fn get_location_from_file_name<T: AsRef<str>>(file_name: T) -> String {
|
||||
let file_name = file_name.as_ref();
|
||||
for [first, last] in FILES_TO_DOWNLOAD {
|
||||
if first == file_name {
|
||||
return last.to_owned();
|
||||
}
|
||||
}
|
||||
let formated = format!("Is not a valid file {}", file_name);
|
||||
error!("{}", formated);
|
||||
panic!("{}", formated)
|
||||
}
|
||||
|
||||
pub async fn download_and_extract<T: Into<String>, T2: Into<String>, P: Into<PathBuf>>(
|
||||
file_name: T,
|
||||
url_prefix: T2,
|
||||
extract_location: P,
|
||||
) {
|
||||
let http_client = ClientBuilder::default().build().unwrap();
|
||||
let file_name: String = file_name.into();
|
||||
let url_prefix: String = url_prefix.into();
|
||||
let extract_location: PathBuf = extract_location.into();
|
||||
|
||||
let buffer = download_file_prefix(&http_client, format!("{}{file_name}", url_prefix)).await;
|
||||
drop(http_client);
|
||||
drop(url_prefix);
|
||||
let dir = extract_location.join(get_location_from_file_name(&file_name));
|
||||
|
||||
create_dir_all(&dir).await.unwrap();
|
||||
info!("Extracting file {}", file_name);
|
||||
extract_to_dir(&buffer, &dir).await;
|
||||
drop(buffer);
|
||||
|
||||
info!("File {} installed to {:?}", file_name, dir.display());
|
||||
}
|
||||
Loading…
Reference in New Issue