mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-14 00:31:33 +10:00
style(downloads): Made all errors type-based
Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
@ -93,9 +93,7 @@ fn recieve_handshake_logic(app: &AppHandle, path: String) -> Result<(), RemoteAc
|
||||
let path_chunks: Vec<&str> = path.split("/").collect();
|
||||
if path_chunks.len() != 3 {
|
||||
app.emit("auth/failed", ()).unwrap();
|
||||
return Err(RemoteAccessError::GenericErrror(
|
||||
"Invalid number of handshake chunks".to_string(),
|
||||
));
|
||||
return Err(RemoteAccessError::InvalidResponse);
|
||||
}
|
||||
|
||||
let base_url = {
|
||||
@ -165,9 +163,7 @@ async fn auth_initiate_wrapper() -> Result<(), RemoteAccessError> {
|
||||
let response = client.post(endpoint.to_string()).json(&body).send().await?;
|
||||
|
||||
if response.status() != 200 {
|
||||
return Err("Failed to create redirect URL. Please try again later."
|
||||
.to_string()
|
||||
.into());
|
||||
return Err(RemoteAccessError::InvalidRedirect);
|
||||
}
|
||||
|
||||
let redir_url = response.text().await?;
|
||||
|
||||
@ -28,21 +28,26 @@ pub struct GameDownloadAgent {
|
||||
pub progress: ProgressObject,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub enum GameDownloadError {
|
||||
CommunicationError(RemoteAccessError),
|
||||
ChecksumError,
|
||||
SetupError(String),
|
||||
LockError,
|
||||
Communication(RemoteAccessError),
|
||||
Checksum,
|
||||
Setup(SetupError),
|
||||
Lock,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SetupError {
|
||||
Context
|
||||
}
|
||||
|
||||
impl Display for GameDownloadError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
GameDownloadError::CommunicationError(error) => write!(f, "{}", error),
|
||||
GameDownloadError::SetupError(error) => write!(f, "{}", error),
|
||||
GameDownloadError::LockError => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
|
||||
GameDownloadError::ChecksumError => write!(f, "Checksum failed to validate for download"),
|
||||
GameDownloadError::Communication(error) => write!(f, "{}", error),
|
||||
GameDownloadError::Setup(error) => write!(f, "{:?}", error),
|
||||
GameDownloadError::Lock => write!(f, "Failed to acquire lock. Something has gone very wrong internally. Please restart the application"),
|
||||
GameDownloadError::Checksum => write!(f, "Checksum failed to validate for download"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,13 +119,8 @@ impl GameDownloadAgent {
|
||||
.unwrap();
|
||||
|
||||
if response.status() != 200 {
|
||||
return Err(GameDownloadError::CommunicationError(
|
||||
format!(
|
||||
"Failed to download game manifest: {} {}",
|
||||
response.status(),
|
||||
response.text().unwrap()
|
||||
)
|
||||
.into(),
|
||||
return Err(GameDownloadError::Communication(
|
||||
RemoteAccessError::ManifestDownloadFailed(response.status(), response.text().unwrap())
|
||||
));
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ impl GameDownloadAgent {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(GameDownloadError::LockError)
|
||||
Err(GameDownloadError::Lock)
|
||||
}
|
||||
|
||||
pub fn generate_contexts(&self) -> Result<(), GameDownloadError> {
|
||||
@ -194,9 +194,7 @@ impl GameDownloadAgent {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Err(GameDownloadError::SetupError(
|
||||
"Failed to generate download contexts".to_owned(),
|
||||
))
|
||||
Err(GameDownloadError::Setup(SetupError::Context))
|
||||
}
|
||||
|
||||
pub fn run(&self) {
|
||||
|
||||
@ -1,52 +1,38 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use crate::AppState;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{AppError, AppState};
|
||||
|
||||
#[tauri::command]
|
||||
pub fn download_game(
|
||||
game_id: String,
|
||||
game_version: String,
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> Result<(), String> {
|
||||
/*
|
||||
info!("beginning game download...");
|
||||
) -> Result<(), AppError> {
|
||||
|
||||
let mut download_agent = GameDownloadAgent::new(game_id.clone(), game_version.clone(), 0);
|
||||
// Setup download requires mutable
|
||||
download_agent.setup_download().unwrap();
|
||||
|
||||
let mut lock: std::sync::MutexGuard<'_, AppState> = state.lock().unwrap();
|
||||
let download_agent_ref = Arc::new(download_agent);
|
||||
lock.download_manager
|
||||
.insert(game_id, download_agent_ref.clone());
|
||||
|
||||
// Run it in another thread
|
||||
spawn(move || {
|
||||
// Run doesn't require mutable
|
||||
download_agent_ref.clone().run();
|
||||
});
|
||||
*/
|
||||
state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.download_manager
|
||||
.queue_game(game_id, game_version, 0)
|
||||
.unwrap();
|
||||
Ok(())
|
||||
.map_err(|_| AppError::Signal)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_current_game_download_progress(
|
||||
state: tauri::State<'_, Mutex<AppState>>,
|
||||
) -> Result<f64, String> {
|
||||
let progress = state
|
||||
) -> Result<f64, AppError> {
|
||||
match state
|
||||
.lock()
|
||||
.unwrap()
|
||||
.download_manager
|
||||
.get_current_game_download_progress()
|
||||
.unwrap_or(0.0);
|
||||
{
|
||||
Some(progress) => Ok(progress),
|
||||
None => Err(AppError::DoesNotExist),
|
||||
}
|
||||
|
||||
Ok(progress)
|
||||
}
|
||||
/*
|
||||
fn use_download_agent(
|
||||
|
||||
@ -148,7 +148,7 @@ pub fn download_game_chunk(
|
||||
.get(chunk_url)
|
||||
.header("Authorization", header)
|
||||
.send()
|
||||
.map_err(|e| GameDownloadError::CommunicationError(e.into()))?;
|
||||
.map_err(|e| GameDownloadError::Communication(e.into()))?;
|
||||
|
||||
let mut destination = DropWriter::new(ctx.path);
|
||||
|
||||
@ -160,11 +160,7 @@ pub fn download_game_chunk(
|
||||
|
||||
let content_length = response.content_length();
|
||||
if content_length.is_none() {
|
||||
return Err(GameDownloadError::CommunicationError(
|
||||
RemoteAccessError::GenericErrror(
|
||||
"Invalid download endpoint, missing Content-Length header.".to_owned(),
|
||||
),
|
||||
));
|
||||
return Err(GameDownloadError::Communication(RemoteAccessError::InvalidResponse));
|
||||
}
|
||||
|
||||
let mut pipeline = DropDownloadPipeline::new(
|
||||
@ -184,7 +180,7 @@ pub fn download_game_chunk(
|
||||
|
||||
let res = hex::encode(checksum.0);
|
||||
if res != ctx.checksum {
|
||||
return Err(GameDownloadError::ChecksumError);
|
||||
return Err(GameDownloadError::Checksum);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
|
||||
@ -11,7 +11,7 @@ use log::info;
|
||||
|
||||
use super::{
|
||||
download_agent::{GameDownloadAgent, GameDownloadError},
|
||||
download_manager_interface::{AgentInterfaceData, DownloadManagerInterface},
|
||||
download_manager_interface::{AgentInterfaceData, DownloadManager},
|
||||
download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag},
|
||||
progress_object::ProgressObject,
|
||||
};
|
||||
@ -53,7 +53,7 @@ Behold, my madness - quexeky
|
||||
|
||||
*/
|
||||
|
||||
pub struct DownloadManager {
|
||||
pub struct DownloadManagerBuilder {
|
||||
download_agent_registry: HashMap<String, Arc<GameDownloadAgent>>,
|
||||
download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
|
||||
command_receiver: Receiver<DownloadManagerSignal>,
|
||||
@ -85,9 +85,8 @@ pub enum DownloadManagerStatus {
|
||||
Downloading,
|
||||
Paused,
|
||||
Empty,
|
||||
Error(GameDownloadError),
|
||||
Error,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub enum GameDownloadStatus {
|
||||
Downloading,
|
||||
Paused,
|
||||
@ -95,8 +94,8 @@ pub enum GameDownloadStatus {
|
||||
Error(GameDownloadError),
|
||||
}
|
||||
|
||||
impl DownloadManager {
|
||||
pub fn generate() -> DownloadManagerInterface {
|
||||
impl DownloadManagerBuilder {
|
||||
pub fn build() -> DownloadManager {
|
||||
let queue = Arc::new(Mutex::new(VecDeque::new()));
|
||||
let (command_sender, command_receiver) = channel();
|
||||
let active_progress = Arc::new(Mutex::new(None));
|
||||
@ -115,7 +114,7 @@ impl DownloadManager {
|
||||
|
||||
let terminator = spawn(|| manager.manage_queue());
|
||||
|
||||
DownloadManagerInterface::new(terminator, queue, active_progress, command_sender)
|
||||
DownloadManager::new(terminator, queue, active_progress, command_sender)
|
||||
}
|
||||
|
||||
fn manage_queue(mut self) -> Result<(), ()> {
|
||||
@ -238,8 +237,8 @@ impl DownloadManager {
|
||||
fn manage_error_signal(&self, error: GameDownloadError) {
|
||||
let current_status = self.current_game_interface.clone().unwrap();
|
||||
let mut lock = current_status.status.lock().unwrap();
|
||||
*lock = GameDownloadStatus::Error(error.clone());
|
||||
self.set_status(DownloadManagerStatus::Error(error));
|
||||
*lock = GameDownloadStatus::Error(error);
|
||||
self.set_status(DownloadManagerStatus::Error);
|
||||
}
|
||||
fn set_status(&self, status: DownloadManagerStatus) {
|
||||
*self.status.lock().unwrap() = status;
|
||||
|
||||
@ -26,7 +26,7 @@ use super::{
|
||||
/// The actual download queue may be accessed through the .edit() function,
|
||||
/// which provides raw access to the underlying queue.
|
||||
/// THIS EDITING IS BLOCKING!!!
|
||||
pub struct DownloadManagerInterface {
|
||||
pub struct DownloadManager {
|
||||
terminator: JoinHandle<Result<(), ()>>,
|
||||
download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
|
||||
progress: Arc<Mutex<Option<ProgressObject>>>,
|
||||
@ -45,7 +45,7 @@ impl From<Arc<GameDownloadAgent>> for AgentInterfaceData {
|
||||
}
|
||||
}
|
||||
|
||||
impl DownloadManagerInterface {
|
||||
impl DownloadManager {
|
||||
pub fn new(
|
||||
terminator: JoinHandle<Result<(), ()>>,
|
||||
download_queue: Arc<Mutex<VecDeque<Arc<AgentInterfaceData>>>>,
|
||||
|
||||
@ -12,13 +12,13 @@ use crate::db::DatabaseImpls;
|
||||
use auth::{auth_initiate, generate_authorization_header, recieve_handshake};
|
||||
use db::{add_new_download_dir, DatabaseInterface, DATA_ROOT_DIR};
|
||||
use downloads::download_commands::*;
|
||||
use downloads::download_manager::DownloadManager;
|
||||
use downloads::download_manager_interface::DownloadManagerInterface;
|
||||
use downloads::download_manager::DownloadManagerBuilder;
|
||||
use downloads::download_manager_interface::DownloadManager;
|
||||
use env_logger::Env;
|
||||
use http::{header::*, response::Builder as ResponseBuilder};
|
||||
use library::{fetch_game, fetch_library, Game};
|
||||
use log::info;
|
||||
use remote::{gen_drop_url, use_remote};
|
||||
use remote::{gen_drop_url, use_remote, RemoteAccessError};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
@ -36,6 +36,13 @@ pub enum AppStatus {
|
||||
SignedInNeedsReauth,
|
||||
ServerUnavailable,
|
||||
}
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum AppError {
|
||||
DoesNotExist,
|
||||
Signal,
|
||||
RemoteAccess(String)
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct User {
|
||||
@ -54,11 +61,11 @@ pub struct AppState {
|
||||
games: HashMap<String, Game>,
|
||||
|
||||
#[serde(skip_serializing)]
|
||||
download_manager: Arc<DownloadManagerInterface>,
|
||||
download_manager: Arc<DownloadManager>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
fn fetch_state(state: tauri::State<'_, Mutex<AppState>>) -> Result<AppState, String> {
|
||||
fn fetch_state(state: tauri::State<'_, Mutex<AppState>>) -> Result<AppState, AppError> {
|
||||
let guard = state.lock().unwrap();
|
||||
let cloned_state = guard.clone();
|
||||
drop(guard);
|
||||
@ -69,7 +76,7 @@ fn setup() -> AppState {
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
|
||||
let games = HashMap::new();
|
||||
let download_manager = Arc::new(DownloadManager::generate());
|
||||
let download_manager = Arc::new(DownloadManagerBuilder::build());
|
||||
|
||||
let is_set_up = DB.database_is_set_up();
|
||||
if !is_set_up {
|
||||
|
||||
@ -7,6 +7,7 @@ use tauri::{AppHandle, Manager};
|
||||
use crate::db::DatabaseGameStatus;
|
||||
use crate::db::DatabaseImpls;
|
||||
use crate::remote::RemoteAccessError;
|
||||
use crate::AppError;
|
||||
use crate::{auth::generate_authorization_header, AppState, DB};
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
@ -18,7 +19,7 @@ struct FetchGameStruct {
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Game {
|
||||
id: String,
|
||||
game_id: String,
|
||||
m_name: String,
|
||||
m_short_description: String,
|
||||
m_description: String,
|
||||
@ -54,12 +55,12 @@ fn fetch_library_logic(app: AppHandle) -> Result<String, RemoteAccessError> {
|
||||
let mut db_handle = DB.borrow_data_mut().unwrap();
|
||||
|
||||
for game in games.iter() {
|
||||
handle.games.insert(game.id.clone(), game.clone());
|
||||
if !db_handle.games.games_statuses.contains_key(&game.id) {
|
||||
handle.games.insert(game.game_id.clone(), game.clone());
|
||||
if !db_handle.games.games_statuses.contains_key(&game.game_id) {
|
||||
db_handle
|
||||
.games
|
||||
.games_statuses
|
||||
.insert(game.id.clone(), DatabaseGameStatus::Remote);
|
||||
.insert(game.game_id.clone(), DatabaseGameStatus::Remote);
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,14 +70,9 @@ fn fetch_library_logic(app: AppHandle) -> Result<String, RemoteAccessError> {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn fetch_library(app: AppHandle) -> Result<String, String> {
|
||||
let result = fetch_library_logic(app);
|
||||
|
||||
if result.is_err() {
|
||||
return Err(result.err().unwrap().to_string());
|
||||
}
|
||||
|
||||
Ok(result.unwrap())
|
||||
pub fn fetch_library(app: AppHandle) -> Result<String, AppError> {
|
||||
fetch_library_logic(app)
|
||||
.map_err(|e| AppError::RemoteAccess(e.to_string()))
|
||||
}
|
||||
|
||||
fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result<String, RemoteAccessError> {
|
||||
@ -92,7 +88,7 @@ fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result<String, RemoteA
|
||||
status: db_handle
|
||||
.games
|
||||
.games_statuses
|
||||
.get(&game.id)
|
||||
.get(&game.game_id)
|
||||
.unwrap()
|
||||
.clone(),
|
||||
};
|
||||
@ -101,7 +97,7 @@ fn fetch_game_logic(id: String, app: tauri::AppHandle) -> Result<String, RemoteA
|
||||
}
|
||||
// TODO request games that aren't found from remote server
|
||||
|
||||
Err("".to_string().into())
|
||||
Err(RemoteAccessError::GameNotFound)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@ -3,29 +3,45 @@ use std::{
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use http::StatusCode;
|
||||
use log::{info, warn};
|
||||
use serde::Deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::{ParseError, Url};
|
||||
|
||||
use crate::{AppState, AppStatus, DB};
|
||||
use crate::{AppError, AppState, AppStatus, DB};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RemoteAccessError {
|
||||
FetchError(Arc<reqwest::Error>),
|
||||
ParsingError(ParseError),
|
||||
InvalidCodeError(u16),
|
||||
GenericErrror(String),
|
||||
InvalidEndpoint,
|
||||
HandshakeFailed,
|
||||
GameNotFound,
|
||||
InvalidResponse,
|
||||
InvalidRedirect,
|
||||
ManifestDownloadFailed(StatusCode, String)
|
||||
}
|
||||
|
||||
impl Display for RemoteAccessError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
RemoteAccessError::FetchError(error) => write!(f, "{}", error),
|
||||
RemoteAccessError::GenericErrror(error) => write!(f, "{}", error),
|
||||
RemoteAccessError::ParsingError(parse_error) => {
|
||||
write!(f, "{}", parse_error)
|
||||
}
|
||||
RemoteAccessError::InvalidCodeError(error) => write!(f, "HTTP {}", error),
|
||||
RemoteAccessError::ParsingError(parse_error) => todo!(),
|
||||
RemoteAccessError::InvalidEndpoint => write!(f, "Invalid drop endpoint"),
|
||||
RemoteAccessError::HandshakeFailed => write!(f, "Failed to complete handshake"),
|
||||
RemoteAccessError::GameNotFound => write!(f, "Could not find game on server"),
|
||||
RemoteAccessError::InvalidResponse => write!(f, "Server returned an invalid response"),
|
||||
RemoteAccessError::InvalidRedirect => write!(f, "Server redirect was invalid"),
|
||||
RemoteAccessError::ManifestDownloadFailed(status, response) =>
|
||||
write!(f, "Failed to download game manifest: {} {}",
|
||||
status,
|
||||
response
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,11 +51,6 @@ impl From<reqwest::Error> for RemoteAccessError {
|
||||
RemoteAccessError::FetchError(Arc::new(err))
|
||||
}
|
||||
}
|
||||
impl From<String> for RemoteAccessError {
|
||||
fn from(err: String) -> Self {
|
||||
RemoteAccessError::GenericErrror(err)
|
||||
}
|
||||
}
|
||||
impl From<ParseError> for RemoteAccessError {
|
||||
fn from(err: ParseError) -> Self {
|
||||
RemoteAccessError::ParsingError(err)
|
||||
@ -74,7 +85,7 @@ async fn use_remote_logic<'a>(
|
||||
|
||||
if result.app_name != "Drop" {
|
||||
warn!("user entered drop endpoint that connected, but wasn't identified as Drop");
|
||||
return Err("Not a valid Drop endpoint".to_string().into());
|
||||
return Err(RemoteAccessError::InvalidEndpoint);
|
||||
}
|
||||
|
||||
let mut app_state = state.lock().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user