feat: move to native_model to allow for database upgrades
This commit is contained in:
@@ -7,13 +7,13 @@ use std::{
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
database::{db::borrow_db_mut_checked, settings::Settings},
|
||||
database::{db::borrow_db_mut_checked},
|
||||
download_manager::internal_error::InternalError,
|
||||
};
|
||||
|
||||
use super::{
|
||||
db::{borrow_db_checked, save_db, DATA_ROOT_DIR},
|
||||
debug::SystemData,
|
||||
debug::SystemData, models::data::Settings,
|
||||
};
|
||||
|
||||
// Will, in future, return disk/remaining size
|
||||
|
||||
@@ -15,122 +15,10 @@ use serde_with::serde_as;
|
||||
use tauri::AppHandle;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
database::settings::Settings,
|
||||
download_manager::downloadable_metadata::DownloadableMetadata,
|
||||
games::{library::push_game_update, state::GameStatusManager},
|
||||
process::process_manager::Platform,
|
||||
DB,
|
||||
};
|
||||
use crate::DB;
|
||||
|
||||
#[derive(serde::Serialize, Clone, Deserialize)]
|
||||
pub struct DatabaseAuth {
|
||||
pub private: String,
|
||||
pub cert: String,
|
||||
pub client_id: String,
|
||||
pub web_token: Option<String>,
|
||||
}
|
||||
use super::models::data::{Database, GameVersion};
|
||||
|
||||
// Strings are version names for a particular game
|
||||
#[derive(Serialize, Clone, Deserialize)]
|
||||
#[serde(tag = "type")]
|
||||
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)]
|
||||
pub enum ApplicationTransientStatus {
|
||||
Downloading { version_name: String },
|
||||
Uninstalling {},
|
||||
Updating { version_name: String },
|
||||
Running {},
|
||||
}
|
||||
|
||||
fn default_template() -> String {
|
||||
"{}".to_owned()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
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")]
|
||||
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, 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,
|
||||
}
|
||||
impl Database {
|
||||
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: "".to_owned(),
|
||||
auth: None,
|
||||
settings: Settings::default(),
|
||||
cache_dir,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> =
|
||||
LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop")));
|
||||
|
||||
@@ -138,13 +26,20 @@ pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> =
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct DropDatabaseSerializer;
|
||||
|
||||
impl<T: Serialize + DeserializeOwned> DeSerializer<T> for DropDatabaseSerializer {
|
||||
impl<T: native_model::Model + Serialize + DeserializeOwned> DeSerializer<T>
|
||||
for DropDatabaseSerializer
|
||||
{
|
||||
fn serialize(&self, val: &T) -> rustbreak::error::DeSerResult<Vec<u8>> {
|
||||
serde_json::to_vec(val).map_err(|e| DeSerError::Internal(e.to_string()))
|
||||
native_model::encode(val).map_err(|e| DeSerError::Internal(e.to_string()))
|
||||
}
|
||||
|
||||
fn deserialize<R: std::io::Read>(&self, s: R) -> rustbreak::error::DeSerResult<T> {
|
||||
serde_json::from_reader(s).map_err(|e| DeSerError::Internal(e.to_string()))
|
||||
fn deserialize<R: std::io::Read>(&self, mut s: R) -> rustbreak::error::DeSerResult<T> {
|
||||
let mut buf = Vec::new();
|
||||
s.read_to_end(&mut buf)
|
||||
.map_err(|e| rustbreak::error::DeSerError::Other(e.into()))?;
|
||||
let (val, _version) =
|
||||
native_model::decode::<T>(buf).map_err(|e| DeSerError::Internal(e.to_string()))?;
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
pub mod commands;
|
||||
pub mod db;
|
||||
pub mod debug;
|
||||
pub mod settings;
|
||||
pub mod models;
|
||||
@@ -0,0 +1,184 @@
|
||||
pub mod data {
|
||||
use native_model::{native_model, Model};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type GameVersion = v1::GameVersion;
|
||||
pub type Database = v1::Database;
|
||||
pub type Settings = v1::Settings;
|
||||
pub type DatabaseAuth = v1::DatabaseAuth;
|
||||
|
||||
pub type GameDownloadStatus = v1::GameDownloadStatus;
|
||||
pub type ApplicationTransientStatus = v1::ApplicationTransientStatus;
|
||||
pub type DownloadableMetadata = v1::DownloadableMetadata;
|
||||
pub type DownloadType = v1::DownloadType;
|
||||
|
||||
pub mod v1 {
|
||||
use crate::process::process_manager::Platform;
|
||||
use serde_with::serde_as;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
|
||||
use super::*;
|
||||
|
||||
fn default_template() -> String {
|
||||
"{}".to_owned()
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[native_model(id = 2, version = 1)]
|
||||
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)]
|
||||
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)]
|
||||
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)]
|
||||
pub enum ApplicationTransientStatus {
|
||||
Downloading { version_name: String },
|
||||
Uninstalling {},
|
||||
Updating { version_name: String },
|
||||
Running {},
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize, Clone, Deserialize)]
|
||||
#[native_model(id = 6, version = 1)]
|
||||
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)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, 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,
|
||||
}
|
||||
|
||||
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: "".to_owned(),
|
||||
auth: None,
|
||||
settings: Settings::default(),
|
||||
cache_dir,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ideally use pointers instead of a macro to assign the settings
|
||||
// fn deserialize_into<T>(v: serde_json::Value, t: &mut T) -> Result<(), serde_json::Error>
|
||||
// where T: for<'a> Deserialize<'a>
|
||||
// {
|
||||
// *t = serde_json::from_value(v)?;
|
||||
// Ok(())
|
||||
// }
|
||||
Reference in New Issue
Block a user