Add more readable errors for the launcher (#319)

This commit is contained in:
Uriel
2022-12-03 03:10:51 -03:00
committed by GitHub
parent 7913b2e839
commit c972bb005d
7 changed files with 396 additions and 78 deletions

243
Cargo.lock generated
View File

@@ -145,6 +145,12 @@ dependencies = [
"memchr",
]
[[package]]
name = "bumpalo"
version = "3.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
[[package]]
name = "bytemuck"
version = "1.12.3"
@@ -243,6 +249,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "clap"
version = "3.2.23"
@@ -1256,6 +1268,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
[[package]]
name = "js-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "json-patch"
version = "0.2.6"
@@ -1402,26 +1423,6 @@ dependencies = [
"adler",
]
[[package]]
name = "native-dialog"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab637f328b31bd0855c43bd38a4a4455e74324d9e74e0aac6a803422f43abc6"
dependencies = [
"block",
"cocoa",
"dirs-next",
"objc",
"objc-foundation",
"objc_id",
"once_cell",
"raw-window-handle 0.4.3",
"thiserror",
"wfd",
"which",
"winapi",
]
[[package]]
name = "ndk"
version = "0.6.0"
@@ -1578,6 +1579,16 @@ version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "open"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2078c0039e6a54a0c42c28faa984e115fb4c2d5bf2208f77d1961002df8576f8"
dependencies = [
"pathdiff",
"windows-sys",
]
[[package]]
name = "os_pipe"
version = "1.1.1"
@@ -1654,6 +1665,12 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
[[package]]
name = "pathdiff"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
[[package]]
name = "percent-encoding"
version = "2.2.0"
@@ -1980,15 +1997,6 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "raw-window-handle"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
dependencies = [
"cty",
]
[[package]]
name = "raw-window-handle"
version = "0.5.0"
@@ -2053,6 +2061,30 @@ dependencies = [
"winapi",
]
[[package]]
name = "rfd"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0149778bd99b6959285b0933288206090c50e2327f47a9c463bfdbf45c8823ea"
dependencies = [
"block",
"dispatch",
"glib-sys",
"gobject-sys",
"gtk-sys",
"js-sys",
"lazy_static",
"log",
"objc",
"objc-foundation",
"objc_id",
"raw-window-handle",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"windows 0.37.0",
]
[[package]]
name = "rustc_version"
version = "0.3.3"
@@ -2302,9 +2334,10 @@ dependencies = [
name = "slimevr_ui"
version = "0.0.0"
dependencies = [
"cfg_aliases",
"clap-verbosity-flag",
"log",
"native-dialog",
"open",
"pretty_env_logger",
"rand 0.8.5",
"serde",
@@ -2312,7 +2345,10 @@ dependencies = [
"tauri",
"tauri-build",
"tauri-plugin-window-state",
"tempfile",
"which",
"win32job",
"winreg",
]
[[package]]
@@ -2469,7 +2505,7 @@ dependencies = [
"parking_lot",
"paste",
"png",
"raw-window-handle 0.5.0",
"raw-window-handle",
"scopeguard",
"serde",
"unicode-segmentation",
@@ -2515,8 +2551,9 @@ dependencies = [
"os_pipe",
"percent-encoding",
"rand 0.8.5",
"raw-window-handle 0.5.0",
"raw-window-handle",
"regex",
"rfd",
"semver 1.0.14",
"serde",
"serde_json",
@@ -2617,7 +2654,7 @@ dependencies = [
"http",
"http-range",
"rand 0.8.5",
"raw-window-handle 0.5.0",
"raw-window-handle",
"serde",
"serde_json",
"tauri-utils",
@@ -2637,7 +2674,7 @@ dependencies = [
"gtk",
"percent-encoding",
"rand 0.8.5",
"raw-window-handle 0.5.0",
"raw-window-handle",
"tauri-runtime",
"tauri-utils",
"uuid 1.2.2",
@@ -3004,6 +3041,82 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "web-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webkit2gtk"
version = "0.18.2"
@@ -3089,16 +3202,6 @@ dependencies = [
"windows-metadata",
]
[[package]]
name = "wfd"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "which"
version = "4.3.0"
@@ -3164,6 +3267,19 @@ dependencies = [
"windows_x86_64_msvc 0.32.0",
]
[[package]]
name = "windows"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
dependencies = [
"windows_aarch64_msvc 0.37.0",
"windows_i686_gnu 0.37.0",
"windows_i686_msvc 0.37.0",
"windows_x86_64_gnu 0.37.0",
"windows_x86_64_msvc 0.37.0",
]
[[package]]
name = "windows"
version = "0.39.0"
@@ -3237,6 +3353,12 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
[[package]]
name = "windows_aarch64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
[[package]]
name = "windows_aarch64_msvc"
version = "0.39.0"
@@ -3255,6 +3377,12 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
[[package]]
name = "windows_i686_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
[[package]]
name = "windows_i686_gnu"
version = "0.39.0"
@@ -3273,6 +3401,12 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
[[package]]
name = "windows_i686_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
[[package]]
name = "windows_i686_msvc"
version = "0.39.0"
@@ -3291,6 +3425,12 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
[[package]]
name = "windows_x86_64_gnu"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.39.0"
@@ -3315,6 +3455,12 @@ version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
[[package]]
name = "windows_x86_64_msvc"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.39.0"
@@ -3327,6 +3473,15 @@ version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]]
name = "winres"
version = "0.1.12"

View File

@@ -40,7 +40,8 @@
"lint": "eslint src/**/*.{js,jsx,ts,tsx,json}",
"lint:fix": "eslint --fix src/**/*.{js,jsx,ts,tsx,json}",
"format": "prettier --write src/**/*.{js,jsx,ts,tsx,css,md,json} --config ./.prettierrc",
"preview-vite": "vite preview"
"preview-vite": "vite preview",
"javaversion-build": "javac src-tauri/src/JavaVersion.java"
},
"eslintConfig": {
"extends": [

View File

@@ -22,17 +22,36 @@ custom-protocol = ["tauri/custom-protocol"]
[build-dependencies]
tauri-build = { version = "1.2", features = [] }
cfg_aliases = "0.1"
[dependencies]
serde_json = "1"
serde = { version = "1", features = ["derive"] }
tauri = { version = "1.2", features = ["cli", "devtools", "fs-all", "path-all", "shell-execute", "window-close", "window-maximize", "window-minimize", "window-set-resizable", "window-set-title", "window-start-dragging", "window-unmaximize", "window-unminimize"] }
tauri = { version = "1.2", features = [
"cli",
"devtools",
"dialog",
"fs-all",
"path-all",
"shell-execute",
"window-close",
"window-maximize",
"window-minimize",
"window-set-resizable",
"window-set-title",
"window-start-dragging",
"window-unmaximize",
"window-unminimize"
] }
pretty_env_logger = "0.4"
log = "0.4"
clap-verbosity-flag = "1"
tauri-plugin-window-state = "0.1.0"
native-dialog = "0.6.3"
rand = "0.8.5"
tempfile = "3"
which = "4.3.0"
open = "3"
[target.'cfg(windows)'.dependencies]
win32job = "1"
winreg = "0.10.1"

View File

@@ -1,3 +1,9 @@
use cfg_aliases::cfg_aliases;
fn main() {
tauri_build::build()
tauri_build::build();
cfg_aliases! {
mobile: { any(target_os = "ios", target_os = "android") },
desktop: { not(any(target_os = "ios", target_os = "android")) }
}
}

Binary file not shown.

View File

@@ -0,0 +1,8 @@
public class JavaVersion {
public static void main (String[] args)
{
var version = Runtime.version().version().get(0);
System.exit(version);
}
}

View File

@@ -1,20 +1,22 @@
#![cfg_attr(
all(not(debug_assertions), windows),
windows_subsystem = "windows"
)]
#![cfg_attr(all(not(debug_assertions), windows), windows_subsystem = "windows")]
use std::env;
use std::ffi::{OsStr, OsString};
use std::io::Write;
use std::panic;
use std::path::PathBuf;
use std::process::{Child, Stdio};
use std::str::FromStr;
use clap::Parser;
use clap_verbosity_flag::{InfoLevel, Verbosity};
use native_dialog::{MessageDialog, MessageType};
use rand::seq::SliceRandom;
use rand::thread_rng;
use tauri::api::clap;
use tauri::api::process::Command;
use rand::{seq::SliceRandom, thread_rng};
use tauri::api::{clap, process::Command};
use tauri::Manager;
use tempfile::Builder;
use which::which_all;
/// It's an i32 because we check it through exit codes of the process
const MINIMUM_JAVA_VERSION: i32 = 17;
static POSSIBLE_TITLES: &[&str] = &[
"Panicking situation",
"looking for spatula",
@@ -35,47 +37,68 @@ struct Cli {
}
fn is_valid_path(path: &PathBuf) -> bool {
let java_folder = path.join("jre");
// Might need to be changed in the future, at least for linux
let server_path = path.join("slimevr.jar");
return java_folder.exists() && server_path.exists();
return server_path.exists();
}
fn get_launch_path(cli: Cli) -> Option<PathBuf> {
let mut path = cli.launch_from_path.unwrap_or_default();
if path.exists() && is_valid_path(&path) {
if is_valid_path(&path) {
return Some(path);
}
path = env::current_dir().unwrap();
if path.exists() && is_valid_path(&path) {
if is_valid_path(&path) {
return Some(path);
}
path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
if path.exists() && is_valid_path(&path) {
if is_valid_path(&path) {
return Some(path);
}
None
}
fn show_error(text: &str) {
MessageDialog::new()
.set_title(&format!(
fn spawn_java(java: &OsStr, java_version: &OsStr) -> std::io::Result<Child> {
std::process::Command::new(java)
.arg(java_version)
.stdin(Stdio::null())
.stderr(Stdio::null())
.stdout(Stdio::null())
.spawn()
}
#[cfg(desktop)]
fn show_error(text: &str) -> bool {
use tauri::api::dialog::{
blocking::MessageDialogBuilder, MessageDialogButtons, MessageDialogKind,
};
MessageDialogBuilder::new(
format!(
"SlimeVR GUI crashed - {}",
POSSIBLE_TITLES.choose(&mut thread_rng()).unwrap()
))
.set_text(text)
.set_type(MessageType::Error)
.show_alert()
.unwrap();
),
text,
)
.buttons(MessageDialogButtons::Ok)
.kind(MessageDialogKind::Error)
.show()
}
#[cfg(mobile)]
fn show_error(text: &str) -> bool {
// needs to do native stuff on mobile
false
}
fn main() {
// Make an error dialog box when panicking
panic::set_hook(Box::new(|panic_info| {
eprintln!("{}", panic_info);
println!("{}", panic_info);
show_error(&panic_info.to_string());
}));
@@ -90,6 +113,7 @@ fn main() {
}
// Ensure child processes die when spawned on windows
// and then check for WebView2's existence
#[cfg(windows)]
{
use win32job::{ExtendedLimitInfo, Job};
@@ -103,6 +127,23 @@ fn main() {
// We don't do anything with the job anymore, but we shouldn't drop it because that would
// terminate our process tree. So we intentionally leak it instead.
std::mem::forget(job);
if !webview2_exists() {
// This makes a dialog appear which let's you press Ok or Cancel
// If you press Ok it will open the SlimeVR installer documentation
use tauri::api::dialog::{
blocking::MessageDialogBuilder, MessageDialogButtons, MessageDialogKind,
};
let confirm = MessageDialogBuilder::new("SlimeVR", "Couldn't find WebView2 installed. You can install it with the SlimeVR installer")
.buttons(MessageDialogButtons::OkCancel)
.kind(MessageDialogKind::Error)
.show();
if confirm {
open::that("https://docs.slimevr.dev/server-setup/installing-and-connecting.html#install-the-latest-slimevr-installer").unwrap();
}
return;
}
}
// Spawn server process
@@ -111,13 +152,22 @@ fn main() {
let stdout_recv = if let Some(p) = run_path {
log::info!("Server found on path: {}", p.to_str().unwrap());
let java_folder = p.join("jre");
let (recv, _child) =
Command::new(java_folder.join("bin/java").to_str().unwrap())
.current_dir(p)
.args(["-Xmx512M", "-jar", "slimevr.jar", "--no-gui"])
.spawn()
.expect("Unable to start the server jar");
// Check if any Java already installed is compatible
let jre = p.join("jre/bin/java");
let java_bin = jre
.exists()
.then(|| jre.into_os_string())
.or_else(|| valid_java_paths().first().map(|x| x.0.to_owned()));
if let None = java_bin {
show_error(&format!("Couldn't find a compatible Java version, please download Java {} or higher", MINIMUM_JAVA_VERSION));
return;
};
let (recv, _child) = Command::new(java_bin.unwrap().to_string_lossy())
.current_dir(p)
.args(["-Xmx512M", "-jar", "slimevr.jar", "--no-gui"])
.spawn()
.expect("Unable to start the server jar");
Some(recv)
} else {
log::warn!("No server found. We will not start the server.");
@@ -157,3 +207,82 @@ fn main() {
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[cfg(windows)]
/// Check if WebView2 exists
fn webview2_exists() -> bool {
use winreg::enums::*;
use winreg::RegKey;
// First on the machine itself
let machine: Option<String> = RegKey::predef(HKEY_LOCAL_MACHINE)
.open_subkey(r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}")
.map(|r| r.get_value("pv").ok()).ok().flatten();
let mut exists = false;
if let Some(version) = machine {
exists = version.split('.').any(|x| x != "0");
}
// Then in the current user
if !exists {
let user: Option<String> = RegKey::predef(HKEY_CURRENT_USER)
.open_subkey(
r"Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}",
)
.map(|r| r.get_value("pv").ok())
.ok()
.flatten();
if let Some(version) = user {
exists = version.split('.').any(|x| x != "0");
}
}
exists
}
fn valid_java_paths() -> Vec<(OsString, i32)> {
let mut file = Builder::new()
.suffix(".class")
.tempfile()
.expect("Couldn't generate .class file");
file.write_all(include_bytes!("JavaVersion.class"))
.expect("Couldn't write to .class file");
let java_version = file.into_temp_path();
// Check if main Java is a supported version
let main_java = if let Ok(java_home) = std::env::var("JAVA_HOME") {
PathBuf::from(java_home).join("bin/java").into_os_string()
} else {
OsString::from_str("java").unwrap()
};
if let Some(main_child) = spawn_java(&main_java, java_version.as_os_str())
.expect("Couldn't spawn the main Java binary")
.wait()
.expect("Couldn't execute the main Java binary")
.code()
{
if main_child >= MINIMUM_JAVA_VERSION {
return vec![(main_java, main_child)];
}
}
// Otherwise check if anything else is a supported version
let mut childs = vec![];
for java in which_all("java").unwrap() {
let res = spawn_java(java.as_os_str(), java_version.as_os_str());
match res {
Ok(child) => childs.push((java.into_os_string(), child)),
Err(e) => println!("Error on trying to spawn a Java executable: {}", e),
}
}
childs
.into_iter()
.filter_map(|(p, mut c)| {
c.wait()
.expect("Failed on executing a Java executable")
.code()
.map(|code| (p, code))
.filter(|(_p, code)| *code >= MINIMUM_JAVA_VERSION)
})
.collect()
}