diff --git a/desktop/src-tauri/src/auth.rs b/desktop/src-tauri/src/auth.rs index 24c8b57e..8b4383d8 100644 --- a/desktop/src-tauri/src/auth.rs +++ b/desktop/src-tauri/src/auth.rs @@ -93,7 +93,9 @@ 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::InvalidResponse); + return Err(RemoteAccessError::HandshakeFailed( + "failed to parse token".to_string(), + )); } let base_url = { diff --git a/desktop/src-tauri/src/db.rs b/desktop/src-tauri/src/db.rs index 0ab464fa..a88bc326 100644 --- a/desktop/src-tauri/src/db.rs +++ b/desktop/src-tauri/src/db.rs @@ -14,18 +14,12 @@ use url::Url; use crate::{process::process_manager::Platform, DB}; #[derive(serde::Serialize, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct DatabaseAuth { pub private: String, pub cert: String, pub client_id: String, } -pub struct GameStatusData { - version_name: String, - install_dir: String, -} - // Strings are version names for a particular game #[derive(Serialize, Clone, Deserialize)] #[serde(tag = "type")] @@ -61,7 +55,6 @@ pub struct GameVersion { } #[derive(Serialize, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct DatabaseGames { pub install_dirs: Vec, // Guaranteed to exist if the game also exists in the app state map @@ -89,6 +82,7 @@ impl Default for Settings { #[derive(Serialize, Deserialize, Clone)] pub struct Database { + #[serde(default)] pub settings: Settings, pub auth: Option, pub base_url: String, @@ -136,8 +130,7 @@ impl DatabaseImpls for DatabaseInterface { let exists = fs::exists(db_path.clone()).unwrap(); match exists { - true => PathDatabase::load_from_path(db_path) - .expect("Database loading failed"), + true => PathDatabase::load_from_path(db_path).expect("Database loading failed"), false => { let default = Database { settings: Settings::default(), diff --git a/desktop/src-tauri/src/downloads/download_logic.rs b/desktop/src-tauri/src/downloads/download_logic.rs index 420d0efb..5c05f7c4 100644 --- a/desktop/src-tauri/src/downloads/download_logic.rs +++ b/desktop/src-tauri/src/downloads/download_logic.rs @@ -3,7 +3,8 @@ use crate::db::DatabaseImpls; use crate::downloads::manifest::DropDownloadContext; use crate::remote::RemoteAccessError; use crate::DB; -use log::warn; +use http::StatusCode; +use log::{info, warn}; use md5::{Context, Digest}; use reqwest::blocking::Response; @@ -171,7 +172,10 @@ pub fn download_game_chunk( let content_length = response.content_length(); if content_length.is_none() { return Err(GameDownloadError::Communication( - RemoteAccessError::InvalidResponse, + RemoteAccessError::ManifestDownloadFailed( + StatusCode::from_u16(500).unwrap(), + "failed to download manifest due to missing content length".to_owned(), + ), )); } diff --git a/desktop/src-tauri/src/downloads/download_manager_builder.rs b/desktop/src-tauri/src/downloads/download_manager_builder.rs index 91ac61cd..f1e2d59f 100644 --- a/desktop/src-tauri/src/downloads/download_manager_builder.rs +++ b/desktop/src-tauri/src/downloads/download_manager_builder.rs @@ -356,11 +356,8 @@ impl DownloadManagerBuilder { if let Err(error) = on_game_complete(game_id, version, install_dir, &self.app_handle) { - self.sender - .send(DownloadManagerSignal::Error( - GameDownloadError::Communication(error), - )) - .unwrap(); + error!("failed to mark game as completed: {}", error); + // TODO mark game as remote so user can retry } } } @@ -500,6 +497,7 @@ impl DownloadManagerBuilder { .unwrap(); } fn manage_error_signal(&mut self, error: GameDownloadError) { + error!("{}", error); let current_status = self.current_download_agent.clone().unwrap(); self.stop_and_wait_current_download(); diff --git a/desktop/src-tauri/src/library.rs b/desktop/src-tauri/src/library.rs index e5705a12..e8a31663 100644 --- a/desktop/src-tauri/src/library.rs +++ b/desktop/src-tauri/src/library.rs @@ -1,16 +1,17 @@ use std::sync::Mutex; +use log::info; use serde::{Deserialize, Serialize}; use tauri::Emitter; use tauri::{AppHandle, Manager}; use urlencoding::encode; use crate::db::DatabaseImpls; -use crate::db::GameVersion; use crate::db::GameStatus; +use crate::db::GameVersion; use crate::downloads::download_manager::{DownloadManagerStatus, GameDownloadStatus}; use crate::process::process_manager::Platform; -use crate::remote::RemoteAccessError; +use crate::remote::{DropServerError, RemoteAccessError}; use crate::state::{GameStatusManager, GameStatusWithTransient}; use crate::{auth::generate_authorization_header, AppState, DB}; @@ -288,6 +289,14 @@ pub fn on_game_complete( .header("Authorization", header) .send()?; + if response.status() != 200 { + return Err(RemoteAccessError::InvalidResponse( + response.json::().map_err(|e| { + RemoteAccessError::Generic(format!("failed to parse server error: {}", e)) + })?, + )); + } + let data = response.json::()?; let mut handle = DB.borrow_data_mut().unwrap(); diff --git a/desktop/src-tauri/src/remote.rs b/desktop/src-tauri/src/remote.rs index 15591558..04c56dba 100644 --- a/desktop/src-tauri/src/remote.rs +++ b/desktop/src-tauri/src/remote.rs @@ -6,6 +6,7 @@ use std::{ use http::StatusCode; use log::{info, warn}; +use reqwest::blocking::Response; use serde::Deserialize; use url::{ParseError, Url}; @@ -19,10 +20,11 @@ pub enum RemoteAccessError { InvalidEndpoint, HandshakeFailed(String), GameNotFound, - InvalidResponse, + InvalidResponse(DropServerError), InvalidRedirect, ManifestDownloadFailed(StatusCode, String), OutOfSync, + Generic(String), } impl Display for RemoteAccessError { @@ -45,7 +47,7 @@ impl Display for RemoteAccessError { RemoteAccessError::InvalidEndpoint => write!(f, "Invalid drop endpoint"), RemoteAccessError::HandshakeFailed(message) => write!(f, "Failed to complete handshake: {}", message), RemoteAccessError::GameNotFound => write!(f, "Could not find game on server"), - RemoteAccessError::InvalidResponse => write!(f, "Server returned an invalid response"), + RemoteAccessError::InvalidResponse(error) => write!(f, "Server returned an invalid response: {} {}", error.status_code, error.status_message), RemoteAccessError::InvalidRedirect => write!(f, "Server redirect was invalid"), RemoteAccessError::ManifestDownloadFailed(status, response) => write!( f, @@ -53,6 +55,7 @@ impl Display for RemoteAccessError { status, response ), RemoteAccessError::OutOfSync => write!(f, "Server's and client's time are out of sync. Please ensure they are within at least 30 seconds of each other."), + RemoteAccessError::Generic(message) => write!(f, "{}", message), } } } @@ -75,7 +78,7 @@ impl From for RemoteAccessError { impl std::error::Error for RemoteAccessError {} -#[derive(Deserialize)] +#[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] pub struct DropServerError { pub status_code: usize,