mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-10 04:22:13 +10:00
feat: improve errors and include installed games in library
This commit is contained in:
@ -85,5 +85,6 @@ const message =
|
|||||||
props.error?.statusMessage ||
|
props.error?.statusMessage ||
|
||||||
props.error?.message ||
|
props.error?.message ||
|
||||||
"An unknown error occurred.";
|
"An unknown error occurred.";
|
||||||
const showSignIn = statusCode ? statusCode == 403 || statusCode == 401 : false;
|
|
||||||
|
console.error(props.error);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -29,6 +29,9 @@
|
|||||||
Drop encountered an error that it couldn't handle. Please
|
Drop encountered an error that it couldn't handle. Please
|
||||||
restart the application and file a bug report.
|
restart the application and file a bug report.
|
||||||
</p>
|
</p>
|
||||||
|
<p class="mt-3 text-sm font-monospace text-zinc-500">
|
||||||
|
Error: {{ error }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<footer
|
<footer
|
||||||
|
|||||||
@ -16,7 +16,7 @@ pub enum RemoteAccessError {
|
|||||||
ParsingError(ParseError),
|
ParsingError(ParseError),
|
||||||
InvalidEndpoint,
|
InvalidEndpoint,
|
||||||
HandshakeFailed(String),
|
HandshakeFailed(String),
|
||||||
GameNotFound,
|
GameNotFound(String),
|
||||||
InvalidResponse(DropServerError),
|
InvalidResponse(DropServerError),
|
||||||
InvalidRedirect,
|
InvalidRedirect,
|
||||||
ManifestDownloadFailed(StatusCode, String),
|
ManifestDownloadFailed(StatusCode, String),
|
||||||
@ -43,7 +43,7 @@ impl Display for RemoteAccessError {
|
|||||||
}
|
}
|
||||||
RemoteAccessError::InvalidEndpoint => write!(f, "invalid drop endpoint"),
|
RemoteAccessError::InvalidEndpoint => write!(f, "invalid drop endpoint"),
|
||||||
RemoteAccessError::HandshakeFailed(message) => write!(f, "failed to complete handshake: {}", message),
|
RemoteAccessError::HandshakeFailed(message) => write!(f, "failed to complete handshake: {}", message),
|
||||||
RemoteAccessError::GameNotFound => write!(f, "could not find game on server"),
|
RemoteAccessError::GameNotFound(id) => write!(f, "could not find game on server: {}", id),
|
||||||
RemoteAccessError::InvalidResponse(error) => write!(f, "server returned an invalid response: {} {}", error.status_code, error.status_message),
|
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::InvalidRedirect => write!(f, "server redirect was invalid"),
|
||||||
RemoteAccessError::ManifestDownloadFailed(status, response) => write!(
|
RemoteAccessError::ManifestDownloadFailed(status, response) => write!(
|
||||||
|
|||||||
@ -14,7 +14,7 @@ use crate::download_manager::downloadable_metadata::DownloadableMetadata;
|
|||||||
use crate::error::remote_access_error::RemoteAccessError;
|
use crate::error::remote_access_error::RemoteAccessError;
|
||||||
use crate::games::state::{GameStatusManager, GameStatusWithTransient};
|
use crate::games::state::{GameStatusManager, GameStatusWithTransient};
|
||||||
use crate::remote::auth::generate_authorization_header;
|
use crate::remote::auth::generate_authorization_header;
|
||||||
use crate::remote::cache::{cache_object, get_cached_object};
|
use crate::remote::cache::{cache_object, get_cached_object, get_cached_object_db};
|
||||||
use crate::remote::requests::make_request;
|
use crate::remote::requests::make_request;
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ pub fn fetch_library_logic(
|
|||||||
return Err(RemoteAccessError::InvalidResponse(err));
|
return Err(RemoteAccessError::InvalidResponse(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
let games: Vec<Game> = response.json()?;
|
let mut games: Vec<Game> = response.json()?;
|
||||||
|
|
||||||
let mut handle = state.lock().unwrap();
|
let mut handle = state.lock().unwrap();
|
||||||
|
|
||||||
@ -100,6 +100,18 @@ pub fn fetch_library_logic(
|
|||||||
.insert(game.id.clone(), GameDownloadStatus::Remote {});
|
.insert(game.id.clone(), GameDownloadStatus::Remote {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add games that are installed but no longer in library
|
||||||
|
for (_, meta) in &db_handle.applications.installed_game_version {
|
||||||
|
if games.iter().find(|e| e.id == meta.id).is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// We should always have a cache of the object
|
||||||
|
// Pass db_handle because otherwise we get a gridlock
|
||||||
|
let game = get_cached_object_db::<String, Game>(meta.id.clone(), &db_handle)?;
|
||||||
|
games.push(game);
|
||||||
|
}
|
||||||
|
|
||||||
drop(handle);
|
drop(handle);
|
||||||
drop(db_handle);
|
drop(db_handle);
|
||||||
cache_object("library", &games)?;
|
cache_object("library", &games)?;
|
||||||
@ -142,13 +154,13 @@ pub fn fetch_game_logic(
|
|||||||
return Ok(data);
|
return Ok(data);
|
||||||
}
|
}
|
||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let response = make_request(&client, &["/api/v1/game/", &id], &[], |r| {
|
let response = make_request(&client, &["/api/v1/client/game/", &id], &[], |r| {
|
||||||
r.header("Authorization", generate_authorization_header())
|
r.header("Authorization", generate_authorization_header())
|
||||||
})?
|
})?
|
||||||
.send()?;
|
.send()?;
|
||||||
|
|
||||||
if response.status() == 404 {
|
if response.status() == 404 {
|
||||||
return Err(RemoteAccessError::GameNotFound);
|
return Err(RemoteAccessError::GameNotFound(id));
|
||||||
}
|
}
|
||||||
if response.status() != 200 {
|
if response.status() != 200 {
|
||||||
let err = response.json().unwrap();
|
let err = response.json().unwrap();
|
||||||
@ -312,7 +324,7 @@ pub fn on_game_complete(
|
|||||||
) -> Result<(), RemoteAccessError> {
|
) -> Result<(), RemoteAccessError> {
|
||||||
// Fetch game version information from remote
|
// Fetch game version information from remote
|
||||||
if meta.version.is_none() {
|
if meta.version.is_none() {
|
||||||
return Err(RemoteAccessError::GameNotFound);
|
return Err(RemoteAccessError::GameNotFound(meta.id.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let header = generate_authorization_header();
|
let header = generate_authorization_header();
|
||||||
@ -320,7 +332,7 @@ pub fn on_game_complete(
|
|||||||
let client = reqwest::blocking::Client::new();
|
let client = reqwest::blocking::Client::new();
|
||||||
let response = make_request(
|
let response = make_request(
|
||||||
&client,
|
&client,
|
||||||
&["/api/v1/client/metadata/version"],
|
&["/api/v1/client/game/version"],
|
||||||
&[
|
&[
|
||||||
("id", &meta.id),
|
("id", &meta.id),
|
||||||
("version", meta.version.as_ref().unwrap()),
|
("version", meta.version.as_ref().unwrap()),
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
use crate::{database::db::borrow_db_checked, error::remote_access_error::RemoteAccessError};
|
use std::sync::RwLockReadGuard;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
database::db::{borrow_db_checked, Database},
|
||||||
|
error::remote_access_error::RemoteAccessError,
|
||||||
|
};
|
||||||
use cacache::Integrity;
|
use cacache::Integrity;
|
||||||
use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response};
|
use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response};
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use serde_binary::binary_stream::Endian;
|
use serde_binary::binary_stream::Endian;
|
||||||
use tauri::{UriSchemeContext, UriSchemeResponder};
|
|
||||||
|
|
||||||
use super::{auth::generate_authorization_header, requests::make_request};
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! offline {
|
macro_rules! offline {
|
||||||
@ -30,12 +33,16 @@ pub fn cache_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
|||||||
pub fn get_cached_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
pub fn get_cached_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
||||||
key: K,
|
key: K,
|
||||||
) -> Result<D, RemoteAccessError> {
|
) -> Result<D, RemoteAccessError> {
|
||||||
let bytes = cacache::read_sync(&borrow_db_checked().cache_dir, key)
|
get_cached_object_db::<K, D>(key, &borrow_db_checked())
|
||||||
.map_err(|e| RemoteAccessError::Cache(e))?;
|
}
|
||||||
|
pub fn get_cached_object_db<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(
|
||||||
|
key: K,
|
||||||
|
db: &Database,
|
||||||
|
) -> Result<D, RemoteAccessError> {
|
||||||
|
let bytes = cacache::read_sync(&db.cache_dir, key).map_err(|e| RemoteAccessError::Cache(e))?;
|
||||||
let data = serde_binary::from_slice::<D>(&bytes, Endian::Little).unwrap();
|
let data = serde_binary::from_slice::<D>(&bytes, Endian::Little).unwrap();
|
||||||
Ok(data)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ObjectCache {
|
pub struct ObjectCache {
|
||||||
content_type: String,
|
content_type: String,
|
||||||
|
|||||||
Reference in New Issue
Block a user