mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-10 04:22:13 +10:00
feat(errors): Using SerializeDisplay for better error management with Result
This commit is contained in:
@ -6,7 +6,7 @@ use std::{
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{database::settings::Settings, error::user_error::UserValue, DB};
|
||||
use crate::{database::settings::Settings, download_manager::{download_manager::DownloadManagerSignal, internal_error::InternalError}, DB};
|
||||
|
||||
use super::{db::DATA_ROOT_DIR, debug::SystemData};
|
||||
|
||||
@ -27,16 +27,16 @@ pub fn delete_download_dir(index: usize) {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn add_download_dir(new_dir: PathBuf) -> UserValue<(), Error> {
|
||||
pub fn add_download_dir(new_dir: PathBuf) -> Result<(), InternalError<()>> {
|
||||
// Check the new directory is all good
|
||||
let new_dir_path = Path::new(&new_dir);
|
||||
if new_dir_path.exists() {
|
||||
let dir_contents = new_dir_path.read_dir()?;
|
||||
if dir_contents.count() != 0 {
|
||||
return UserValue::Err(Error::new(
|
||||
return Err(Error::new(
|
||||
ErrorKind::DirectoryNotEmpty,
|
||||
"Selected directory cannot contain any existing files",
|
||||
));
|
||||
).into());
|
||||
}
|
||||
} else {
|
||||
create_dir_all(new_dir_path)?;
|
||||
@ -45,16 +45,16 @@ pub fn add_download_dir(new_dir: PathBuf) -> UserValue<(), Error> {
|
||||
// Add it to the dictionary
|
||||
let mut lock = DB.borrow_data_mut().unwrap();
|
||||
if lock.applications.install_dirs.contains(&new_dir) {
|
||||
return UserValue::Err(Error::new(
|
||||
return Err(Error::new(
|
||||
ErrorKind::AlreadyExists,
|
||||
"Selected directory already exists in database",
|
||||
));
|
||||
).into());
|
||||
}
|
||||
lock.applications.install_dirs.push(new_dir);
|
||||
drop(lock);
|
||||
DB.save().unwrap();
|
||||
|
||||
UserValue::Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
27
src-tauri/src/download_manager/internal_error.rs
Normal file
27
src-tauri/src/download_manager/internal_error.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use std::{fmt::Display, io, sync::mpsc::SendError};
|
||||
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
#[derive(SerializeDisplay)]
|
||||
pub enum InternalError<T> {
|
||||
IOError(io::Error),
|
||||
SignalError(SendError<T>)
|
||||
}
|
||||
impl<T> Display for InternalError<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
InternalError::IOError(error) => write!(f, "{}", error.to_string()),
|
||||
InternalError::SignalError(send_error) => write!(f, "{}", send_error.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> From<SendError<T>> for InternalError<T> {
|
||||
fn from(value: SendError<T>) -> Self {
|
||||
InternalError::SignalError(value)
|
||||
}
|
||||
}
|
||||
impl<T> From<io::Error> for InternalError<T> {
|
||||
fn from(value: io::Error) -> Self {
|
||||
InternalError::IOError(value)
|
||||
}
|
||||
}
|
||||
@ -7,3 +7,4 @@ pub mod downloadable_metadata;
|
||||
pub mod progress_object;
|
||||
pub mod queue;
|
||||
pub mod rolling_progress_updates;
|
||||
pub mod internal_error;
|
||||
@ -3,10 +3,12 @@ use std::{
|
||||
io,
|
||||
};
|
||||
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
use super::{remote_access_error::RemoteAccessError, setup_error::SetupError};
|
||||
|
||||
// TODO: Rename / separate from downloads
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, SerializeDisplay)]
|
||||
pub enum ApplicationDownloadError {
|
||||
Communication(RemoteAccessError),
|
||||
Checksum,
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
#[derive(SerializeDisplay)]
|
||||
pub enum LibraryError {
|
||||
MetaNotFound(String),
|
||||
}
|
||||
|
||||
@ -4,4 +4,3 @@ pub mod library_error;
|
||||
pub mod process_error;
|
||||
pub mod remote_access_error;
|
||||
pub mod setup_error;
|
||||
pub mod user_error;
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
use std::{fmt::Display, io::Error};
|
||||
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
#[derive(SerializeDisplay)]
|
||||
pub enum ProcessError {
|
||||
SetupRequired,
|
||||
NotInstalled,
|
||||
|
||||
@ -5,11 +5,12 @@ use std::{
|
||||
};
|
||||
|
||||
use http::StatusCode;
|
||||
use serde_with::SerializeDisplay;
|
||||
use url::ParseError;
|
||||
|
||||
use super::drop_server_error::DropServerError;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, SerializeDisplay)]
|
||||
pub enum RemoteAccessError {
|
||||
FetchError(Arc<reqwest::Error>),
|
||||
ParsingError(ParseError),
|
||||
|
||||
@ -1,66 +0,0 @@
|
||||
use std::{
|
||||
fmt::Display,
|
||||
ops::{FromResidual, Try},
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UserValue<T, D>
|
||||
where
|
||||
T: Serialize,
|
||||
D: Display,
|
||||
{
|
||||
Ok(T),
|
||||
Err(D),
|
||||
}
|
||||
impl<T: Serialize, D: Display> Serialize for UserValue<T, D> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
match self {
|
||||
UserValue::Ok(data) => data.serialize(serializer),
|
||||
UserValue::Err(err) => serializer.serialize_str(err.to_string().as_ref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Serialize, D: Display> From<Result<T, D>> for UserValue<T, D> {
|
||||
fn from(value: Result<T, D>) -> Self {
|
||||
match value {
|
||||
Ok(data) => UserValue::Ok(data),
|
||||
Err(data) => UserValue::Err(data),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Serialize, D: Display> Try for UserValue<T, D> {
|
||||
type Output = T;
|
||||
|
||||
type Residual = D;
|
||||
|
||||
fn from_output(output: Self::Output) -> Self {
|
||||
Self::Ok(output)
|
||||
}
|
||||
|
||||
fn branch(self) -> std::ops::ControlFlow<Self::Residual, Self::Output> {
|
||||
match self {
|
||||
UserValue::Ok(data) => std::ops::ControlFlow::Continue(data),
|
||||
UserValue::Err(e) => std::ops::ControlFlow::Break(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Serialize, D: Display> FromResidual for UserValue<T, D> {
|
||||
fn from_residual(residual: <Self as std::ops::Try>::Residual) -> Self {
|
||||
UserValue::Err(residual)
|
||||
}
|
||||
}
|
||||
impl<T: Serialize, D: Display, U> FromResidual<Result<U, D>> for UserValue<T, D> {
|
||||
fn from_residual(residual: Result<U, D>) -> Self {
|
||||
match residual {
|
||||
Ok(_) => unreachable!(),
|
||||
Err(e) => UserValue::Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use tauri::AppHandle;
|
||||
|
||||
use crate::{
|
||||
error::{
|
||||
library_error::LibraryError, remote_access_error::RemoteAccessError, user_error::UserValue,
|
||||
library_error::LibraryError, remote_access_error::RemoteAccessError,
|
||||
},
|
||||
games::library::{get_current_meta, uninstall_game_logic},
|
||||
AppState,
|
||||
@ -19,16 +19,16 @@ use super::{
|
||||
};
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_library(app: AppHandle) -> UserValue<Vec<Game>, RemoteAccessError> {
|
||||
fetch_library_logic(app).into()
|
||||
pub fn fetch_library(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
|
||||
fetch_library_logic(app)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_game(
|
||||
game_id: String,
|
||||
app: tauri::AppHandle,
|
||||
) -> UserValue<FetchGameStruct, RemoteAccessError> {
|
||||
fetch_game_logic(game_id, app).into()
|
||||
) -> Result<FetchGameStruct, RemoteAccessError> {
|
||||
fetch_game_logic(game_id, app)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -37,21 +37,21 @@ pub fn fetch_game_status(id: String) -> GameStatusWithTransient {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn uninstall_game(game_id: String, app_handle: AppHandle) -> UserValue<(), LibraryError> {
|
||||
pub fn uninstall_game(game_id: String, app_handle: AppHandle) -> Result<(), LibraryError> {
|
||||
let meta = match get_current_meta(&game_id) {
|
||||
Some(data) => data,
|
||||
None => return UserValue::Err(LibraryError::MetaNotFound(game_id)),
|
||||
None => return Err(LibraryError::MetaNotFound(game_id)),
|
||||
};
|
||||
println!("{:?}", meta);
|
||||
uninstall_game_logic(meta, &app_handle);
|
||||
|
||||
UserValue::Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_game_verion_options(
|
||||
game_id: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> UserValue<Vec<GameVersionOption>, RemoteAccessError> {
|
||||
fetch_game_verion_options_logic(game_id, state).into()
|
||||
) -> Result<Vec<GameVersionOption>, RemoteAccessError> {
|
||||
fetch_game_verion_options_logic(game_id, state)
|
||||
}
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
use std::sync::{mpsc::SendError, Arc, Mutex};
|
||||
|
||||
use crate::{
|
||||
download_manager::{download_manager::DownloadManagerSignal, downloadable::Downloadable},
|
||||
error::user_error::UserValue,
|
||||
download_manager::{download_manager::DownloadManagerSignal, downloadable::Downloadable, internal_error::InternalError},
|
||||
AppState,
|
||||
};
|
||||
|
||||
@ -14,7 +13,7 @@ pub fn download_game(
|
||||
game_version: String,
|
||||
install_dir: usize,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> UserValue<(), SendError<DownloadManagerSignal>> {
|
||||
) -> Result<(), InternalError<DownloadManagerSignal>> {
|
||||
let sender = state.lock().unwrap().download_manager.get_sender();
|
||||
let game_download_agent = Arc::new(Box::new(GameDownloadAgent::new(
|
||||
game_id,
|
||||
@ -22,10 +21,9 @@ pub fn download_game(
|
||||
install_dir,
|
||||
sender,
|
||||
)) as Box<dyn Downloadable + Send + Sync>);
|
||||
state
|
||||
Ok(state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.download_manager
|
||||
.queue_download(game_download_agent)
|
||||
.into()
|
||||
.queue_download(game_download_agent)?)
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ impl GameDownloadAgent {
|
||||
let manifest_url = base_url
|
||||
.join(
|
||||
format!(
|
||||
"/api/v1/client/metadata/manifest?id={}&version={}",
|
||||
"/api/v1/client/game/manifest?id={}&version={}",
|
||||
self.id,
|
||||
encode(&self.version)
|
||||
)
|
||||
|
||||
@ -180,7 +180,7 @@ pub fn fetch_game_verion_options_logic(
|
||||
) -> Result<Vec<GameVersionOption>, RemoteAccessError> {
|
||||
let client = reqwest::blocking::Client::new();
|
||||
|
||||
let response = make_request(&client, &["/api/v1/client/metadata/versions"], &[("id", &game_id)], |r| {
|
||||
let response = make_request(&client, &["/api/v1/client/game/versions"], &[("id", &game_id)], |r| {
|
||||
r.header("Authorization", generate_authorization_header())
|
||||
})?.send()?;
|
||||
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::{
|
||||
error::{process_error::ProcessError, user_error::UserValue},
|
||||
AppState, DB,
|
||||
error::process_error::ProcessError,
|
||||
AppState,
|
||||
};
|
||||
|
||||
#[tauri::command]
|
||||
pub fn launch_game(
|
||||
id: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> UserValue<(), ProcessError> {
|
||||
) -> Result<(), ProcessError> {
|
||||
let state_lock = state.lock().unwrap();
|
||||
let mut process_manager_lock = state_lock.process_manager.lock().unwrap();
|
||||
|
||||
@ -21,24 +21,23 @@ pub fn launch_game(
|
||||
|
||||
match process_manager_lock.launch_process(id) {
|
||||
Ok(_) => {}
|
||||
Err(e) => return UserValue::Err(e),
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
drop(process_manager_lock);
|
||||
drop(state_lock);
|
||||
|
||||
UserValue::Ok(())
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn kill_game(
|
||||
game_id: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> UserValue<(), ProcessError> {
|
||||
) -> Result<(), ProcessError> {
|
||||
let state_lock = state.lock().unwrap();
|
||||
let mut process_manager_lock = state_lock.process_manager.lock().unwrap();
|
||||
process_manager_lock
|
||||
.kill_game(game_id)
|
||||
.map_err(ProcessError::IOError)
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ use tauri::{AppHandle, Emitter, Manager};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
error::{remote_access_error::RemoteAccessError, user_error::UserValue},
|
||||
error::remote_access_error::RemoteAccessError,
|
||||
AppState, AppStatus, DB,
|
||||
};
|
||||
|
||||
@ -17,12 +17,12 @@ use super::{
|
||||
pub fn use_remote(
|
||||
url: String,
|
||||
state: tauri::State<'_, Mutex<AppState<'_>>>,
|
||||
) -> UserValue<(), RemoteAccessError> {
|
||||
UserValue::Ok(use_remote_logic(url, state)?)
|
||||
) -> Result<(), RemoteAccessError> {
|
||||
Ok(use_remote_logic(url, state)?)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn gen_drop_url(path: String) -> UserValue<String, RemoteAccessError> {
|
||||
pub fn gen_drop_url(path: String) -> Result<String, RemoteAccessError> {
|
||||
let base_url = {
|
||||
let handle = DB.borrow_data().unwrap();
|
||||
|
||||
@ -31,7 +31,7 @@ pub fn gen_drop_url(path: String) -> UserValue<String, RemoteAccessError> {
|
||||
|
||||
let url = base_url.join(&path).unwrap();
|
||||
|
||||
UserValue::Ok(url.to_string())
|
||||
Ok(url.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@ -67,7 +67,7 @@ pub fn retry_connect(state: tauri::State<'_, Mutex<AppState>>) {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn auth_initiate() -> UserValue<(), RemoteAccessError> {
|
||||
pub fn auth_initiate() -> Result<(), RemoteAccessError> {
|
||||
auth_initiate_logic().into()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user