mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2026-07-15 15:26:34 +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:
@@ -4,8 +4,10 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bitcode = "0.6.7"
|
||||
chrono = "0.4.42"
|
||||
dirs = "6.0.0"
|
||||
drop-consts = { version = "0.1.0", path = "../drop-consts" }
|
||||
log = "0.4.28"
|
||||
native_model = { version = "0.6.4", features = ["rmp_serde_1_3"], git = "https://github.com/Drop-OSS/native_model.git"}
|
||||
rustbreak = "2.0.0"
|
||||
|
||||
@@ -3,24 +3,18 @@ use std::{
|
||||
sync::{Arc, LazyLock},
|
||||
};
|
||||
|
||||
use drop_consts::DATA_ROOT_PREFIX;
|
||||
use rustbreak::{DeSerError, DeSerializer};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
use crate::interface::{DatabaseImpls, DatabaseInterface};
|
||||
use crate::{interface::DatabaseImpls, models::DatabaseInterface};
|
||||
|
||||
pub static DB: LazyLock<DatabaseInterface> = LazyLock::new(DatabaseInterface::set_up_database);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
static DATA_ROOT_PREFIX: &str = "drop";
|
||||
#[cfg(debug_assertions)]
|
||||
static DATA_ROOT_PREFIX: &str = "drop-debug";
|
||||
|
||||
pub static DATA_ROOT_DIR: LazyLock<Arc<PathBuf>> = LazyLock::new(|| {
|
||||
Arc::new(
|
||||
pub static DATA_ROOT_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
dirs::data_dir()
|
||||
.expect("Failed to get data dir")
|
||||
.join(DATA_ROOT_PREFIX),
|
||||
)
|
||||
.join(DATA_ROOT_PREFIX)
|
||||
});
|
||||
|
||||
// Custom JSON serializer to support everything we need
|
||||
|
||||
@@ -9,20 +9,14 @@ use std::{
|
||||
use chrono::Utc;
|
||||
use log::{debug, error, info, warn};
|
||||
use rustbreak::{PathDatabase, RustbreakError};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
db::{DATA_ROOT_DIR, DB, DropDatabaseSerializer},
|
||||
models::data::Database,
|
||||
db::{DropDatabaseSerializer, DATA_ROOT_DIR, DB},
|
||||
models::{Database, DatabaseInterface},
|
||||
};
|
||||
|
||||
pub type DatabaseInterface =
|
||||
rustbreak::Database<Database, rustbreak::backend::PathBackend, DropDatabaseSerializer>;
|
||||
|
||||
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 {
|
||||
@@ -88,16 +82,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 {
|
||||
!borrow_db_checked().base_url.is_empty()
|
||||
}
|
||||
|
||||
fn fetch_base_url(&self) -> Url {
|
||||
let handle = borrow_db_checked();
|
||||
Url::parse(&handle.base_url)
|
||||
.unwrap_or_else(|_| panic!("Failed to parse base url {}", handle.base_url))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make the error relelvant rather than just assume that it's a Deserialize error
|
||||
|
||||
@@ -8,7 +8,7 @@ pub mod platform;
|
||||
|
||||
pub use db::DB;
|
||||
pub use interface::{borrow_db_checked, borrow_db_mut_checked};
|
||||
pub use models::data::{
|
||||
pub use models::{
|
||||
ApplicationTransientStatus, Database, DatabaseApplications, DatabaseAuth, DownloadType,
|
||||
DownloadableMetadata, GameDownloadStatus, GameVersion, Settings,
|
||||
};
|
||||
|
||||
@@ -1,373 +0,0 @@
|
||||
pub mod data {
|
||||
use std::{hash::Hash, path::PathBuf};
|
||||
|
||||
use native_model::native_model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// NOTE: Within each version, you should NEVER use these types.
|
||||
// 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 Settings = v1::Settings;
|
||||
pub type DatabaseAuth = v1::DatabaseAuth;
|
||||
|
||||
pub type GameDownloadStatus = v2::GameDownloadStatus;
|
||||
pub type ApplicationTransientStatus = v1::ApplicationTransientStatus;
|
||||
/**
|
||||
* Need to be universally accessible by the ID, and the version is just a couple sprinkles on top
|
||||
*/
|
||||
pub type DownloadableMetadata = v1::DownloadableMetadata;
|
||||
pub type DownloadType = v1::DownloadType;
|
||||
pub type DatabaseApplications = v2::DatabaseApplications;
|
||||
// pub type DatabaseCompatInfo = v2::DatabaseCompatInfo;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
impl PartialEq for DownloadableMetadata {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id && self.download_type == other.download_type
|
||||
}
|
||||
}
|
||||
impl Hash for DownloadableMetadata {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
self.download_type.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
mod v1 {
|
||||
use serde_with::serde_as;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::platform::Platform;
|
||||
|
||||
use super::{Deserialize, Serialize, native_model};
|
||||
|
||||
fn default_template() -> String {
|
||||
"{}".to_owned()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 2, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct GameVersion {
|
||||
pub game_id: String,
|
||||
pub version_name: String,
|
||||
|
||||
pub platform: Platform,
|
||||
|
||||
pub launch_command: String,
|
||||
pub launch_args: Vec<String>,
|
||||
#[serde(default = "default_template")]
|
||||
pub launch_command_template: String,
|
||||
|
||||
pub setup_command: String,
|
||||
pub setup_args: Vec<String>,
|
||||
#[serde(default = "default_template")]
|
||||
pub setup_command_template: String,
|
||||
|
||||
pub only_setup: bool,
|
||||
|
||||
pub version_index: usize,
|
||||
pub delta: bool,
|
||||
|
||||
pub umu_id_override: Option<String>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 3, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct DatabaseApplications {
|
||||
pub install_dirs: Vec<PathBuf>,
|
||||
// Guaranteed to exist if the game also exists in the app state map
|
||||
pub game_statuses: HashMap<String, GameDownloadStatus>,
|
||||
pub game_versions: HashMap<String, HashMap<String, GameVersion>>,
|
||||
pub installed_game_version: HashMap<String, DownloadableMetadata>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub transient_statuses: HashMap<DownloadableMetadata, ApplicationTransientStatus>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 4, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct Settings {
|
||||
pub autostart: bool,
|
||||
pub max_download_threads: usize,
|
||||
pub force_offline: bool, // ... other settings ...
|
||||
}
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
autostart: false,
|
||||
max_download_threads: 4,
|
||||
force_offline: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strings are version names for a particular game
|
||||
#[derive(Serialize, Clone, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
#[native_model(id = 5, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub enum GameDownloadStatus {
|
||||
Remote {},
|
||||
SetupRequired {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
Installed {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
}
|
||||
|
||||
// Stuff that shouldn't be synced to disk
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum ApplicationTransientStatus {
|
||||
Queued { version_name: String },
|
||||
Downloading { version_name: String },
|
||||
Uninstalling {},
|
||||
Updating { version_name: String },
|
||||
Validating { version_name: String },
|
||||
Running {},
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Clone, Deserialize)]
|
||||
#[native_model(id = 6, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct DatabaseAuth {
|
||||
pub private: String,
|
||||
pub cert: String,
|
||||
pub client_id: String,
|
||||
pub web_token: Option<String>,
|
||||
}
|
||||
|
||||
#[native_model(id = 8, version = 1)]
|
||||
#[derive(
|
||||
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Clone, Copy,
|
||||
)]
|
||||
pub enum DownloadType {
|
||||
Game,
|
||||
Tool,
|
||||
Dlc,
|
||||
Mod,
|
||||
}
|
||||
|
||||
#[native_model(id = 7, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Debug, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DownloadableMetadata {
|
||||
pub id: String,
|
||||
pub version: Option<String>,
|
||||
pub download_type: DownloadType,
|
||||
}
|
||||
impl DownloadableMetadata {
|
||||
pub fn new(id: String, version: Option<String>, download_type: DownloadType) -> Self {
|
||||
Self {
|
||||
id,
|
||||
version,
|
||||
download_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[native_model(id = 1, version = 1)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: Settings,
|
||||
pub auth: Option<DatabaseAuth>,
|
||||
pub base_url: String,
|
||||
pub applications: DatabaseApplications,
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
}
|
||||
}
|
||||
|
||||
mod v2 {
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use serde_with::serde_as;
|
||||
|
||||
use super::{Deserialize, Serialize, native_model, v1};
|
||||
|
||||
#[native_model(id = 1, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from = v1::Database)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: v1::Settings,
|
||||
pub auth: Option<v1::DatabaseAuth>,
|
||||
pub base_url: String,
|
||||
pub applications: v1::DatabaseApplications,
|
||||
#[serde(skip)]
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
pub compat_info: Option<DatabaseCompatInfo>,
|
||||
}
|
||||
|
||||
#[native_model(id = 9, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
|
||||
pub struct DatabaseCompatInfo {
|
||||
pub umu_installed: bool,
|
||||
}
|
||||
|
||||
impl From<v1::Database> for Database {
|
||||
fn from(value: v1::Database) -> Self {
|
||||
Self {
|
||||
settings: value.settings,
|
||||
auth: value.auth,
|
||||
base_url: value.base_url,
|
||||
applications: value.applications,
|
||||
prev_database: value.prev_database,
|
||||
cache_dir: value.cache_dir,
|
||||
compat_info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Strings are version names for a particular game
|
||||
#[derive(Serialize, Clone, Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
#[native_model(id = 5, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from = v1::GameDownloadStatus)]
|
||||
pub enum GameDownloadStatus {
|
||||
Remote {},
|
||||
SetupRequired {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
Installed {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
PartiallyInstalled {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
}
|
||||
impl From<v1::GameDownloadStatus> for GameDownloadStatus {
|
||||
fn from(value: v1::GameDownloadStatus) -> Self {
|
||||
match value {
|
||||
v1::GameDownloadStatus::Remote {} => Self::Remote {},
|
||||
v1::GameDownloadStatus::SetupRequired {
|
||||
version_name,
|
||||
install_dir,
|
||||
} => Self::SetupRequired {
|
||||
version_name,
|
||||
install_dir,
|
||||
},
|
||||
v1::GameDownloadStatus::Installed {
|
||||
version_name,
|
||||
install_dir,
|
||||
} => Self::Installed {
|
||||
version_name,
|
||||
install_dir,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 3, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from=v1::DatabaseApplications)]
|
||||
pub struct DatabaseApplications {
|
||||
pub install_dirs: Vec<PathBuf>,
|
||||
// Guaranteed to exist if the game also exists in the app state map
|
||||
pub game_statuses: HashMap<String, GameDownloadStatus>,
|
||||
|
||||
pub game_versions: HashMap<String, HashMap<String, v1::GameVersion>>,
|
||||
pub installed_game_version: HashMap<String, v1::DownloadableMetadata>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub transient_statuses:
|
||||
HashMap<v1::DownloadableMetadata, v1::ApplicationTransientStatus>,
|
||||
}
|
||||
impl From<v1::DatabaseApplications> for DatabaseApplications {
|
||||
fn from(value: v1::DatabaseApplications) -> Self {
|
||||
Self {
|
||||
game_statuses: value
|
||||
.game_statuses
|
||||
.into_iter()
|
||||
.map(|x| (x.0, x.1.into()))
|
||||
.collect::<HashMap<String, GameDownloadStatus>>(),
|
||||
install_dirs: value.install_dirs,
|
||||
game_versions: value.game_versions,
|
||||
installed_game_version: value.installed_game_version,
|
||||
transient_statuses: value.transient_statuses,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mod v3 {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::{Deserialize, Serialize, native_model, v1, v2};
|
||||
#[native_model(id = 1, version = 3, with = native_model::rmp_serde_1_3::RmpSerde, from = v2::Database)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: v1::Settings,
|
||||
pub auth: Option<v1::DatabaseAuth>,
|
||||
pub base_url: String,
|
||||
pub applications: v2::DatabaseApplications,
|
||||
#[serde(skip)]
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
pub compat_info: Option<v2::DatabaseCompatInfo>,
|
||||
}
|
||||
|
||||
impl From<v2::Database> for Database {
|
||||
fn from(value: v2::Database) -> Self {
|
||||
Self {
|
||||
settings: value.settings,
|
||||
auth: value.auth,
|
||||
base_url: value.base_url,
|
||||
applications: value.applications.into(),
|
||||
prev_database: value.prev_database,
|
||||
cache_dir: value.cache_dir,
|
||||
compat_info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new<T: Into<PathBuf>>(
|
||||
games_base_dir: T,
|
||||
prev_database: Option<PathBuf>,
|
||||
cache_dir: PathBuf,
|
||||
) -> Self {
|
||||
Self {
|
||||
applications: DatabaseApplications {
|
||||
install_dirs: vec![games_base_dir.into()],
|
||||
game_statuses: HashMap::new(),
|
||||
game_versions: HashMap::new(),
|
||||
installed_game_version: HashMap::new(),
|
||||
transient_statuses: HashMap::new(),
|
||||
},
|
||||
prev_database,
|
||||
base_url: String::new(),
|
||||
auth: None,
|
||||
settings: Settings::default(),
|
||||
cache_dir,
|
||||
compat_info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DatabaseAuth {
|
||||
pub fn new(
|
||||
private: String,
|
||||
cert: String,
|
||||
client_id: String,
|
||||
web_token: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
private,
|
||||
cert,
|
||||
client_id,
|
||||
web_token,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
mod v1;
|
||||
mod v2;
|
||||
mod v3;
|
||||
mod v4;
|
||||
|
||||
use std::{hash::Hash, path::PathBuf};
|
||||
|
||||
use native_model::native_model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::db::DropDatabaseSerializer;
|
||||
|
||||
|
||||
// NOTE: Within each version, you should NEVER use these types.
|
||||
// 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 = v4::Database;
|
||||
pub type Settings = v1::Settings;
|
||||
pub type DatabaseAuth = v1::DatabaseAuth;
|
||||
|
||||
pub type GameDownloadStatus = v2::GameDownloadStatus;
|
||||
pub type ApplicationTransientStatus = v1::ApplicationTransientStatus;
|
||||
/**
|
||||
* Need to be universally accessible by the ID, and the version is just a couple sprinkles on top
|
||||
*/
|
||||
pub type DownloadableMetadata = v1::DownloadableMetadata;
|
||||
pub type DownloadType = v1::DownloadType;
|
||||
pub type DatabaseApplications = v2::DatabaseApplications;
|
||||
// pub type DatabaseCompatInfo = v2::DatabaseCompatInfo;
|
||||
|
||||
pub type Game = v1::Game;
|
||||
|
||||
impl Game {
|
||||
pub fn id(&self) -> &String {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
pub type DatabaseInterface =
|
||||
rustbreak::Database<Database, rustbreak::backend::PathBackend, DropDatabaseSerializer>;
|
||||
|
||||
pub type LibraryMetadata = v1::LibraryMetadata;
|
||||
pub type LibraryProviderMetadata = v1::LibraryProviderMetadata;
|
||||
pub type ProviderType = v1::ProviderType;
|
||||
|
||||
pub type Collection = v1::Collection;
|
||||
pub type CollectionObject = v1::CollectionObject;
|
||||
|
||||
impl PartialEq for DownloadableMetadata {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id && self.download_type == other.download_type
|
||||
}
|
||||
}
|
||||
impl Hash for DownloadableMetadata {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.id.hash(state);
|
||||
self.download_type.hash(state);
|
||||
}
|
||||
}
|
||||
impl LibraryProviderMetadata {
|
||||
pub fn provider(&self) -> &ProviderType {
|
||||
&self.provider
|
||||
}
|
||||
pub fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl Database {
|
||||
pub fn new<T: Into<PathBuf>>(
|
||||
games_base_dir: T,
|
||||
prev_database: Option<PathBuf>,
|
||||
cache_dir: PathBuf,
|
||||
) -> Self {
|
||||
Self {
|
||||
prev_database,
|
||||
settings: Settings::default(),
|
||||
cache_dir,
|
||||
compat_info: None,
|
||||
library: v1::LibraryMetadata { providers: vec![] },
|
||||
}
|
||||
}
|
||||
}
|
||||
impl DatabaseAuth {
|
||||
pub fn new(
|
||||
private: String,
|
||||
cert: String,
|
||||
client_id: String,
|
||||
web_token: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
private,
|
||||
cert,
|
||||
client_id,
|
||||
web_token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LibraryMetadata {
|
||||
pub fn providers(&self) -> &Vec<LibraryProviderMetadata> {
|
||||
&self.providers
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
use bitcode::{Decode, Encode};
|
||||
use serde_with::serde_as;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use crate::{models::v1, platform::Platform};
|
||||
|
||||
use super::{Deserialize, Serialize, native_model};
|
||||
|
||||
fn default_template() -> String {
|
||||
"{}".to_owned()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 2, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct GameVersion {
|
||||
pub game_id: String,
|
||||
pub version_name: String,
|
||||
|
||||
pub platform: Platform,
|
||||
|
||||
pub launch_command: String,
|
||||
pub launch_args: Vec<String>,
|
||||
#[serde(default = "default_template")]
|
||||
pub launch_command_template: String,
|
||||
|
||||
pub setup_command: String,
|
||||
pub setup_args: Vec<String>,
|
||||
#[serde(default = "default_template")]
|
||||
pub setup_command_template: String,
|
||||
|
||||
pub only_setup: bool,
|
||||
|
||||
pub version_index: usize,
|
||||
pub delta: bool,
|
||||
|
||||
pub umu_id_override: Option<String>,
|
||||
}
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 3, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct DatabaseApplications {
|
||||
pub install_dirs: Vec<PathBuf>,
|
||||
// Guaranteed to exist if the game also exists in the app state map
|
||||
pub game_statuses: HashMap<String, v1::GameDownloadStatus>,
|
||||
pub game_versions: HashMap<String, HashMap<String, v1::GameVersion>>,
|
||||
pub installed_game_version: HashMap<String, v1::DownloadableMetadata>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub transient_statuses: HashMap<v1::DownloadableMetadata, v1::ApplicationTransientStatus>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 4, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct Settings {
|
||||
pub autostart: bool,
|
||||
pub max_download_threads: usize,
|
||||
pub force_offline: bool, // ... other settings ...
|
||||
}
|
||||
impl Default for Settings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
autostart: false,
|
||||
max_download_threads: 4,
|
||||
force_offline: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strings are version names for a particular game
|
||||
#[derive(Serialize, Clone, Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
#[native_model(id = 5, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub enum GameDownloadStatus {
|
||||
Remote {},
|
||||
SetupRequired {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
Installed {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
}
|
||||
|
||||
// Stuff that shouldn't be synced to disk
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub enum ApplicationTransientStatus {
|
||||
Queued { version_name: String },
|
||||
Downloading { version_name: String },
|
||||
Uninstalling {},
|
||||
Updating { version_name: String },
|
||||
Validating { version_name: String },
|
||||
Running {},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, Encode, Decode)]
|
||||
#[native_model(id = 6, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
pub struct DatabaseAuth {
|
||||
pub private: String,
|
||||
pub cert: String,
|
||||
pub client_id: String,
|
||||
pub web_token: Option<String>,
|
||||
}
|
||||
|
||||
#[native_model(id = 8, version = 1)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Clone, Copy)]
|
||||
pub enum DownloadType {
|
||||
Game,
|
||||
Tool,
|
||||
Dlc,
|
||||
Mod,
|
||||
}
|
||||
|
||||
#[native_model(id = 7, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Debug, Eq, PartialOrd, Ord, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DownloadableMetadata {
|
||||
pub id: String,
|
||||
pub version: Option<String>,
|
||||
pub download_type: v1::DownloadType,
|
||||
}
|
||||
impl DownloadableMetadata {
|
||||
pub fn new(id: String, version: Option<String>, download_type: v1::DownloadType) -> Self {
|
||||
Self {
|
||||
id,
|
||||
version,
|
||||
download_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[native_model(id = 1, version = 1)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: Settings,
|
||||
pub auth: Option<v1::DatabaseAuth>,
|
||||
pub base_url: String,
|
||||
pub applications: v1::DatabaseApplications,
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
}
|
||||
#[native_model(id = 15, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Encode, Decode, Default)]
|
||||
pub struct LibraryMetadata {
|
||||
pub(crate) providers: Vec<v1::LibraryProviderMetadata>
|
||||
}
|
||||
|
||||
|
||||
#[native_model(id = 11, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Encode, Decode)]
|
||||
pub struct LibraryProviderMetadata {
|
||||
pub(crate) id: usize,
|
||||
pub(crate) name: String,
|
||||
pub(crate) provider: v1::ProviderType
|
||||
}
|
||||
#[native_model(id = 10, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Encode, Decode)]
|
||||
pub enum ProviderType {
|
||||
Drop(v1::DatabaseAuth),
|
||||
}
|
||||
#[native_model(id = 12, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Encode, Decode)]
|
||||
pub struct Game {
|
||||
pub library_id: LibraryProviderMetadata,
|
||||
pub(crate) id: String,
|
||||
m_name: String,
|
||||
m_short_description: String,
|
||||
m_description: String,
|
||||
// mDevelopers
|
||||
// mPublishers
|
||||
m_icon_object_id: String,
|
||||
m_banner_object_id: String,
|
||||
m_cover_object_id: String,
|
||||
m_image_library_object_ids: Vec<String>,
|
||||
m_image_carousel_object_ids: Vec<String>,
|
||||
}
|
||||
|
||||
#[native_model(id = 13, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Collection {
|
||||
id: String,
|
||||
name: String,
|
||||
is_default: bool,
|
||||
user_id: String,
|
||||
entries: Vec<CollectionObject>,
|
||||
}
|
||||
|
||||
#[native_model(id = 14, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CollectionObject {
|
||||
collection_id: String,
|
||||
game_id: String,
|
||||
game: Game,
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use serde_with::serde_as;
|
||||
|
||||
use super::{Deserialize, Serialize, native_model, v1};
|
||||
|
||||
#[native_model(id = 1, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from = v1::Database)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: v1::Settings,
|
||||
pub auth: Option<v1::DatabaseAuth>,
|
||||
pub base_url: String,
|
||||
pub applications: v1::DatabaseApplications,
|
||||
#[serde(skip)]
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
pub compat_info: Option<DatabaseCompatInfo>,
|
||||
}
|
||||
|
||||
#[native_model(id = 9, version = 1, with = native_model::rmp_serde_1_3::RmpSerde)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
|
||||
pub struct DatabaseCompatInfo {
|
||||
pub umu_installed: bool,
|
||||
}
|
||||
|
||||
impl From<v1::Database> for Database {
|
||||
fn from(value: v1::Database) -> Self {
|
||||
Self {
|
||||
settings: value.settings,
|
||||
auth: value.auth,
|
||||
base_url: value.base_url,
|
||||
applications: value.applications,
|
||||
prev_database: value.prev_database,
|
||||
cache_dir: value.cache_dir,
|
||||
compat_info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Strings are version names for a particular game
|
||||
#[derive(Serialize, Clone, Deserialize, Debug)]
|
||||
#[serde(tag = "type")]
|
||||
#[native_model(id = 5, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from = v1::GameDownloadStatus)]
|
||||
pub enum GameDownloadStatus {
|
||||
Remote {},
|
||||
SetupRequired {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
Installed {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
PartiallyInstalled {
|
||||
version_name: String,
|
||||
install_dir: String,
|
||||
},
|
||||
}
|
||||
impl From<v1::GameDownloadStatus> for GameDownloadStatus {
|
||||
fn from(value: v1::GameDownloadStatus) -> Self {
|
||||
match value {
|
||||
v1::GameDownloadStatus::Remote {} => Self::Remote {},
|
||||
v1::GameDownloadStatus::SetupRequired {
|
||||
version_name,
|
||||
install_dir,
|
||||
} => Self::SetupRequired {
|
||||
version_name,
|
||||
install_dir,
|
||||
},
|
||||
v1::GameDownloadStatus::Installed {
|
||||
version_name,
|
||||
install_dir,
|
||||
} => Self::Installed {
|
||||
version_name,
|
||||
install_dir,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Clone, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 3, version = 2, with = native_model::rmp_serde_1_3::RmpSerde, from=v1::DatabaseApplications)]
|
||||
pub struct DatabaseApplications {
|
||||
pub install_dirs: Vec<PathBuf>,
|
||||
// Guaranteed to exist if the game also exists in the app state map
|
||||
pub game_statuses: HashMap<String, GameDownloadStatus>,
|
||||
|
||||
pub game_versions: HashMap<String, HashMap<String, v1::GameVersion>>,
|
||||
pub installed_game_version: HashMap<String, v1::DownloadableMetadata>,
|
||||
|
||||
#[serde(skip)]
|
||||
pub transient_statuses:
|
||||
HashMap<v1::DownloadableMetadata, v1::ApplicationTransientStatus>,
|
||||
}
|
||||
impl From<v1::DatabaseApplications> for DatabaseApplications {
|
||||
fn from(value: v1::DatabaseApplications) -> Self {
|
||||
Self {
|
||||
game_statuses: value
|
||||
.game_statuses
|
||||
.into_iter()
|
||||
.map(|x| (x.0, x.1.into()))
|
||||
.collect::<HashMap<String, GameDownloadStatus>>(),
|
||||
install_dirs: value.install_dirs,
|
||||
game_versions: value.game_versions,
|
||||
installed_game_version: value.installed_game_version,
|
||||
transient_statuses: value.transient_statuses,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use serde_with::serde_as;
|
||||
|
||||
use super::{Deserialize, Serialize, native_model, v1, v2};
|
||||
#[native_model(id = 1, version = 3, with = native_model::rmp_serde_1_3::RmpSerde, from = v2::Database)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: v1::Settings,
|
||||
pub auth: Option<v1::DatabaseAuth>,
|
||||
pub base_url: String,
|
||||
pub applications: v2::DatabaseApplications,
|
||||
#[serde(skip)]
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
pub compat_info: Option<v2::DatabaseCompatInfo>,
|
||||
}
|
||||
|
||||
impl From<v2::Database> for Database {
|
||||
fn from(value: v2::Database) -> Self {
|
||||
Self {
|
||||
settings: value.settings,
|
||||
auth: value.auth,
|
||||
base_url: value.base_url,
|
||||
applications: value.applications.into(),
|
||||
prev_database: value.prev_database,
|
||||
cache_dir: value.cache_dir,
|
||||
compat_info: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use native_model::native_model;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::models::{
|
||||
v1::{self, LibraryMetadata},
|
||||
v2, v3,
|
||||
};
|
||||
|
||||
#[native_model(id = 1, version = 4, with = native_model::rmp_serde_1_3::RmpSerde, from = v3::Database)]
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Database {
|
||||
#[serde(default)]
|
||||
pub settings: v1::Settings,
|
||||
#[serde(skip)]
|
||||
pub prev_database: Option<PathBuf>,
|
||||
pub cache_dir: PathBuf,
|
||||
pub compat_info: Option<v2::DatabaseCompatInfo>,
|
||||
pub library: v1::LibraryMetadata,
|
||||
}
|
||||
|
||||
impl From<v3::Database> for Database {
|
||||
fn from(value: v3::Database) -> Self {
|
||||
Self {
|
||||
settings: value.settings,
|
||||
prev_database: value.prev_database,
|
||||
cache_dir: value.cache_dir,
|
||||
compat_info: value.compat_info,
|
||||
library: v1::LibraryMetadata {
|
||||
providers: if let Some(auth) = value.auth {
|
||||
vec![v1::LibraryProviderMetadata {
|
||||
id: 0,
|
||||
name: String::from("Default"),
|
||||
provider: v1::ProviderType::Drop(auth),
|
||||
}]
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user