From 43b56462d6e04654afeb692cb1c1b99750b58d33 Mon Sep 17 00:00:00 2001 From: DecDuck Date: Tue, 16 Sep 2025 15:09:43 +1000 Subject: [PATCH] feat: more refactoring (broken) --- src-tauri/Cargo.lock | 39 ++++++--- src-tauri/Cargo.toml | 4 +- src-tauri/drop-consts/Cargo.toml | 7 ++ src-tauri/drop-consts/src/lib.rs | 15 ++++ src-tauri/drop-database/Cargo.toml | 6 +- src-tauri/drop-database/src/db.rs | 33 ++------ src-tauri/drop-database/src/models.rs | 72 +++++++++++++---- .../drop-errors/src/drop_server_error.rs | 2 +- .../drop-errors/src/remote_access_error.rs | 4 +- src-tauri/drop-library/Cargo.toml | 11 +++ src-tauri/drop-library/src/errors.rs | 11 +++ src-tauri/drop-library/src/game.rs | 30 +++++++ src-tauri/drop-library/src/lib.rs | 3 + src-tauri/drop-library/src/libraries.rs | 76 +++++++++++++++++ src-tauri/drop-native-library/Cargo.toml | 11 +-- .../drop-native-library/src/collections.rs | 2 +- src-tauri/drop-native-library/src/impls.rs | 50 ++++++++++++ src-tauri/drop-native-library/src/lib.rs | 9 ++- src-tauri/drop-native-library/src/library.rs | 45 +++++++---- src-tauri/drop-native-library/src/state.rs | 2 +- src-tauri/drop-remote/Cargo.toml | 2 +- src-tauri/drop-remote/src/auth.rs | 81 ++++++++----------- src-tauri/drop-remote/src/cache.rs | 17 ++-- src-tauri/drop-remote/src/fetch_object.rs | 11 ++- src-tauri/drop-remote/src/lib.rs | 24 ++++++ src-tauri/drop-remote/src/requests.rs | 10 +-- src-tauri/drop-remote/src/utils.rs | 3 +- .../downloads/download_logic.rs | 4 +- 28 files changed, 429 insertions(+), 155 deletions(-) create mode 100644 src-tauri/drop-consts/Cargo.toml create mode 100644 src-tauri/drop-consts/src/lib.rs create mode 100644 src-tauri/drop-library/Cargo.toml create mode 100644 src-tauri/drop-library/src/errors.rs create mode 100644 src-tauri/drop-library/src/game.rs create mode 100644 src-tauri/drop-library/src/lib.rs create mode 100644 src-tauri/drop-library/src/libraries.rs create mode 100644 src-tauri/drop-native-library/src/impls.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index ae65551..b80961a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1154,13 +1154,22 @@ dependencies = [ "zstd", ] +[[package]] +name = "drop-consts" +version = "0.1.0" +dependencies = [ + "dirs 6.0.0", +] + [[package]] name = "drop-database" version = "0.1.0" dependencies = [ "bitcode", "chrono", - "dirs 6.0.0", + "drop-consts", + "drop-library", + "drop-native-library", "log", "native_model", "rustbreak", @@ -1198,17 +1207,29 @@ dependencies = [ "url", ] +[[package]] +name = "drop-library" +version = "0.1.0" +dependencies = [ + "drop-errors", + "http", + "reqwest", + "serde", + "tauri", +] + [[package]] name = "drop-native-library" version = "0.1.0" dependencies = [ "bitcode", - "drop-database", "drop-errors", + "drop-library", "drop-remote", "log", "serde", "tauri", + "url", ] [[package]] @@ -1234,7 +1255,7 @@ version = "0.1.0" dependencies = [ "bitcode", "chrono", - "drop-database", + "drop-consts", "drop-errors", "droplet-rs", "gethostname", @@ -4482,9 +4503,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.220" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceecad4c782e936ac90ecfd6b56532322e3262b14320abf30ce89a92ffdbfe22" +checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" dependencies = [ "serde_core", "serde_derive", @@ -4513,18 +4534,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.220" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddba47394f3b862d6ff6efdbd26ca4673e3566a307880a0ffb98f274bbe0ec32" +checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.220" +version = "1.0.225" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e1f3b1761e96def5ec6d04a6e7421c0404fa3cf5c0155f1e2848fae3d8cc08" +checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" dependencies = [ "proc-macro2", "quote", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 4c96e4d..dcb2358 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -7,10 +7,10 @@ description = "The client application for the open-source, self-hosted game dist [workspace] resolver = "3" -members = [ +members = ["drop-consts", "drop-database", "drop-downloads", - "drop-errors", + "drop-errors", "drop-library", "drop-native-library", "drop-process", "drop-remote", diff --git a/src-tauri/drop-consts/Cargo.toml b/src-tauri/drop-consts/Cargo.toml new file mode 100644 index 0000000..3485b2c --- /dev/null +++ b/src-tauri/drop-consts/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "drop-consts" +version = "0.1.0" +edition = "2024" + +[dependencies] +dirs = "6.0.0" diff --git a/src-tauri/drop-consts/src/lib.rs b/src-tauri/drop-consts/src/lib.rs new file mode 100644 index 0000000..91389db --- /dev/null +++ b/src-tauri/drop-consts/src/lib.rs @@ -0,0 +1,15 @@ +use std::{ + path::PathBuf, + sync::{Arc, LazyLock}, +}; + +#[cfg(not(debug_assertions))] +static DATA_ROOT_PREFIX: &'static str = "drop"; +#[cfg(debug_assertions)] +static DATA_ROOT_PREFIX: &str = "drop-debug"; + +pub static DATA_ROOT_DIR: LazyLock<&'static PathBuf> = + LazyLock::new(|| Box::leak(Box::new(dirs::data_dir().unwrap().join(DATA_ROOT_PREFIX)))); + +pub static CACHE_DIR: LazyLock<&'static PathBuf> = + LazyLock::new(|| Box::leak(Box::new(DATA_ROOT_DIR.join("cache")))); diff --git a/src-tauri/drop-database/Cargo.toml b/src-tauri/drop-database/Cargo.toml index d77be4a..023176e 100644 --- a/src-tauri/drop-database/Cargo.toml +++ b/src-tauri/drop-database/Cargo.toml @@ -6,10 +6,12 @@ edition = "2024" [dependencies] bitcode = "0.6.7" chrono = "0.4.42" -dirs = "6.0.0" +drop-consts = { path = "../drop-consts" } +drop-library = { path = "../drop-library" } +drop-native-library = { path = "../drop-native-library" } log = "0.4.28" native_model = { git = "https://github.com/Drop-OSS/native_model.git", version = "0.6.4", features = [ - "rmp_serde_1_3" + "rmp_serde_1_3", ] } rustbreak = "2.0.0" serde = { version = "1.0.219", features = ["derive"] } diff --git a/src-tauri/drop-database/src/db.rs b/src-tauri/drop-database/src/db.rs index a821b39..83652fe 100644 --- a/src-tauri/drop-database/src/db.rs +++ b/src-tauri/drop-database/src/db.rs @@ -7,23 +7,15 @@ use std::{ }; use chrono::Utc; +use drop_consts::DATA_ROOT_DIR; use log::{debug, error, info, warn}; use rustbreak::{DeSerError, DeSerializer, PathDatabase, RustbreakError}; use serde::{Serialize, de::DeserializeOwned}; -use url::Url; use crate::DB; use super::models::data::Database; -#[cfg(not(debug_assertions))] -static DATA_ROOT_PREFIX: &'static str = "drop"; -#[cfg(debug_assertions)] -static DATA_ROOT_PREFIX: &str = "drop-debug"; - -pub static DATA_ROOT_DIR: LazyLock> = - LazyLock::new(|| Arc::new(dirs::data_dir().unwrap().join(DATA_ROOT_PREFIX))); - // Custom JSON serializer to support everything we need #[derive(Debug, Default, Clone)] pub struct DropDatabaseSerializer; @@ -32,16 +24,15 @@ impl DeSerializer for DropDatabaseSerializer { fn serialize(&self, val: &T) -> rustbreak::error::DeSerResult> { - native_model::encode(val) - .map_err(|e| DeSerError::Internal(e.to_string())) + native_model::encode(val).map_err(|e| DeSerError::Internal(e.to_string())) } fn deserialize(&self, mut s: R) -> rustbreak::error::DeSerResult { let mut buf = Vec::new(); s.read_to_end(&mut buf) .map_err(|e| rustbreak::error::DeSerError::Internal(e.to_string()))?; - let (val, _version) = native_model::decode(buf) - .map_err(|e| DeSerError::Internal(e.to_string()))?; + let (val, _version) = + native_model::decode(buf).map_err(|e| DeSerError::Internal(e.to_string()))?; Ok(val) } } @@ -51,8 +42,6 @@ pub type DatabaseInterface = pub trait DatabaseImpls { fn set_up_database() -> DatabaseInterface; - fn database_is_set_up(&self) -> bool; - fn fetch_base_url(&self) -> Url; } impl DatabaseImpls for DatabaseInterface { fn set_up_database() -> DatabaseInterface { @@ -77,7 +66,7 @@ impl DatabaseImpls for DatabaseInterface { Err(e) => handle_invalid_database(e, db_path, games_base_dir, cache_dir), } } else { - let default = Database::new(games_base_dir, None, cache_dir); + let default = Database::new(games_base_dir, None); debug!( "Creating database at path {}", db_path.as_os_str().to_str().unwrap() @@ -85,15 +74,6 @@ impl DatabaseImpls for DatabaseInterface { PathDatabase::create_at_path(db_path, default).expect("Database could not be created") } } - - fn database_is_set_up(&self) -> bool { - !self.borrow_data().unwrap().base_url.is_empty() - } - - fn fetch_base_url(&self) -> Url { - let handle = self.borrow_data().unwrap(); - Url::parse(&handle.base_url).unwrap() - } } // TODO: Make the error relelvant rather than just assume that it's a Deserialize error @@ -116,7 +96,6 @@ fn handle_invalid_database( let db = Database::new( games_base_dir.into_os_string().into_string().unwrap(), Some(new_path), - cache_dir, ); PathDatabase::create_at_path(db_path, db).expect("Database could not be created") @@ -158,4 +137,4 @@ impl Drop for DBWrite<'_> { } } } -} \ No newline at end of file +} diff --git a/src-tauri/drop-database/src/models.rs b/src-tauri/drop-database/src/models.rs index 4e649b9..e8c7f43 100644 --- a/src-tauri/drop-database/src/models.rs +++ b/src-tauri/drop-database/src/models.rs @@ -8,7 +8,7 @@ pub mod data { // Declare it using the actual version that it is from, i.e. v1::Settings rather than just Settings from here pub type GameVersion = v1::GameVersion; - pub type Database = v3::Database; + pub type Database = v4::Database; pub type Settings = v1::Settings; pub type DatabaseAuth = v1::DatabaseAuth; @@ -19,7 +19,7 @@ pub mod data { */ pub type DownloadableMetadata = v1::DownloadableMetadata; pub type DownloadType = v1::DownloadType; - pub type DatabaseApplications = v2::DatabaseApplications; + pub type DatabaseApplications = v4::DatabaseApplications; // pub type DatabaseCompatInfo = v2::DatabaseCompatInfo; use std::collections::HashMap; @@ -275,8 +275,6 @@ pub mod data { #[native_model(id = 3, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from=v1::DatabaseApplications)] pub struct DatabaseApplications { pub install_dirs: Vec, - #[serde(skip)] - pub games: HashMap, pub game_statuses: HashMap, pub game_versions: HashMap>, pub installed_game_version: HashMap, @@ -293,7 +291,6 @@ pub mod data { .into_iter() .map(|x| (x.0, x.1.into())) .collect::>(), - games: HashMap::new(), install_dirs: value.install_dirs, game_versions: value.game_versions, installed_game_version: value.installed_game_version, @@ -335,27 +332,72 @@ pub mod data { } } + mod v4 { + use std::{collections::HashMap, path::PathBuf}; + use drop_library::libraries::LibraryProviderIdentifier; + use drop_native_library::impls::DropNativeLibraryProvider; + use serde_with::serde_as; + use crate::models::data::v3; + use super::{Deserialize, Serialize, native_model, v1, v2}; + + #[derive(Serialize, Deserialize, Clone)] + pub enum Library { + NativeLibrary(DropNativeLibraryProvider), + } + + #[serde_as] + #[derive(Serialize, Deserialize, Default, Clone)] + #[serde(rename_all = "camelCase")] + #[native_model(id = 3, version = 4, with = native_model::rmp_serde_1_3::RmpSerde, from=v2::DatabaseApplications)] + pub struct DatabaseApplications { + pub install_dirs: Vec, + pub libraries: HashMap, + + #[serde(skip)] + pub transient_statuses: + HashMap, + } + + impl From for DatabaseApplications { + fn from(value: v2::DatabaseApplications) -> Self { + todo!() + } + } + + #[native_model(id = 1, version = 4, with = native_model::rmp_serde_1_3::RmpSerde, from = v3::Database)] + #[derive(Serialize, Deserialize, Default, Clone)] + pub struct Database { + #[serde(default)] + pub settings: v1::Settings, + pub drop_applications: DatabaseApplications, + #[serde(skip)] + pub prev_database: Option, + } + + impl From for Database { + fn from(value: v3::Database) -> Self { + Database { + settings: value.settings, + drop_applications: value.applications.into(), + prev_database: value.prev_database, + } + } + } + } + impl Database { pub fn new>( games_base_dir: T, prev_database: Option, - cache_dir: PathBuf, ) -> Self { Self { - applications: DatabaseApplications { + drop_applications: DatabaseApplications { install_dirs: vec![games_base_dir.into()], - games: HashMap::new(), - game_statuses: HashMap::new(), - game_versions: HashMap::new(), - installed_game_version: HashMap::new(), + libraries: HashMap::new(), transient_statuses: HashMap::new(), }, prev_database, - base_url: String::new(), - auth: None, settings: Settings::default(), - cache_dir, - compat_info: None, } } } diff --git a/src-tauri/drop-errors/src/drop_server_error.rs b/src-tauri/drop-errors/src/drop_server_error.rs index 26f371b..cbb9b8a 100644 --- a/src-tauri/drop-errors/src/drop_server_error.rs +++ b/src-tauri/drop-errors/src/drop_server_error.rs @@ -2,7 +2,7 @@ use serde::Deserialize; #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] -pub struct DropServerError { +pub struct ServerError { pub status_code: usize, pub status_message: String, // pub message: String, diff --git a/src-tauri/drop-errors/src/remote_access_error.rs b/src-tauri/drop-errors/src/remote_access_error.rs index d57ce15..6122047 100644 --- a/src-tauri/drop-errors/src/remote_access_error.rs +++ b/src-tauri/drop-errors/src/remote_access_error.rs @@ -8,7 +8,7 @@ use http::StatusCode; use serde_with::SerializeDisplay; use url::ParseError; -use super::drop_server_error::DropServerError; +use super::drop_server_error::ServerError; #[derive(Debug, SerializeDisplay)] pub enum RemoteAccessError { @@ -18,7 +18,7 @@ pub enum RemoteAccessError { InvalidEndpoint, HandshakeFailed(String), GameNotFound(String), - InvalidResponse(DropServerError), + InvalidResponse(ServerError), UnparseableResponse(String), ManifestDownloadFailed(StatusCode, String), OutOfSync, diff --git a/src-tauri/drop-library/Cargo.toml b/src-tauri/drop-library/Cargo.toml new file mode 100644 index 0000000..a5d9d79 --- /dev/null +++ b/src-tauri/drop-library/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "drop-library" +version = "0.1.0" +edition = "2024" + +[dependencies] +drop-errors = { path = "../drop-errors" } +http = "*" +reqwest = { version = "*", default-features = false } +serde = { version = "*", default-features = false, features = ["derive"] } +tauri = "*" diff --git a/src-tauri/drop-library/src/errors.rs b/src-tauri/drop-library/src/errors.rs new file mode 100644 index 0000000..ff4d4ea --- /dev/null +++ b/src-tauri/drop-library/src/errors.rs @@ -0,0 +1,11 @@ +pub enum DropLibraryError { + NetworkError(reqwest::Error), + ServerError(drop_errors::drop_server_error::ServerError), + Unconfigured, +} + +impl From for DropLibraryError { + fn from(value: reqwest::Error) -> Self { + DropLibraryError::NetworkError(value) + } +} \ No newline at end of file diff --git a/src-tauri/drop-library/src/game.rs b/src-tauri/drop-library/src/game.rs new file mode 100644 index 0000000..1a9cdae --- /dev/null +++ b/src-tauri/drop-library/src/game.rs @@ -0,0 +1,30 @@ +use crate::libraries::LibraryProviderIdentifier; + +pub struct LibraryGamePreview { + pub library: LibraryProviderIdentifier, + pub internal_id: String, + pub name: String, + pub short_description: String, + pub icon: String, +} + +pub struct LibraryGame { + pub library: LibraryProviderIdentifier, + pub internal_id: String, + pub name: String, + pub short_description: String, + pub md_description: String, + pub icon: String, +} + +impl From for LibraryGamePreview { + fn from(value: LibraryGame) -> Self { + LibraryGamePreview { + library: value.library, + internal_id: value.internal_id, + name: value.name, + short_description: value.short_description, + icon: value.icon, + } + } +} diff --git a/src-tauri/drop-library/src/lib.rs b/src-tauri/drop-library/src/lib.rs new file mode 100644 index 0000000..a1fa7b2 --- /dev/null +++ b/src-tauri/drop-library/src/lib.rs @@ -0,0 +1,3 @@ +pub mod libraries; +pub mod game; +pub mod errors; \ No newline at end of file diff --git a/src-tauri/drop-library/src/libraries.rs b/src-tauri/drop-library/src/libraries.rs new file mode 100644 index 0000000..db6e449 --- /dev/null +++ b/src-tauri/drop-library/src/libraries.rs @@ -0,0 +1,76 @@ +use std::{ + fmt::Display, + hash::{DefaultHasher, Hash, Hasher}, +}; + +use http::Request; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use tauri::UriSchemeResponder; + +use crate::{ + errors::DropLibraryError, + game::{LibraryGame, LibraryGamePreview}, +}; + +#[derive(Clone, Serialize, Deserialize)] +pub struct LibraryProviderIdentifier { + internal_id: usize, + name: String, +} + +impl PartialEq for LibraryProviderIdentifier { + fn eq(&self, other: &Self) -> bool { + self.internal_id == other.internal_id + } +} + +impl Eq for LibraryProviderIdentifier {} + +impl Hash for LibraryProviderIdentifier { + fn hash(&self, state: &mut H) { + self.internal_id.hash(state); + } +} + +impl Display for LibraryProviderIdentifier { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.name) + } +} + +impl LibraryProviderIdentifier { + pub fn str_hash(&self) -> String { + let mut hasher = DefaultHasher::new(); + self.hash(&mut hasher); + hasher.finish().to_string() + } +} + +pub struct LibraryFetchConfig { + pub hard_refresh: bool, +} + +pub trait DropLibraryProvider: Serialize + DeserializeOwned + Sized { + fn build(identifier: LibraryProviderIdentifier) -> Self; + fn id(&self) -> &LibraryProviderIdentifier; + fn load_object( + &self, + request: Request>, + responder: UriSchemeResponder, + ) -> impl Future> + Send; + + fn fetch_library( + &self, + config: &LibraryFetchConfig, + ) -> impl Future, DropLibraryError>> + Send; + fn fetch_game( + &self, + config: &LibraryFetchConfig, + ) -> impl Future> + Send; + + + + fn owns_game(&self, id: &LibraryProviderIdentifier) -> bool { + self.id().internal_id == id.internal_id + } +} diff --git a/src-tauri/drop-native-library/Cargo.toml b/src-tauri/drop-native-library/Cargo.toml index 4c3adf0..127a67d 100644 --- a/src-tauri/drop-native-library/Cargo.toml +++ b/src-tauri/drop-native-library/Cargo.toml @@ -4,10 +4,11 @@ version = "0.1.0" edition = "2024" [dependencies] -bitcode = "0.6.7" -drop-database = { path = "../drop-database" } +bitcode = "*" drop-errors = { path = "../drop-errors" } +drop-library = { path = "../drop-library" } drop-remote = { path = "../drop-remote" } -log = "0.4.28" -serde = { version = "1.0.219", features = ["derive"] } -tauri = "2.8.5" +log = "*" +serde = { version = "*", features = ["derive"] } +tauri = "*" +url = "*" diff --git a/src-tauri/drop-native-library/src/collections.rs b/src-tauri/drop-native-library/src/collections.rs index 7dd6707..64c2a31 100644 --- a/src-tauri/drop-native-library/src/collections.rs +++ b/src-tauri/drop-native-library/src/collections.rs @@ -1,5 +1,5 @@ use bitcode::{Decode, Encode}; -use drop_database::runtime_models::Game; +// use drop_database::runtime_models::Game; use serde::{Deserialize, Serialize}; pub type Collections = Vec; diff --git a/src-tauri/drop-native-library/src/impls.rs b/src-tauri/drop-native-library/src/impls.rs new file mode 100644 index 0000000..8875d0f --- /dev/null +++ b/src-tauri/drop-native-library/src/impls.rs @@ -0,0 +1,50 @@ +use drop_library::{ + errors::DropLibraryError, game::{LibraryGame, LibraryGamePreview}, libraries::{DropLibraryProvider, LibraryFetchConfig, LibraryProviderIdentifier} +}; +use drop_remote::{fetch_object::fetch_object, DropRemoteContext}; +use serde::{Deserialize, Serialize}; +use url::Url; + +#[derive(Serialize, Deserialize, Clone)] +pub struct DropNativeLibraryProvider { + identifier: LibraryProviderIdentifier, + context: Option, +} + +impl DropNativeLibraryProvider { + pub fn configure(&mut self, base_url: Url) { + self.context = Some(DropRemoteContext::new(base_url)); + } +} + +impl DropLibraryProvider for DropNativeLibraryProvider { + fn build(identifier: LibraryProviderIdentifier) -> Self { + Self { + identifier, + context: None, + } + } + + fn id(&self) -> &LibraryProviderIdentifier { + &self.identifier + } + + async fn load_object(&self, request: tauri::http::Request>, responder: tauri::UriSchemeResponder) -> Result<(), DropLibraryError> { + let context = self.context.as_ref().ok_or(DropLibraryError::Unconfigured)?; + fetch_object(context, request, responder).await; + Ok(()) + } + + async fn fetch_library( + &self, + config: &LibraryFetchConfig + ) -> Result, DropLibraryError> { + todo!() + } + + async fn fetch_game(&self, config: &LibraryFetchConfig) -> Result { + todo!() + } + + +} diff --git a/src-tauri/drop-native-library/src/lib.rs b/src-tauri/drop-native-library/src/lib.rs index b5a98e6..ab58949 100644 --- a/src-tauri/drop-native-library/src/lib.rs +++ b/src-tauri/drop-native-library/src/lib.rs @@ -1,4 +1,5 @@ -pub mod collections; -pub mod library; -pub mod state; -pub mod events; \ No newline at end of file +//pub mod collections; +//pub mod library; +//pub mod state; +//pub mod events; +pub mod impls; diff --git a/src-tauri/drop-native-library/src/library.rs b/src-tauri/drop-native-library/src/library.rs index 683c401..4b562e0 100644 --- a/src-tauri/drop-native-library/src/library.rs +++ b/src-tauri/drop-native-library/src/library.rs @@ -9,9 +9,10 @@ use drop_database::models::data::DownloadableMetadata; use drop_database::models::data::GameDownloadStatus; use drop_database::models::data::GameVersion; use drop_database::runtime_models::Game; -use drop_errors::drop_server_error::DropServerError; +use drop_errors::drop_server_error::ServerError; use drop_errors::library_error::LibraryError; use drop_errors::remote_access_error::RemoteAccessError; +use drop_remote::DropRemoteContext; use drop_remote::auth::generate_authorization_header; use drop_remote::cache::cache_object; use drop_remote::cache::cache_object_db; @@ -36,22 +37,25 @@ pub struct FetchGameStruct { version: Option, } -pub async fn fetch_library_logic(hard_fresh: Option) -> Result, RemoteAccessError> { +pub async fn fetch_library_logic( + context: &DropRemoteContext, + hard_fresh: Option, +) -> Result, RemoteAccessError> { 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"], &[])?; + let response = generate_url(context, &["/api/v1/client/user/library"], &[])?; let response = client .get(response) - .header("Authorization", generate_authorization_header()) + .header("Authorization", generate_authorization_header(context)) .send() .await?; if response.status() != 200 { - let err = response.json().await.unwrap_or(DropServerError { + let err = response.json().await.unwrap_or(ServerError { status_code: 500, status_message: "Invalid response from server.".to_owned(), }); @@ -64,7 +68,10 @@ pub async fn fetch_library_logic(hard_fresh: Option) -> Result, let mut db_handle = borrow_db_mut_checked(); for game in &games { - db_handle.applications.games.insert(game.id.clone(), game.clone()); + db_handle + .applications + .games + .insert(game.id.clone(), game.clone()); if !db_handle.applications.game_statuses.contains_key(&game.id) { db_handle .applications @@ -80,7 +87,7 @@ pub async fn fetch_library_logic(hard_fresh: Option) -> Result, } // 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::(&meta.id.clone(), &db_handle) { + let game = match get_cached_object_db::(&meta.id.clone()) { Ok(game) => game, Err(err) => { warn!( @@ -118,7 +125,10 @@ pub async fn fetch_library_logic_offline( Ok(games) } -pub async fn fetch_game_logic(id: String) -> Result { +pub async fn fetch_game_logic( + context: &DropRemoteContext, + id: String, +) -> Result { let version = { let db_lock = borrow_db_checked(); @@ -152,10 +162,10 @@ pub async fn fetch_game_logic(id: String) -> Result Result Result, RemoteAccessError> { let client = DROP_CLIENT_ASYNC.clone(); - let response = generate_url(&["/api/v1/client/game/versions"], &[("id", &game_id)])?; + let response = generate_url( + context, + &["/api/v1/client/game/versions"], + &[("id", &game_id)], + )?; let response = client .get(response) - .header("Authorization", generate_authorization_header()) + .header("Authorization", generate_authorization_header(context)) .send() .await?; @@ -379,6 +394,7 @@ pub fn get_current_meta(game_id: &String) -> Option { } pub fn on_game_complete( + context: &DropRemoteContext, meta: &DownloadableMetadata, install_dir: String, app_handle: &AppHandle, @@ -390,6 +406,7 @@ pub fn on_game_complete( let client = DROP_CLIENT_SYNC.clone(); let response = generate_url( + context, &["/api/v1/client/game/version"], &[ ("id", &meta.id), @@ -398,7 +415,7 @@ pub fn on_game_complete( )?; let response = client .get(response) - .header("Authorization", generate_authorization_header()) + .header("Authorization", generate_authorization_header(context)) .send()?; let game_version: GameVersion = response.json()?; @@ -473,4 +490,4 @@ pub fn push_game_update( }, ) .unwrap(); -} \ No newline at end of file +} diff --git a/src-tauri/drop-native-library/src/state.rs b/src-tauri/drop-native-library/src/state.rs index 2928275..65aef6e 100644 --- a/src-tauri/drop-native-library/src/state.rs +++ b/src-tauri/drop-native-library/src/state.rs @@ -1,4 +1,4 @@ -use drop_database::models::data::{ApplicationTransientStatus, Database, DownloadType, DownloadableMetadata, GameDownloadStatus}; +// use drop_database::models::data::{ApplicationTransientStatus, Database, DownloadType, DownloadableMetadata, GameDownloadStatus}; pub type GameStatusWithTransient = ( Option, diff --git a/src-tauri/drop-remote/Cargo.toml b/src-tauri/drop-remote/Cargo.toml index a665787..95cd5ab 100644 --- a/src-tauri/drop-remote/Cargo.toml +++ b/src-tauri/drop-remote/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] bitcode = "0.6.7" chrono = "0.4.42" -drop-database = { path = "../drop-database" } +drop-consts = { path = "../drop-consts" } drop-errors = { path = "../drop-errors" } droplet-rs = "0.7.3" gethostname = "1.0.2" diff --git a/src-tauri/drop-remote/src/auth.rs b/src-tauri/drop-remote/src/auth.rs index e89f761..9aedb27 100644 --- a/src-tauri/drop-remote/src/auth.rs +++ b/src-tauri/drop-remote/src/auth.rs @@ -1,15 +1,16 @@ use std::{collections::HashMap, env, sync::Mutex}; use chrono::Utc; -use drop_database::{borrow_db_checked, borrow_db_mut_checked, models::data::DatabaseAuth, runtime_models::User}; -use drop_errors::{drop_server_error::DropServerError, remote_access_error::RemoteAccessError}; +use drop_errors::{drop_server_error::ServerError, remote_access_error::RemoteAccessError}; use droplet_rs::ssl::sign_nonce; use gethostname::gethostname; use log::{debug, error, warn}; use serde::{Deserialize, Serialize}; use url::Url; -use crate::{requests::make_authenticated_get, utils::{DROP_CLIENT_ASYNC, DROP_CLIENT_SYNC}}; +use crate::{ + requests::make_authenticated_get, utils::{DROP_CLIENT_ASYNC, DROP_CLIENT_SYNC}, DropRemoteAuth, DropRemoteContext +}; use super::requests::generate_url; @@ -41,23 +42,24 @@ struct HandshakeResponse { id: String, } -pub fn generate_authorization_header() -> String { - let certs = { - let db = borrow_db_checked(); - db.auth.clone().unwrap() +pub fn generate_authorization_header(context: &DropRemoteContext) -> String { + let auth = if let Some(auth) = &context.auth { + auth + } else { + return "".to_owned(); }; - let nonce = Utc::now().timestamp_millis().to_string(); - let signature = sign_nonce(certs.private, nonce.clone()).unwrap(); + let signature = sign_nonce(auth.private.clone(), nonce.clone()).unwrap(); - format!("Nonce {} {} {}", certs.client_id, nonce, signature) + format!("Nonce {} {} {}", auth.client_id, nonce, signature) } -pub async fn fetch_user() -> Result { - let response = make_authenticated_get(generate_url(&["/api/v1/client/user"], &[])?).await?; +pub async fn fetch_user(context: &DropRemoteContext) -> Result, RemoteAccessError> { + let response = + make_authenticated_get(context, generate_url(context, &["/api/v1/client/user"], &[])?).await?; if response.status() != 200 { - let err: DropServerError = response.json().await?; + let err: ServerError = response.json().await?; warn!("{err:?}"); if err.status_message == "Nonce expired" { @@ -68,25 +70,24 @@ pub async fn fetch_user() -> Result { } response - .json::() + .bytes() .await .map_err(std::convert::Into::into) + .map(|v| v.to_vec()) } -pub async fn recieve_handshake_logic(path: String) -> Result<(), RemoteAccessError> { +pub async fn recieve_handshake_logic( + context: &mut DropRemoteContext, + path: String, +) -> Result<(), RemoteAccessError> { let path_chunks: Vec<&str> = path.split('/').collect(); if path_chunks.len() != 3 { -// app.emit("auth/failed", ()).unwrap(); + // app.emit("auth/failed", ()).unwrap(); return Err(RemoteAccessError::HandshakeFailed( "failed to parse token".to_string(), )); } - let base_url = { - let handle = borrow_db_checked(); - Url::parse(handle.base_url.as_str())? - }; - let client_id = path_chunks.get(1).unwrap(); let token = path_chunks.get(2).unwrap(); let body = HandshakeRequestBody { @@ -94,7 +95,7 @@ pub async fn recieve_handshake_logic(path: String) -> Result<(), RemoteAccessErr token: (*token).to_string(), }; - let endpoint = base_url.join("/api/v1/client/auth/handshake")?; + let endpoint = generate_url(context, &["/api/v1/client/auth/handshake"], &[])?; let client = DROP_CLIENT_ASYNC.clone(); let response = client.post(endpoint).json(&body).send().await?; debug!("handshake responsded with {}", response.status().as_u16()); @@ -103,20 +104,10 @@ pub async fn recieve_handshake_logic(path: String) -> Result<(), RemoteAccessErr } let response_struct: HandshakeResponse = response.json().await?; - { - let mut handle = borrow_db_mut_checked(); - handle.auth = Some(DatabaseAuth { - private: response_struct.private, - cert: response_struct.certificate, - client_id: response_struct.id, - web_token: None, // gets created later - }); - } - let web_token = { - let header = generate_authorization_header(); + let header = generate_authorization_header(context); let token = client - .post(base_url.join("/api/v1/client/user/webtoken").unwrap()) + .post(generate_url(context, &["/api/v1/client/user/webtoken"], &[])?) .header("Authorization", header) .send() .await @@ -125,22 +116,20 @@ pub async fn recieve_handshake_logic(path: String) -> Result<(), RemoteAccessErr token.text().await.unwrap() }; - let mut handle = borrow_db_mut_checked(); - let mut_auth = handle.auth.as_mut().unwrap(); - mut_auth.web_token = Some(web_token); + context.auth = Some(DropRemoteAuth { + private: response_struct.private, + cert: response_struct.certificate, + client_id: response_struct.id, + web_token: web_token, + }); Ok(()) } -pub fn auth_initiate_logic(mode: String) -> Result { - let base_url = { - let db_lock = borrow_db_checked(); - Url::parse(&db_lock.base_url.clone())? - }; - +pub fn auth_initiate_logic(context: &DropRemoteContext, mode: String) -> Result { let hostname = gethostname(); - let endpoint = base_url.join("/api/v1/client/auth/initiate")?; + let endpoint = generate_url(context, &["/api/v1/client/auth/initiate"], &[])?; let body = InitiateRequestBody { name: format!("{} (Desktop)", hostname.into_string().unwrap()), platform: env::consts::OS.to_string(), @@ -155,7 +144,7 @@ pub fn auth_initiate_logic(mode: String) -> Result { let response = client.post(endpoint.to_string()).json(&body).send()?; if response.status() != 200 { - let data: DropServerError = response.json()?; + let data: ServerError = response.json()?; error!("could not start handshake: {}", data.status_message); return Err(RemoteAccessError::HandshakeFailed(data.status_message)); @@ -164,4 +153,4 @@ pub fn auth_initiate_logic(mode: String) -> Result { let response = response.text()?; Ok(response) -} \ No newline at end of file +} diff --git a/src-tauri/drop-remote/src/cache.rs b/src-tauri/drop-remote/src/cache.rs index a4f4fed..7f39084 100644 --- a/src-tauri/drop-remote/src/cache.rs +++ b/src-tauri/drop-remote/src/cache.rs @@ -6,7 +6,7 @@ use std::{ }; use bitcode::{Decode, DecodeOwned, Encode}; -use drop_database::{borrow_db_checked, models::data::Database}; +use drop_consts::CACHE_DIR; use drop_errors::remote_access_error::RemoteAccessError; use http::{Response, header::CONTENT_TYPE, response::Builder as ResponseBuilder}; @@ -57,36 +57,33 @@ fn delete_sync(base: &Path, key: &str) -> io::Result<()> { } pub fn cache_object(key: &str, data: &D) -> Result<(), RemoteAccessError> { - cache_object_db(key, data, &borrow_db_checked()) + cache_object_db(key, data) } pub fn cache_object_db( key: &str, data: &D, - database: &Database, ) -> Result<(), RemoteAccessError> { let bytes = bitcode::encode(data); - write_sync(&database.cache_dir, key, bytes).map_err(RemoteAccessError::Cache) + write_sync(&CACHE_DIR, key, bytes).map_err(RemoteAccessError::Cache) } pub fn get_cached_object(key: &str) -> Result { - get_cached_object_db::(key, &borrow_db_checked()) + get_cached_object_db::(key) } pub fn get_cached_object_db( key: &str, - db: &Database, ) -> Result { - let bytes = read_sync(&db.cache_dir, key).map_err(RemoteAccessError::Cache)?; + let bytes = read_sync(&CACHE_DIR, key).map_err(RemoteAccessError::Cache)?; let data = bitcode::decode::(&bytes).map_err(|e| RemoteAccessError::Cache(io::Error::other(e)))?; Ok(data) } pub fn clear_cached_object(key: &str) -> Result<(), RemoteAccessError> { - clear_cached_object_db(key, &borrow_db_checked()) + clear_cached_object_db(key) } pub fn clear_cached_object_db( key: &str, - db: &Database, ) -> Result<(), RemoteAccessError> { - delete_sync(&db.cache_dir, key).map_err(RemoteAccessError::Cache)?; + delete_sync(&CACHE_DIR, key).map_err(RemoteAccessError::Cache)?; Ok(()) } diff --git a/src-tauri/drop-remote/src/fetch_object.rs b/src-tauri/drop-remote/src/fetch_object.rs index 3b50490..b3b1ca4 100644 --- a/src-tauri/drop-remote/src/fetch_object.rs +++ b/src-tauri/drop-remote/src/fetch_object.rs @@ -1,17 +1,16 @@ -use drop_database::{db::DatabaseImpls as _, DB}; -use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder}; +use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Request}; use log::warn; use tauri::UriSchemeResponder; -use crate::utils::DROP_CLIENT_ASYNC; +use crate::{requests::generate_url, utils::DROP_CLIENT_ASYNC, DropRemoteContext}; use super::{ auth::generate_authorization_header, cache::{ObjectCache, cache_object, get_cached_object}, }; -pub async fn fetch_object(request: http::Request>, responder: UriSchemeResponder) { +pub async fn fetch_object(context: &DropRemoteContext, request: Request>, responder: UriSchemeResponder) { // Drop leading / let object_id = &request.uri().path()[1..]; @@ -23,9 +22,9 @@ pub async fn fetch_object(request: http::Request>, responder: UriSchemeR return; } - let header = generate_authorization_header(); + let header = generate_authorization_header(context); let client = DROP_CLIENT_ASYNC.clone(); - let url = format!("{}api/v1/client/object/{object_id}", DB.fetch_base_url()); + let url = generate_url(context, &["/api/v1/client/object", object_id], &[]).expect("failed to generated object url"); let response = client.get(url).header("Authorization", header).send().await; if response.is_err() { diff --git a/src-tauri/drop-remote/src/lib.rs b/src-tauri/drop-remote/src/lib.rs index 007a1c8..33df2d7 100644 --- a/src-tauri/drop-remote/src/lib.rs +++ b/src-tauri/drop-remote/src/lib.rs @@ -1,5 +1,29 @@ +use serde::{Deserialize, Serialize}; +use url::Url; + pub mod auth; pub mod cache; pub mod fetch_object; pub mod requests; pub mod utils; + +#[derive(Serialize, Deserialize, Clone)] +struct DropRemoteAuth { + private: String, + cert: String, + client_id: String, + web_token: String, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct DropRemoteContext { + base_url: Url, + auth: Option, +} + + +impl DropRemoteContext { + pub fn new(base_url: Url) -> Self { + DropRemoteContext { base_url, auth: None } + } +} \ No newline at end of file diff --git a/src-tauri/drop-remote/src/requests.rs b/src-tauri/drop-remote/src/requests.rs index c43581b..fb4f2de 100644 --- a/src-tauri/drop-remote/src/requests.rs +++ b/src-tauri/drop-remote/src/requests.rs @@ -1,14 +1,14 @@ -use drop_database::{db::DatabaseImpls as _, DB}; use drop_errors::remote_access_error::RemoteAccessError; use url::Url; -use crate::{auth::generate_authorization_header, utils::DROP_CLIENT_ASYNC}; +use crate::{auth::generate_authorization_header, utils::DROP_CLIENT_ASYNC, DropRemoteContext}; pub fn generate_url>( + context: &DropRemoteContext, path_components: &[T], query: &[(T, T)], ) -> Result { - let mut base_url = DB.fetch_base_url(); + let mut base_url = context.base_url.clone(); for endpoint in path_components { base_url = base_url.join(endpoint.as_ref())?; } @@ -21,10 +21,10 @@ pub fn generate_url>( Ok(base_url) } -pub async fn make_authenticated_get(url: Url) -> Result { +pub async fn make_authenticated_get(context: &DropRemoteContext, url: Url) -> Result { DROP_CLIENT_ASYNC .get(url) - .header("Authorization", generate_authorization_header()) + .header("Authorization", generate_authorization_header(context)) .send() .await } diff --git a/src-tauri/drop-remote/src/utils.rs b/src-tauri/drop-remote/src/utils.rs index 293705c..ff0896f 100644 --- a/src-tauri/drop-remote/src/utils.rs +++ b/src-tauri/drop-remote/src/utils.rs @@ -4,10 +4,9 @@ use std::{ sync::LazyLock, }; -use drop_database::db::DATA_ROOT_DIR; +use drop_consts::DATA_ROOT_DIR; use log::{debug, info}; use reqwest::Certificate; -use serde::Deserialize; static DROP_CERT_BUNDLE: LazyLock> = LazyLock::new(fetch_certificates); pub static DROP_CLIENT_SYNC: LazyLock = LazyLock::new(get_client_sync); diff --git a/src-tauri/src/native_library/downloads/download_logic.rs b/src-tauri/src/native_library/downloads/download_logic.rs index e899bc9..ad76bed 100644 --- a/src-tauri/src/native_library/downloads/download_logic.rs +++ b/src-tauri/src/native_library/downloads/download_logic.rs @@ -1,7 +1,7 @@ use drop_downloads::util::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}; use drop_downloads::util::progress_object::ProgressHandle; use drop_errors::application_download_error::ApplicationDownloadError; -use drop_errors::drop_server_error::DropServerError; +use drop_errors::drop_server_error::ServerError; use drop_errors::remote_access_error::RemoteAccessError; use drop_remote::auth::generate_authorization_header; use drop_remote::requests::generate_url; @@ -197,7 +197,7 @@ pub fn download_game_bucket( ApplicationDownloadError::Communication(RemoteAccessError::FetchError(e.into())) })?; info!("{raw_res}"); - if let Ok(err) = serde_json::from_str::(&raw_res) { + if let Ok(err) = serde_json::from_str::(&raw_res) { return Err(ApplicationDownloadError::Communication( RemoteAccessError::InvalidResponse(err), ));