mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2026-07-24 00:42:59 +10:00
chore: Starting migrating references to database applications, auth, and base_url
Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "library"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.89"
|
||||
client = { version = "0.1.0", path = "../client" }
|
||||
database = { version = "0.1.0", path = "../database" }
|
||||
futures = "0.3.31"
|
||||
itertools = "0.14.0"
|
||||
log = "0.4.28"
|
||||
remote = { version = "0.1.0", path = "../remote" }
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
serde_with = "3.15.0"
|
||||
tauri = "2.8.5"
|
||||
url = "2.5.7"
|
||||
@@ -0,0 +1,134 @@
|
||||
use std::sync::nonpoison::Mutex;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use client::app_state::AppState;
|
||||
use database::{
|
||||
DatabaseAuth, GameDownloadStatus, borrow_db_mut_checked,
|
||||
models::{Collection, Game, LibraryProviderMetadata},
|
||||
};
|
||||
use log::warn;
|
||||
use remote::{
|
||||
auth::generate_authorization_header,
|
||||
cache::{cache_object, get_cached_object, get_cached_object_db},
|
||||
error::{DropServerError, RemoteAccessError},
|
||||
requests::generate_url,
|
||||
utils::DROP_CLIENT_ASYNC,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use crate::{error::LibraryError, provider::LibraryProvider};
|
||||
|
||||
pub struct DropLibraryProvider {
|
||||
metadata: LibraryProviderMetadata,
|
||||
auth: DatabaseAuth,
|
||||
base_url: Url,
|
||||
}
|
||||
|
||||
impl DropLibraryProvider {
|
||||
pub fn new(metadata: LibraryProviderMetadata, auth: DatabaseAuth, base_url: Url) -> Self {
|
||||
Self {
|
||||
metadata,
|
||||
auth,
|
||||
base_url,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[async_trait]
|
||||
impl LibraryProvider for DropLibraryProvider {
|
||||
async fn get_library(
|
||||
&self,
|
||||
state: &tauri::State<'_, Mutex<AppState>>,
|
||||
) -> Result<Vec<Game>, LibraryError> {
|
||||
// let do_hard_refresh = hard_fresh.unwrap_or(false);
|
||||
if
|
||||
/* !do_hard_refresh &&*/
|
||||
let Ok(library) = get_cached_object("library") {
|
||||
return Ok(library);
|
||||
}
|
||||
|
||||
let client = DROP_CLIENT_ASYNC.clone();
|
||||
let response = generate_url(&["/api/v1/client/user/library"], &[], self.base_url)?;
|
||||
let response = client
|
||||
.get(response)
|
||||
.header("Authorization", generate_authorization_header(self.auth))
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| LibraryError::FetchError(RemoteAccessError::FetchError(e.into())))?;
|
||||
|
||||
if response.status() != 200 {
|
||||
let err = response.json().await.unwrap_or(DropServerError {
|
||||
status_code: 500,
|
||||
status_message: "Invalid response from server.".to_owned(),
|
||||
});
|
||||
warn!("{err:?}");
|
||||
return Err(LibraryError::FetchError(
|
||||
RemoteAccessError::InvalidResponse(err),
|
||||
));
|
||||
}
|
||||
|
||||
let mut games: Vec<Game> = response
|
||||
.json()
|
||||
.await
|
||||
.map_err(|e| RemoteAccessError::FetchError(e.into()))?;
|
||||
|
||||
let mut handle = state.lock();
|
||||
|
||||
let mut db_handle = borrow_db_mut_checked();
|
||||
|
||||
for game in &games {
|
||||
handle.games_mut().insert(game.id().clone(), game.clone());
|
||||
if !db_handle.applications.game_statuses.contains_key(game.id()) {
|
||||
db_handle
|
||||
.applications
|
||||
.game_statuses
|
||||
.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.values() {
|
||||
if games.iter().any(|e| *e.id() == meta.id) {
|
||||
continue;
|
||||
}
|
||||
// We should always have a cache of the object
|
||||
// Pass db_handle because otherwise we get a gridlock
|
||||
let game = match get_cached_object_db::<Game>(&meta.id.clone(), &db_handle) {
|
||||
Ok(game) => game,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
"{} is installed, but encountered error fetching its error: {}.",
|
||||
meta.id, err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
games.push(game);
|
||||
}
|
||||
|
||||
drop(handle);
|
||||
drop(db_handle);
|
||||
cache_object("library", &games)?;
|
||||
|
||||
Ok(games)
|
||||
}
|
||||
async fn get_collections(&self) -> Result<Vec<Collection>, LibraryError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn install(&mut self, game_id: String) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn uninstall(&mut self, game_id: String) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn metadata(&self) -> LibraryProviderMetadata {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_library_logic(state: &Mutex<AppState>) -> Result<Vec<Game>, RemoteAccessError> {}
|
||||
async fn fetch_library_logic_offline() -> Result<Vec<Game>, RemoteAccessError> {
|
||||
todo!()
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
pub mod drop;
|
||||
@@ -0,0 +1,31 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
use database::models::LibraryProviderMetadata;
|
||||
use remote::error::RemoteAccessError;
|
||||
use serde_with::SerializeDisplay;
|
||||
|
||||
#[derive(Debug, SerializeDisplay)]
|
||||
pub enum LibraryError {
|
||||
ProviderConnection(ProviderError),
|
||||
FetchError(RemoteAccessError)
|
||||
}
|
||||
#[derive(Debug, SerializeDisplay)]
|
||||
pub struct ProviderError {
|
||||
provider: LibraryProviderMetadata
|
||||
}
|
||||
|
||||
impl Display for LibraryError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl Display for ProviderError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl From<RemoteAccessError> for LibraryError {
|
||||
fn from(value: RemoteAccessError) -> Self {
|
||||
LibraryError::FetchError(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
#![feature(nonpoison_mutex)]
|
||||
#![feature(sync_nonpoison)]
|
||||
|
||||
use std::sync::{LazyLock, nonpoison::Mutex};
|
||||
|
||||
use client::app_state::AppState;
|
||||
use database::{borrow_db_checked, models::{Game, LibraryProviderMetadata, ProviderType}};
|
||||
use futures::{StreamExt, future::join_all};
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{drop::drop::DropLibraryProvider, error::LibraryError, provider::LibraryProvider};
|
||||
|
||||
pub mod drop;
|
||||
pub mod error;
|
||||
pub mod provider;
|
||||
|
||||
pub static LIBRARY: LazyLock<Library> = LazyLock::new(Library::init);
|
||||
|
||||
pub struct Library {
|
||||
providers: Vec<Box<dyn LibraryProvider>>,
|
||||
}
|
||||
|
||||
impl Library {
|
||||
pub fn init() -> Self {
|
||||
let metadata = borrow_db_checked();
|
||||
let library = &metadata.library;
|
||||
let providers = library.providers().iter().map(|provider| {
|
||||
Library::construct(provider)
|
||||
}).collect();
|
||||
Self {
|
||||
providers
|
||||
}
|
||||
}
|
||||
fn construct(provider: &LibraryProviderMetadata) -> Box<dyn LibraryProvider> {
|
||||
todo!()
|
||||
}
|
||||
pub async fn get_library(
|
||||
&self,
|
||||
state: &tauri::State<'_, Mutex<AppState>>,
|
||||
) -> (Vec<Game>, Vec<LibraryError>) {
|
||||
let res = join_all(
|
||||
self.providers
|
||||
.iter()
|
||||
.map(|provider| provider.get_library(state)),
|
||||
)
|
||||
.await
|
||||
.into_iter()
|
||||
.fold(
|
||||
(Vec::new(), Vec::new()),
|
||||
|(mut acc_ok, mut acc_err), res| {
|
||||
match res {
|
||||
Ok(games) => acc_ok.extend(games),
|
||||
Err(e) => acc_err.push(e),
|
||||
};
|
||||
(acc_ok, acc_err)
|
||||
},
|
||||
);
|
||||
res
|
||||
}
|
||||
pub fn add(&mut self, provider: LibraryProviderMetadata) {
|
||||
let new_provider = Box::new(match provider.provider() {
|
||||
ProviderType::Drop(_) => DropLibraryProvider::new(provider),
|
||||
});
|
||||
self.providers.push(new_provider);
|
||||
}
|
||||
pub fn remove(&mut self, id: usize) {
|
||||
self.providers.retain(|v| v.metadata().id() != id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use std::sync::nonpoison::Mutex;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use client::app_state::AppState;
|
||||
use database::models::{Collection, Game, LibraryProviderMetadata};
|
||||
|
||||
use crate::error::LibraryError;
|
||||
|
||||
#[async_trait]
|
||||
pub trait LibraryProvider: Sync + Send {
|
||||
async fn get_library(&self, state: &tauri::State<'_, Mutex<AppState>>) -> Result<Vec<Game>, LibraryError>;
|
||||
async fn get_collections(&self) -> Result<Vec<Collection>, LibraryError>;
|
||||
fn install(&mut self, game_id: String);
|
||||
fn uninstall(&mut self, game_id: String);
|
||||
fn metadata(&self) -> LibraryProviderMetadata;
|
||||
}
|
||||
Reference in New Issue
Block a user