error handling part 1.5

This commit is contained in:
Pauline 2024-03-23 05:11:54 +01:00
parent e661921539
commit a8e6c2449b
No known key found for this signature in database
GPG key ID: 722BB181973296AE
7 changed files with 36 additions and 23 deletions

View file

@ -28,6 +28,7 @@ tar = { version = "0.4" }
zip = { version = "0.6" }
async-trait = { version = "0.1" }
thiserror = { version = "1" }
anyhow = { version = "1" }
[profile.dev]
# Make compilation faster on macOS

View file

@ -28,6 +28,7 @@ uuid = { workspace = true }
async-trait = { workspace = true }
prisma-client-rust = { workspace = true }
thiserror = { workspace = true }
anyhow = { workspace = true }
[features]
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!

View file

@ -4,13 +4,13 @@ use serde_json::json;
use tauri::{AppHandle, Runtime};
use tauri_plugin_shell::ShellExt;
use crate::{constants::CLIENT_ID, utils::http::create_client};
use crate::{constants::CLIENT_ID, utils::http::create_client, PolyResult};
use super::{Account, AuthenticationMethod};
pub(super) struct MicrosoftAuthenticationMethod;
impl AuthenticationMethod for MicrosoftAuthenticationMethod {
async fn auth<R: Runtime, F>(handle: &AppHandle<R>, stage: F) -> <Account, Box<dyn Error>>
async fn auth<R: Runtime, F>(handle: &AppHandle<R>, stage: F) -> PolyResult<Account>
where F: Fn(String, u8, bool) -> () {
stage("Authenticating with Microsoft".into(), 0, false);

View file

@ -1,9 +1,9 @@
use std::error::Error;
use serde::{Deserialize, Serialize};
use tauri::{plugin::TauriPlugin, AppHandle, Manager, Runtime};
use tauri_plugin_http::reqwest::Client;
use crate::{PolyError, PolyResult};
use self::microsoft_auth::MicrosoftAuthenticationMethod;
mod microsoft_auth;
@ -27,10 +27,10 @@ pub struct AccountSkin {
pub trait AuthenticationMethod {
/// Authenticate with a given method. Stage is a function that takes a string and a u8.
/// The string is the message to display to the user, and the u8 is the progress of the authentication.
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) -> PolyResult<Account>
where F: Fn(String, u8, bool) -> ();
async fn get_profile(access_token: String) -> Result<Account, Box<dyn Error>> {
async fn get_profile(access_token: String) -> PolyResult<Account> {
let response = Client::new()
.get("https://api.minecraftservices.com/minecraft/profile")
.header("Authorization", format!("Bearer {}", access_token))
@ -39,7 +39,7 @@ pub trait AuthenticationMethod {
let response = response.json::<serde_json::Value>().await?;
if let Some(error) = response.get("error") {
return Err(error.to_string().into());
return Err(PolyError(error.to_string()));
}
let account = serde_json::from_value::<Account>(response)?;
@ -64,4 +64,4 @@ async fn login_msa<R: tauri::Runtime>(app: tauri::AppHandle<R>) -> Result<Accoun
Ok(account) => Ok(account),
Err(err) => Err(err.to_string())
}
}
}

View file

@ -36,9 +36,15 @@ pub enum PolyError {
#[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 establish a HTTP connection: {0}")]
/// Wrapper around [`reqwest::Error`] to handle HTTP errors.
HTTPError(#[from] tauri_plugin_http::reqwest::Error),
#[error("failed to download java: {0}")]
/// Wrapper around [`game::client::JavaDownloadError`] to handle Java executable downloading.
JavaError(#[from] game::client::JavaDownloadError),
#[error("file management failed: {0}")]
/// Wrapper around [`utils::file::FileError`] to handle file management errors.
FileError(#[from] utils::file::FileError),
}
/// Alias for a [`Result`] with the error type [`PolyError`].

View file

@ -1,27 +1,32 @@
use std::{error::Error, fs::File, path::Path};
use std::{fs::File, path::Path};
use anyhow::anyhow;
use thiserror::Error;
pub fn extract_archive(archive: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
use crate::{PolyError, PolyResult};
pub fn extract_archive(archive: &Path, dest: &Path) -> PolyResult<()> {
let ext = match archive.extension() {
Some(ext) => ext.to_str().unwrap(),
None => return Err("Archive has no extension".into())
None => return Err(anyhow!("unsupported archive type"))
};
match ext {
"zip" => extract_zip(archive, dest),
"gz" => extract_tar_gz(archive, dest),
_ => Err("Unsupported archive type".into())
_ => Err(PolyError::FileError(FileError::UnsupportedArch))
}
}
pub fn extract_zip(archive: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
let mut archive = zip::ZipArchive::new(File::open(archive)?)?;
archive.extract(dest)?;
pub fn extract_zip(archive: &Path, dest: &Path) -> PolyResult<()> {
let mut archive = zip::ZipArchive::new(File::open(archive)?)
.map_err(|err| PolyError::FileError(FileError::ZipError(err)));
archive?.extract(dest).map_err(|err| PolyError::FileError(FileError::ZipError(err)));
Ok(())
}
pub fn extract_tar_gz(archive: &Path, dest: &Path) -> Result<(), Box<dyn Error>> {
pub fn extract_tar_gz(archive: &Path, dest: &Path) -> PolyResult<()> {
let tar_gz = flate2::read::GzDecoder::new(File::open(archive)?);
let mut archive = tar::Archive::new(tar_gz);
archive.unpack(dest)?;
Ok(())
}
}

View file

@ -1,17 +1,17 @@
use std::{error::Error, fs::File, io::{self, Cursor}, path::Path};
use std::{fs::File, io::{self, Cursor}, path::Path};
use tauri_plugin_http::reqwest::{Client, ClientBuilder};
use crate::constants::USER_AGENT;
use crate::{constants::USER_AGENT, PolyError, PolyResult};
pub fn create_client() -> Client {
pub fn create_client() -> PolyResult<Client> {
ClientBuilder::new()
.user_agent(USER_AGENT)
.build().expect("Failed to create HTTP client. Please report this issue on GitHub.")
.build().map_err(|err| PolyError::HTTPError(err))
}
pub async fn download_file(url: &str, path: &Path) -> Result<(), Box<dyn Error>> {
let response = create_client().get(url).send().await?;
pub async fn download_file(url: &str, path: &Path) -> PolyResult<()> {
let response = create_client()?.get(url).send().await?;
let mut file = File::create(path)?;
let mut content = Cursor::new(response.bytes().await?);
io::copy(&mut content, &mut file)?;