error handling part 1
This commit is contained in:
parent
15f3021701
commit
e661921539
6 changed files with 87 additions and 33 deletions
|
|
@ -27,6 +27,7 @@ zip = { workspace = true }
|
|||
uuid = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
prisma-client-rust = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
|
||||
[features]
|
||||
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use super::{Account, AuthenticationMethod};
|
|||
|
||||
pub(super) struct MicrosoftAuthenticationMethod;
|
||||
impl AuthenticationMethod for MicrosoftAuthenticationMethod {
|
||||
async fn auth<R: Runtime, F>(handle: &AppHandle<R>, stage: F) -> Result<Account, Box<dyn Error>>
|
||||
async fn auth<R: Runtime, F>(handle: &AppHandle<R>, stage: F) -> <Account, Box<dyn Error>>
|
||||
where F: Fn(String, u8, bool) -> () {
|
||||
|
||||
stage("Authenticating with Microsoft".into(), 0, false);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
// Basic Metadata
|
||||
pub const NAME: &str = "OneLauncher";
|
||||
pub const VERSION: &str = "0.1.0";
|
||||
|
||||
// Authentication and HTTP (TODO: env?)
|
||||
pub const USER_AGENT: &str = "OneLauncher/1.0.0 (polyfrost.org)";
|
||||
pub const CLIENT_ID: &str = "9419b7ee-1448-4d1b-b52a-550d8f36ab56";
|
||||
pub const CLIENT_ID: &str = "9419b7ee-1448-4d1b-b52a-550d8f36ab56";
|
||||
|
||||
// Java Downloading
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
use std::{collections::HashMap, env, error::Error, fs, path::PathBuf};
|
||||
use std::{collections::HashMap, env, fs, path::PathBuf};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tauri::{AppHandle, Manager};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::utils::{file, http};
|
||||
use crate::{utils::{file, http}, PolyError, PolyResult};
|
||||
|
||||
use super::{clients::vanilla::{vanilla_manifest, VanillaClient, VanillaManifest}, JavaVersion};
|
||||
|
||||
|
|
@ -61,8 +62,8 @@ pub fn get_game_client(handle: AppHandle, details: GameClientDetails) -> Box<dyn
|
|||
pub trait GameClient: Send + Sync {
|
||||
fn new(handle: AppHandle, details: GameClientDetails) -> Self where Self: Sized;
|
||||
|
||||
async fn get_all_version_urls() -> Result<HashMap<String, String>, Box<dyn Error>> where Self: Sized;
|
||||
async fn get_minecraft_manifest(version: String) -> Result<vanilla_manifest::MinecraftManifest, Box<dyn Error>> where Self: Sized;
|
||||
async fn get_all_version_urls() -> PolyResult<HashMap<String, String>> where Self: Sized;
|
||||
async fn get_minecraft_manifest(version: String) -> PolyResult<vanilla_manifest::MinecraftManifest> where Self: Sized;
|
||||
|
||||
// async fn get_details_from_version(version: String) -> Result<GameClientDetails, Box<dyn Error>> where Self: Sized;
|
||||
|
||||
|
|
@ -72,13 +73,14 @@ pub trait GameClient: Send + Sync {
|
|||
&self.get_details().client_type
|
||||
}
|
||||
|
||||
async fn launch(&self) -> Result<(), Box<dyn Error>>;
|
||||
async fn setup(&self) -> Result<(), Box<dyn Error>>;
|
||||
async fn launch(&self) -> PolyResult<()>;
|
||||
async fn setup(&self) -> PolyResult<()>;
|
||||
|
||||
async fn download_java(&self) -> Result<PathBuf, JavaDownloadError> {
|
||||
async fn download_java(&self) -> PolyResult<PathBuf> {
|
||||
let config_dir = match self.get_handle().path().app_config_dir() {
|
||||
Ok(dir) => dir,
|
||||
Err(_) => return Err(JavaDownloadError::UnsupportedOS)
|
||||
// SURELY THERES A BETTER WAY TO DO THIS IDK LOLL
|
||||
Err(err) => return Err(PolyError::JavaError(JavaDownloadError::UnsupportedOS(err.to_string())))
|
||||
};
|
||||
|
||||
let java_dir = config_dir.join("java");
|
||||
|
|
@ -86,7 +88,7 @@ pub trait GameClient: Send + Sync {
|
|||
if !java_dir.exists() {
|
||||
match fs::create_dir_all(&java_dir) {
|
||||
Ok(_) => (),
|
||||
Err(_) => return Err(JavaDownloadError::PermissionDenied)
|
||||
Err(err) => return Err(PolyError::JavaError(JavaDownloadError::PermissionDenied(err.to_string())))
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -96,7 +98,7 @@ pub trait GameClient: Send + Sync {
|
|||
"windows" => "zip",
|
||||
"macos" => "tar.gz",
|
||||
"linux" => "tar.gz",
|
||||
_ => return Err(JavaDownloadError::UnsupportedOS)
|
||||
_ => return Err(PolyError::JavaError(JavaDownloadError::UnsupportedOS(os.to_string())))
|
||||
};
|
||||
|
||||
let archive_name = format!("zulu-{}.{}", java_version.to_string(), archive_type);
|
||||
|
|
@ -115,29 +117,35 @@ pub trait GameClient: Send + Sync {
|
|||
if let Ok(mut files) = fs::read_dir(&dest) {
|
||||
let file = match files.nth(0) {
|
||||
Some(file) => file.unwrap().path(),
|
||||
None => return Err(JavaDownloadError::NoJavaVersionFound)
|
||||
None => return Err(PolyError::JavaError(JavaDownloadError::NoJavaVersionFound("unable to get the java executable file".to_string())))
|
||||
};
|
||||
|
||||
return Ok(file.join("bin").join("java"));
|
||||
}
|
||||
|
||||
Err(JavaDownloadError::NoJavaVersionFound)
|
||||
Err(PolyError::JavaError(JavaDownloadError::NoJavaVersionFound("unable to download the java executable file".to_string())))
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ModdedGameClient: GameClient {
|
||||
async fn install_mods(&self) -> Result<(), Box<dyn Error>>;
|
||||
async fn install_mods(&self) -> PolyResult<()>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum JavaDownloadError {
|
||||
NoJavaVersionFound,
|
||||
PermissionDenied,
|
||||
UnsupportedOS,
|
||||
UnsupportedArch,
|
||||
ExtractError,
|
||||
DownloadError,
|
||||
#[error("failed to find a valid java version: {0}")]
|
||||
NoJavaVersionFound(String),
|
||||
#[error("failed creating a java directory (try running at an elevated permission): {0}")]
|
||||
PermissionDenied(String),
|
||||
#[error("unable to match your operating system ({0}) with a valid java version")]
|
||||
UnsupportedOS(String),
|
||||
#[error("unable to match your architecture ({0}) with a valid java version")]
|
||||
UnsupportedArch(String),
|
||||
#[error("failed to extract the java executable: {0}")]
|
||||
ExtractError(String),
|
||||
#[error("failed to download the java executable")]
|
||||
DownloadError(String),
|
||||
}
|
||||
|
||||
fn get_arch() -> String {
|
||||
|
|
@ -151,7 +159,7 @@ fn get_arch() -> String {
|
|||
}.to_string()
|
||||
}
|
||||
|
||||
async fn get_java_versions(java_version: &JavaVersion, os: &str, archive_type: &str) -> Result<Value, JavaDownloadError> {
|
||||
async fn get_java_versions(java_version: &JavaVersion, os: &str, archive_type: &str) -> PolyResult<Value> {
|
||||
let url = format!("
|
||||
https://api.azul.com/metadata/v1/zulu/packages/\
|
||||
?java_version={}\
|
||||
|
|
@ -168,38 +176,38 @@ async fn get_java_versions(java_version: &JavaVersion, os: &str, archive_type: &
|
|||
let response = match http::create_client().get(&url).send().await {
|
||||
Ok(response) => match response.json::<serde_json::Value>().await {
|
||||
Ok(json) => json,
|
||||
Err(_) => return Err(JavaDownloadError::NoJavaVersionFound)
|
||||
Err(err) => return Err(PolyError::JavaError(JavaDownloadError::NoJavaVersionFound(err.to_string())))
|
||||
},
|
||||
Err(_) => return Err(JavaDownloadError::NoJavaVersionFound)
|
||||
Err(err) => return Err(PolyError::JavaError(JavaDownloadError::NoJavaVersionFound(err.to_string())))
|
||||
};
|
||||
|
||||
if !response.is_array() || response.as_array().unwrap().is_empty() {
|
||||
return Err(JavaDownloadError::NoJavaVersionFound);
|
||||
return Err(PolyError::JavaError(JavaDownloadError::NoJavaVersionFound("didn't get the expected java api result".to_string())));
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn download(java_version: &JavaVersion, os: &str, archive_type: &str, archive: &PathBuf) -> Result<(), JavaDownloadError> {
|
||||
async fn download(java_version: &JavaVersion, os: &str, archive_type: &str, archive: &PathBuf) -> PolyResult<()> {
|
||||
let response = get_java_versions(java_version, os, archive_type).await?;
|
||||
let latest = response.as_array().unwrap().first().unwrap();
|
||||
let download_url = latest.get("download_url").unwrap().as_str().unwrap();
|
||||
|
||||
if let Err(err) = http::download_file(download_url, archive.as_path()).await {
|
||||
eprintln!("{}", err);
|
||||
return Err(JavaDownloadError::DownloadError);
|
||||
// eprintln!("{}", err);
|
||||
return Err(PolyError::JavaError(JavaDownloadError::DownloadError(err.to_string())));
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract(archive: &PathBuf, dest: &PathBuf) -> Result<(), JavaDownloadError> {
|
||||
fn extract(archive: &PathBuf, dest: &PathBuf) -> PolyResult<()> {
|
||||
if let Err(err) = file::extract_archive(archive.as_path(), dest.as_path()) {
|
||||
eprintln!("{}", err);
|
||||
// eprintln!("{}", err);
|
||||
let _ = fs::remove_file(dest.as_path());
|
||||
return Err(JavaDownloadError::ExtractError);
|
||||
return Err(PolyError::JavaError(JavaDownloadError::ExtractError(err.to_string())));
|
||||
}
|
||||
|
||||
let _ = fs::remove_file(archive.as_path());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
0
src-tauri/src/game/java.rs
Normal file
0
src-tauri/src/game/java.rs
Normal file
|
|
@ -1,4 +1,45 @@
|
|||
use thiserror::Error;
|
||||
|
||||
pub mod auth;
|
||||
pub mod game;
|
||||
pub mod utils;
|
||||
pub mod constants;
|
||||
|
||||
/// A standardized [`Error`] type that is used across the launcher
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PolyError {
|
||||
#[error("a tauri runtime error occured (this should not happen): {0}")]
|
||||
/// Wrapper around [`tauri::Error`] to handle expected Tauri errors.
|
||||
TauriError(#[from] tauri::Error),
|
||||
#[error("failed to manage a tokio semaphore: {0}")]
|
||||
/// Wrapper around [`tokio::sync::AcquireError`] to handle sempahore errors.
|
||||
TokioError(#[from] tokio::sync::AcquireError),
|
||||
#[error("failed to compress a file with flate: {0}")]
|
||||
/// Wrapper around [`flate2::CompressError`] to handle flate compression errors.
|
||||
FlateError(#[from] flate2::CompressError),
|
||||
// im actually the funniest person alive dont @ me
|
||||
#[error("failed to decompress a file with flate: {0}")]
|
||||
/// Wrapper around [`flate2::DecompressError`] to handle flate decompression errors.
|
||||
DeflateError(#[from] flate2::DecompressError),
|
||||
#[error("failed to parse uuids: {0}")]
|
||||
/// Wrapper around [`uuid::Error`] to handle UUID parsing errors.
|
||||
UUIDError(#[from] uuid::Error),
|
||||
#[error("failed to manage serialization of json: {0}")]
|
||||
/// Wrapper around [`serde_json::Error`] to handle Serde JSON parsing errors.
|
||||
SerdeError(#[from] serde_json::Error),
|
||||
#[error("failed to manage writing and reading of files: {0}")]
|
||||
/// Wrapper around [`std::io::Error`] only to be used if a more defined error isn't available (e.g. when using `zip`)
|
||||
IOError(#[from] std::io::Error),
|
||||
#[error("failed to query the database: {0}")]
|
||||
/// Wrapper around [`prisma_client_rust::QueryError`] to handle DB query errors.
|
||||
DBQueryError(#[from] prisma_client_rust::QueryError),
|
||||
#[error("failed to establish a connection to the database: {0}")]
|
||||
/// Wrapper around [`prisma_client_rust::NewClientError`] to handle errors occuring while programmatically connecting to Prisma.
|
||||
DBConnectionError(#[from] prisma_client_rust::NewClientError),
|
||||
#[error("failed to download java: {0}")]
|
||||
/// Wrapper around [`game::client::JavaDownloadError`] to handle Java executable downloading.
|
||||
JavaError(#[from] game::client::JavaDownloadError),
|
||||
}
|
||||
|
||||
/// Alias for a [`Result`] with the error type [`PolyError`].
|
||||
pub type PolyResult<T> = std::result::Result<T, PolyError>;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue