Merge branch 'compat' into develop

Signed-off-by: quexeky <git@quexeky.dev>
This commit is contained in:
quexeky
2025-05-28 11:24:30 +10:00
46 changed files with 275 additions and 171 deletions

3
.gitmodules vendored
View File

@ -4,3 +4,6 @@
[submodule "src-tauri/tailscale/libtailscale"] [submodule "src-tauri/tailscale/libtailscale"]
path = src-tauri/tailscale/libtailscale path = src-tauri/tailscale/libtailscale
url = https://github.com/tailscale/libtailscale.git url = https://github.com/tailscale/libtailscale.git
[submodule "src-tauri/umu/umu-launcher"]
path = src-tauri/umu/umu-launcher
url = https://github.com/Open-Wine-Components/umu-launcher.git

43
src-tauri/Cargo.lock generated
View File

@ -1332,6 +1332,7 @@ dependencies = [
"log", "log",
"log4rs", "log4rs",
"md5", "md5",
"memfd-exec",
"native_model", "native_model",
"parking_lot 0.12.3", "parking_lot 0.12.3",
"rayon", "rayon",
@ -1571,7 +1572,7 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f"
dependencies = [ dependencies = [
"memoffset", "memoffset 0.9.1",
"rustc_version", "rustc_version",
] ]
@ -2948,6 +2949,16 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "memfd-exec"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e627eb44f3789e87dccac3f4c7279a608cbf14ff71f2c54f122f44a07e2ca338"
dependencies = [
"libc",
"nix 0.26.4",
]
[[package]] [[package]]
name = "memmap" name = "memmap"
version = "0.7.0" version = "0.7.0"
@ -2967,6 +2978,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "memoffset"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "memoffset" name = "memoffset"
version = "0.9.1" version = "0.9.1"
@ -3126,6 +3146,19 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "nix"
version = "0.26.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b"
dependencies = [
"bitflags 1.3.2",
"cfg-if",
"libc",
"memoffset 0.7.1",
"pin-utils",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.30.1" version = "0.30.1"
@ -3136,7 +3169,7 @@ dependencies = [
"cfg-if", "cfg-if",
"cfg_aliases", "cfg_aliases",
"libc", "libc",
"memoffset", "memoffset 0.9.1",
] ]
[[package]] [[package]]
@ -4032,7 +4065,7 @@ dependencies = [
"once_cell", "once_cell",
"socket2", "socket2",
"tracing", "tracing",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -6152,7 +6185,7 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9"
dependencies = [ dependencies = [
"memoffset", "memoffset 0.9.1",
"tempfile", "tempfile",
"winapi", "winapi",
] ]
@ -7314,7 +7347,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-lite", "futures-lite",
"hex 0.4.3", "hex 0.4.3",
"nix", "nix 0.30.1",
"ordered-stream", "ordered-stream",
"serde", "serde",
"serde_repr", "serde_repr",

View File

@ -57,6 +57,7 @@ droplet-rs = "0.7.3"
gethostname = "1.0.1" gethostname = "1.0.1"
native_model = { version = "0.6.1", features = ["rmp_serde_1_3"] } native_model = { version = "0.6.1", features = ["rmp_serde_1_3"] }
tailscale = { path = "./tailscale" } tailscale = { path = "./tailscale" }
memfd-exec = "0.2.1"
[dependencies.dynfmt] [dependencies.dynfmt]
version = "0.1.5" version = "0.1.5"

View File

@ -0,0 +1,3 @@
pub mod autostart;
pub mod cleanup;
pub mod commands;

View File

@ -6,14 +6,12 @@ use std::{
use serde_json::Value; use serde_json::Value;
use crate::{ use crate::{database::db::borrow_db_mut_checked, error::download_manager_error::DownloadManagerError};
database::{db::borrow_db_mut_checked},
download_manager::internal_error::InternalError,
};
use super::{ use super::{
db::{borrow_db_checked, save_db, DATA_ROOT_DIR}, db::{borrow_db_checked, save_db, DATA_ROOT_DIR},
debug::SystemData, models::data::Settings, debug::SystemData,
models::data::Settings,
}; };
// Will, in future, return disk/remaining size // Will, in future, return disk/remaining size
@ -33,7 +31,7 @@ pub fn delete_download_dir(index: usize) {
} }
#[tauri::command] #[tauri::command]
pub fn add_download_dir(new_dir: PathBuf) -> Result<(), InternalError<()>> { pub fn add_download_dir(new_dir: PathBuf) -> Result<(), DownloadManagerError<()>> {
// Check the new directory is all good // Check the new directory is all good
let new_dir_path = Path::new(&new_dir); let new_dir_path = Path::new(&new_dir);
if new_dir_path.exists() { if new_dir_path.exists() {

View File

@ -1,8 +1,6 @@
use std::{ use std::{
collections::HashMap,
fs::{self, create_dir_all}, fs::{self, create_dir_all},
hash::Hash, path::PathBuf,
path::{Path, PathBuf},
sync::{LazyLock, Mutex, RwLockReadGuard, RwLockWriteGuard}, sync::{LazyLock, Mutex, RwLockReadGuard, RwLockWriteGuard},
}; };
@ -10,14 +8,12 @@ use chrono::Utc;
use directories::BaseDirs; use directories::BaseDirs;
use log::{debug, error, info}; use log::{debug, error, info};
use rustbreak::{DeSerError, DeSerializer, PathDatabase, RustbreakError}; use rustbreak::{DeSerError, DeSerializer, PathDatabase, RustbreakError};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Serialize};
use serde_with::serde_as;
use tauri::AppHandle;
use url::Url; use url::Url;
use crate::DB; use crate::DB;
use super::models::data::{Database, GameVersion}; use super::models::data::Database;
pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> = pub static DATA_ROOT_DIR: LazyLock<Mutex<PathBuf>> =
LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop"))); LazyLock::new(|| Mutex::new(BaseDirs::new().unwrap().data_dir().join("drop")));
@ -58,12 +54,14 @@ impl DatabaseImpls for DatabaseInterface {
let games_base_dir = data_root_dir.join("games"); let games_base_dir = data_root_dir.join("games");
let logs_root_dir = data_root_dir.join("logs"); let logs_root_dir = data_root_dir.join("logs");
let cache_dir = data_root_dir.join("cache"); let cache_dir = data_root_dir.join("cache");
let pfx_dir = data_root_dir.join("pfx");
debug!("creating data directory at {:?}", data_root_dir); debug!("creating data directory at {:?}", data_root_dir);
create_dir_all(data_root_dir.clone()).unwrap(); create_dir_all(data_root_dir.clone()).unwrap();
create_dir_all(&games_base_dir).unwrap(); create_dir_all(&games_base_dir).unwrap();
create_dir_all(&logs_root_dir).unwrap(); create_dir_all(&logs_root_dir).unwrap();
create_dir_all(&cache_dir).unwrap(); create_dir_all(&cache_dir).unwrap();
create_dir_all(&pfx_dir).unwrap();
let exists = fs::exists(db_path.clone()).unwrap(); let exists = fs::exists(db_path.clone()).unwrap();

View File

@ -1,4 +1,4 @@
pub mod commands; pub mod commands;
pub mod db; pub mod db;
pub mod debug; pub mod debug;
pub mod models; pub mod models;

View File

@ -3,7 +3,7 @@ pub mod data {
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub type GameVersion = v1::GameVersion; pub type GameVersion = v1::GameVersion;
pub type Database = v1::Database; pub type Database = v2::Database;
pub type Settings = v1::Settings; pub type Settings = v1::Settings;
pub type DatabaseAuth = v1::DatabaseAuth; pub type DatabaseAuth = v1::DatabaseAuth;
@ -11,6 +11,8 @@ pub mod data {
pub type ApplicationTransientStatus = v1::ApplicationTransientStatus; pub type ApplicationTransientStatus = v1::ApplicationTransientStatus;
pub type DownloadableMetadata = v1::DownloadableMetadata; pub type DownloadableMetadata = v1::DownloadableMetadata;
pub type DownloadType = v1::DownloadType; pub type DownloadType = v1::DownloadType;
pub type DatabaseApplications = v1::DatabaseApplications;
pub type DatabaseCompatInfo = v2::DatabaseCompatInfo;
pub mod v1 { pub mod v1 {
use crate::process::process_manager::Platform; use crate::process::process_manager::Platform;
@ -157,8 +159,46 @@ pub mod data {
pub prev_database: Option<PathBuf>, pub prev_database: Option<PathBuf>,
pub cache_dir: PathBuf, pub cache_dir: PathBuf,
} }
}
pub mod v2 {
use std::{collections::HashMap, path::PathBuf, process::Command};
use crate::process::process_manager::UMU_LAUNCHER_EXECUTABLE;
use super::*;
#[native_model(id = 1, version = 2)]
#[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,
pub compat_info: Option<DatabaseCompatInfo>,
}
#[native_model(id = 8, version = 2)]
#[derive(Serialize, Deserialize, Clone, Default)]
pub struct DatabaseCompatInfo {
umu_installed: bool,
}
impl Database { impl Database {
fn create_new_compat_info() -> Option<DatabaseCompatInfo> {
#[cfg(target_os = "windows")]
return None;
let has_umu_installed = Command::new(UMU_LAUNCHER_EXECUTABLE).spawn().is_ok();
Some(DatabaseCompatInfo {
umu_installed: has_umu_installed,
})
}
pub fn new<T: Into<PathBuf>>( pub fn new<T: Into<PathBuf>>(
games_base_dir: T, games_base_dir: T,
prev_database: Option<PathBuf>, prev_database: Option<PathBuf>,
@ -177,6 +217,21 @@ pub mod data {
auth: None, auth: None,
settings: Settings::default(), settings: Settings::default(),
cache_dir, cache_dir,
compat_info: Database::create_new_compat_info(),
}
}
}
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: Database::create_new_compat_info(),
} }
} }
} }

View File

@ -12,11 +12,13 @@ use std::{
use log::{debug, info}; use log::{debug, info};
use serde::Serialize; use serde::Serialize;
use crate::{database::models::data::DownloadableMetadata, error::application_download_error::ApplicationDownloadError}; use crate::{
database::models::data::DownloadableMetadata,
error::application_download_error::ApplicationDownloadError,
};
use super::{ use super::{
download_manager_builder::{CurrentProgressObject, DownloadAgent}, download_manager_builder::{CurrentProgressObject, DownloadAgent}, util::queue::Queue,
queue::Queue,
}; };
pub enum DownloadManagerSignal { pub enum DownloadManagerSignal {

View File

@ -11,15 +11,14 @@ use log::{debug, error, info, warn};
use tauri::{AppHandle, Emitter}; use tauri::{AppHandle, Emitter};
use crate::{ use crate::{
database::models::data::DownloadableMetadata, error::application_download_error::ApplicationDownloadError, games::library::{QueueUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent} database::models::data::DownloadableMetadata,
error::application_download_error::ApplicationDownloadError,
games::library::{QueueUpdateEvent, QueueUpdateEventQueueData, StatsUpdateEvent},
}; };
use super::{ use super::{
download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus}, download_manager::{DownloadManager, DownloadManagerSignal, DownloadManagerStatus},
download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, downloadable::Downloadable, util::{download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag}, progress_object::ProgressObject, queue::Queue},
downloadable::Downloadable,
progress_object::ProgressObject,
queue::Queue,
}; };
pub type DownloadAgent = Arc<Box<dyn Downloadable + Send + Sync>>; pub type DownloadAgent = Arc<Box<dyn Downloadable + Send + Sync>>;

View File

@ -2,11 +2,13 @@ use std::sync::Arc;
use tauri::AppHandle; use tauri::AppHandle;
use crate::{database::models::data::DownloadableMetadata, error::application_download_error::ApplicationDownloadError}; use crate::{
database::models::data::DownloadableMetadata,
error::application_download_error::ApplicationDownloadError,
};
use super::{ use super::{
download_manager::DownloadStatus, download_thread_control_flag::DownloadThreadControl, download_manager::DownloadStatus, util::{download_thread_control_flag::DownloadThreadControl, progress_object::ProgressObject},
progress_object::ProgressObject,
}; };
pub trait Downloadable: Send + Sync { pub trait Downloadable: Send + Sync {

View File

@ -1 +0,0 @@
use serde::{Deserialize, Serialize};

View File

@ -1,27 +0,0 @@
use std::{fmt::Display, io, sync::mpsc::SendError};
use serde_with::SerializeDisplay;
#[derive(SerializeDisplay)]
pub enum InternalError<T> {
IOError(io::Error),
SignalError(SendError<T>),
}
impl<T> Display for InternalError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InternalError::IOError(error) => write!(f, "{}", error),
InternalError::SignalError(send_error) => write!(f, "{}", send_error),
}
}
}
impl<T> From<SendError<T>> for InternalError<T> {
fn from(value: SendError<T>) -> Self {
InternalError::SignalError(value)
}
}
impl<T> From<io::Error> for InternalError<T> {
fn from(value: io::Error) -> Self {
InternalError::IOError(value)
}
}

View File

@ -1,10 +1,5 @@
pub mod commands; pub mod commands;
pub mod download_manager; pub mod download_manager;
pub mod download_manager_builder; pub mod download_manager_builder;
pub mod download_thread_control_flag;
pub mod downloadable; pub mod downloadable;
pub mod downloadable_metadata; pub mod util;
pub mod internal_error;
pub mod progress_object;
pub mod queue;
pub mod rolling_progress_updates;

View File

@ -0,0 +1,4 @@
pub mod progress_object;
pub mod queue;
pub mod rolling_progress_updates;
pub mod download_thread_control_flag;

View File

@ -10,8 +10,10 @@ use std::{
use atomic_instant_full::AtomicInstant; use atomic_instant_full::AtomicInstant;
use throttle_my_fn::throttle; use throttle_my_fn::throttle;
use crate::download_manager::download_manager::DownloadManagerSignal;
use super::{ use super::{
download_manager::DownloadManagerSignal, rolling_progress_updates::RollingProgressWindow, rolling_progress_updates::RollingProgressWindow,
}; };
#[derive(Clone)] #[derive(Clone)]

View File

@ -0,0 +1,27 @@
use std::{fmt::Display, io, sync::mpsc::SendError};
use serde_with::SerializeDisplay;
#[derive(SerializeDisplay)]
pub enum DownloadManagerError<T> {
IOError(io::Error),
SignalError(SendError<T>),
}
impl<T> Display for DownloadManagerError<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DownloadManagerError::IOError(error) => write!(f, "{}", error),
DownloadManagerError::SignalError(send_error) => write!(f, "{}", send_error),
}
}
}
impl<T> From<SendError<T>> for DownloadManagerError<T> {
fn from(value: SendError<T>) -> Self {
DownloadManagerError::SignalError(value)
}
}
impl<T> From<io::Error> for DownloadManagerError<T> {
fn from(value: io::Error) -> Self {
DownloadManagerError::IOError(value)
}
}

View File

@ -1,5 +1,6 @@
pub mod application_download_error; pub mod application_download_error;
pub mod drop_server_error; pub mod drop_server_error;
pub mod download_manager_error;
pub mod library_error; pub mod library_error;
pub mod process_error; pub mod process_error;
pub mod remote_access_error; pub mod remote_access_error;

View File

@ -1,5 +1,4 @@
use std::{ use std::{
any::{Any, TypeId},
error::Error, error::Error,
fmt::{Display, Formatter}, fmt::{Display, Formatter},
sync::Arc, sync::Arc,
@ -23,7 +22,6 @@ pub enum RemoteAccessError {
ManifestDownloadFailed(StatusCode, String), ManifestDownloadFailed(StatusCode, String),
OutOfSync, OutOfSync,
Cache(cacache::Error), Cache(cacache::Error),
Generic(String),
} }
impl Display for RemoteAccessError { impl Display for RemoteAccessError {
@ -59,7 +57,6 @@ impl Display for RemoteAccessError {
status, response status, response
), ),
RemoteAccessError::OutOfSync => write!(f, "server's and client's time are out of sync. Please ensure they are within at least 30 seconds of each other"), RemoteAccessError::OutOfSync => write!(f, "server's and client's time are out of sync. Please ensure they are within at least 30 seconds of each other"),
RemoteAccessError::Generic(message) => write!(f, "{}", message),
RemoteAccessError::Cache(error) => write!(f, "Cache Error: {}", error), RemoteAccessError::Cache(error) => write!(f, "Cache Error: {}", error),
} }
} }

View File

@ -11,7 +11,7 @@ pub struct Collection {
name: String, name: String,
is_default: bool, is_default: bool,
user_id: String, user_id: String,
entries: Vec<CollectionObject> entries: Vec<CollectionObject>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
@ -21,4 +21,3 @@ pub struct CollectionObject {
game_id: String, game_id: String,
game: Game, game: Game,
} }

View File

@ -2,7 +2,12 @@ use reqwest::blocking::Client;
use serde_json::json; use serde_json::json;
use url::Url; use url::Url;
use crate::{database::db::DatabaseImpls, error::remote_access_error::RemoteAccessError, remote::{auth::generate_authorization_header, requests::make_request}, DB}; use crate::{
database::db::DatabaseImpls,
error::remote_access_error::RemoteAccessError,
remote::{auth::generate_authorization_header, requests::make_request},
DB,
};
use super::collection::{Collection, Collections}; use super::collection::{Collection, Collections};
@ -20,9 +25,12 @@ pub fn fetch_collections() -> Result<Collections, RemoteAccessError> {
#[tauri::command] #[tauri::command]
pub fn fetch_collection(collection_id: String) -> Result<Collection, RemoteAccessError> { pub fn fetch_collection(collection_id: String) -> Result<Collection, RemoteAccessError> {
let client = Client::new(); let client = Client::new();
let response = make_request(&client, &["/api/v1/client/collection/", &collection_id], &[], |r| { let response = make_request(
r.header("Authorization", generate_authorization_header()) &client,
})? &["/api/v1/client/collection/", &collection_id],
&[],
|r| r.header("Authorization", generate_authorization_header()),
)?
.send()?; .send()?;
Ok(response.json()?) Ok(response.json()?)
@ -35,20 +43,26 @@ pub fn create_collection(name: String) -> Result<Collection, RemoteAccessError>
let base_url = Url::parse(&format!("{}api/v1/client/collection/", base_url))?; let base_url = Url::parse(&format!("{}api/v1/client/collection/", base_url))?;
let response = client let response = client
.post(base_url) .post(base_url)
.header("Authorization", generate_authorization_header()) .header("Authorization", generate_authorization_header())
.json(&json!({"name": name})) .json(&json!({"name": name}))
.send()?; .send()?;
Ok(response.json()?) Ok(response.json()?)
} }
#[tauri::command] #[tauri::command]
pub fn add_game_to_collection(collection_id: String, game_id: String) -> Result<(), RemoteAccessError> { pub fn add_game_to_collection(
collection_id: String,
game_id: String,
) -> Result<(), RemoteAccessError> {
let client = Client::new(); let client = Client::new();
let url = Url::parse(&format!("{}api/v1/client/collection/{}/entry/", DB.fetch_base_url(), collection_id))?; let url = Url::parse(&format!(
"{}api/v1/client/collection/{}/entry/",
DB.fetch_base_url(),
collection_id
))?;
client client
.post(url) .post(url)
@ -61,7 +75,11 @@ pub fn add_game_to_collection(collection_id: String, game_id: String) -> Result<
#[tauri::command] #[tauri::command]
pub fn delete_collection(collection_id: String) -> Result<bool, RemoteAccessError> { pub fn delete_collection(collection_id: String) -> Result<bool, RemoteAccessError> {
let client = Client::new(); let client = Client::new();
let base_url = Url::parse(&format!("{}api/v1/client/collection/{}", DB.fetch_base_url(), collection_id))?; let base_url = Url::parse(&format!(
"{}api/v1/client/collection/{}",
DB.fetch_base_url(),
collection_id
))?;
let response = client let response = client
.delete(base_url) .delete(base_url)
@ -71,9 +89,16 @@ pub fn delete_collection(collection_id: String) -> Result<bool, RemoteAccessErro
Ok(response.json()?) Ok(response.json()?)
} }
#[tauri::command] #[tauri::command]
pub fn delete_game_in_collection(collection_id: String, game_id: String) -> Result<(), RemoteAccessError> { pub fn delete_game_in_collection(
collection_id: String,
game_id: String,
) -> Result<(), RemoteAccessError> {
let client = Client::new(); let client = Client::new();
let base_url = Url::parse(&format!("{}api/v1/client/collection/{}/entry", DB.fetch_base_url(), collection_id))?; let base_url = Url::parse(&format!(
"{}api/v1/client/collection/{}/entry",
DB.fetch_base_url(),
collection_id
))?;
client client
.delete(base_url) .delete(base_url)
@ -82,4 +107,4 @@ pub fn delete_game_in_collection(collection_id: String, game_id: String) -> Resu
.send()?; .send()?;
Ok(()) Ok(())
} }

View File

@ -1,2 +1,2 @@
pub mod collection;
pub mod commands; pub mod commands;
pub mod collection;

View File

@ -1,6 +1,6 @@
use std::sync::Mutex; use std::sync::Mutex;
use tauri::{AppHandle, Manager}; use tauri::AppHandle;
use crate::{ use crate::{
database::models::data::GameVersion, database::models::data::GameVersion,

View File

@ -3,9 +3,7 @@ use std::sync::{Arc, Mutex};
use crate::{ use crate::{
download_manager::{ download_manager::{
download_manager::DownloadManagerSignal, downloadable::Downloadable, download_manager::DownloadManagerSignal, downloadable::Downloadable,
internal_error::InternalError, }, error::download_manager_error::DownloadManagerError, AppState
},
AppState,
}; };
use super::download_agent::GameDownloadAgent; use super::download_agent::GameDownloadAgent;
@ -16,7 +14,7 @@ pub fn download_game(
game_version: String, game_version: String,
install_dir: usize, install_dir: usize,
state: tauri::State<'_, Mutex<AppState>>, state: tauri::State<'_, Mutex<AppState>>,
) -> Result<(), InternalError<DownloadManagerSignal>> { ) -> Result<(), DownloadManagerError<DownloadManagerSignal>> {
let sender = state.lock().unwrap().download_manager.get_sender(); let sender = state.lock().unwrap().download_manager.get_sender();
let game_download_agent = Arc::new(Box::new(GameDownloadAgent::new( let game_download_agent = Arc::new(Box::new(GameDownloadAgent::new(
game_id, game_id,

View File

@ -1,12 +1,12 @@
use crate::auth::generate_authorization_header; use crate::auth::generate_authorization_header;
use crate::database::db::borrow_db_checked; use crate::database::db::borrow_db_checked;
use crate::database::models::data::{ApplicationTransientStatus, DownloadType, DownloadableMetadata, GameDownloadStatus}; use crate::database::models::data::{
use crate::download_manager::download_manager::{DownloadManagerSignal, DownloadStatus}; ApplicationTransientStatus, DownloadType, DownloadableMetadata, GameDownloadStatus,
use crate::download_manager::download_thread_control_flag::{
DownloadThreadControl, DownloadThreadControlFlag,
}; };
use crate::download_manager::download_manager::{DownloadManagerSignal, DownloadStatus};
use crate::download_manager::downloadable::Downloadable; use crate::download_manager::downloadable::Downloadable;
use crate::download_manager::progress_object::{ProgressHandle, ProgressObject}; use crate::download_manager::util::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
use crate::download_manager::util::progress_object::{ProgressHandle, ProgressObject};
use crate::error::application_download_error::ApplicationDownloadError; use crate::error::application_download_error::ApplicationDownloadError;
use crate::error::remote_access_error::RemoteAccessError; use crate::error::remote_access_error::RemoteAccessError;
use crate::games::downloads::manifest::{DropDownloadContext, DropManifest}; use crate::games::downloads::manifest::{DropDownloadContext, DropManifest};

View File

@ -1,7 +1,5 @@
use crate::download_manager::download_thread_control_flag::{ use crate::download_manager::util::download_thread_control_flag::{DownloadThreadControl, DownloadThreadControlFlag};
DownloadThreadControl, DownloadThreadControlFlag, use crate::download_manager::util::progress_object::ProgressHandle;
};
use crate::download_manager::progress_object::ProgressHandle;
use crate::error::application_download_error::ApplicationDownloadError; use crate::error::application_download_error::ApplicationDownloadError;
use crate::error::remote_access_error::RemoteAccessError; use crate::error::remote_access_error::RemoteAccessError;
use crate::games::downloads::manifest::DropDownloadContext; use crate::games::downloads::manifest::DropDownloadContext;

View File

@ -2,13 +2,15 @@ use std::fs::remove_dir_all;
use std::sync::Mutex; use std::sync::Mutex;
use std::thread::spawn; use std::thread::spawn;
use log::{debug, error, info, warn}; use log::{debug, error, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tauri::Emitter; use tauri::Emitter;
use tauri::{AppHandle, Manager}; use tauri::AppHandle;
use crate::database::db::{borrow_db_checked, borrow_db_mut_checked, save_db}; use crate::database::db::{borrow_db_checked, borrow_db_mut_checked, save_db};
use crate::database::models::data::{ApplicationTransientStatus, DownloadableMetadata, GameDownloadStatus, GameVersion}; use crate::database::models::data::{
ApplicationTransientStatus, DownloadableMetadata, GameDownloadStatus, GameVersion,
};
use crate::download_manager::download_manager::DownloadStatus; use crate::download_manager::download_manager::DownloadStatus;
use crate::error::library_error::LibraryError; use crate::error::library_error::LibraryError;
use crate::error::remote_access_error::RemoteAccessError; use crate::error::remote_access_error::RemoteAccessError;

View File

@ -1,5 +1,5 @@
pub mod collections;
pub mod commands; pub mod commands;
pub mod downloads; pub mod downloads;
pub mod library; pub mod library;
pub mod state; pub mod state;
pub mod collections;

View File

@ -1,4 +1,7 @@
use crate::database::{db::borrow_db_checked, models::data::{ApplicationTransientStatus, GameDownloadStatus}}; use crate::database::{
db::borrow_db_checked,
models::data::{ApplicationTransientStatus, GameDownloadStatus},
};
pub type GameStatusWithTransient = ( pub type GameStatusWithTransient = (
Option<GameDownloadStatus>, Option<GameDownloadStatus>,

View File

@ -1,18 +1,18 @@
mod database; mod database;
mod games; mod games;
mod autostart; mod client;
mod cleanup;
mod commands;
mod download_manager; mod download_manager;
mod error; mod error;
mod process; mod process;
mod remote; mod remote;
use crate::database::db::DatabaseImpls; use crate::database::db::DatabaseImpls;
use autostart::{get_autostart_enabled, toggle_autostart}; use client::{
use cleanup::{cleanup_and_exit, quit}; autostart::{get_autostart_enabled, sync_autostart_on_startup, toggle_autostart},
use commands::fetch_state; cleanup::{cleanup_and_exit, quit},
};
use client::commands::fetch_state;
use database::commands::{ use database::commands::{
add_download_dir, delete_download_dir, fetch_download_dir_stats, fetch_settings, add_download_dir, delete_download_dir, fetch_download_dir_stats, fetch_settings,
fetch_system_data, update_settings, fetch_system_data, update_settings,
@ -33,7 +33,6 @@ use games::commands::{
}; };
use games::downloads::commands::download_game; use games::downloads::commands::download_game;
use games::library::{update_game_configuration, Game}; use games::library::{update_game_configuration, Game};
use http::Response;
use log::{debug, info, warn, LevelFilter}; use log::{debug, info, warn, LevelFilter};
use log4rs::append::console::ConsoleAppender; use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender; use log4rs::append::file::FileAppender;
@ -48,9 +47,7 @@ use remote::commands::{
sign_out, use_remote, sign_out, use_remote,
}; };
use remote::fetch_object::{fetch_object, fetch_object_offline}; use remote::fetch_object::{fetch_object, fetch_object_offline};
use remote::requests::make_request;
use remote::server_proto::{handle_server_proto, handle_server_proto_offline}; use remote::server_proto::{handle_server_proto, handle_server_proto_offline};
use reqwest::blocking::Body;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::env; use std::env;
use std::path::Path; use std::path::Path;
@ -196,7 +193,7 @@ fn setup(handle: AppHandle) -> AppState<'static> {
debug!("finished setup!"); debug!("finished setup!");
// Sync autostart state // Sync autostart state
if let Err(e) = autostart::sync_autostart_on_startup(&handle) { if let Err(e) = sync_autostart_on_startup(&handle) {
warn!("failed to sync autostart state: {}", e); warn!("failed to sync autostart state: {}", e);
} }

View File

@ -1,13 +1 @@
// Since this code isn't being used, we can either:
// 1. Delete the entire file if compatibility features are not planned
// 2. Or add a TODO comment if planning to implement later
// Option 1: Delete the file
// Delete src-tauri/src/process/compat.rs
// Option 2: Add TODO comment
/*
TODO: Compatibility layer for running Windows games on Linux
This module is currently unused but reserved for future implementation
of Windows game compatibility features on Linux.
*/

View File

@ -1,3 +1,4 @@
pub mod commands; pub mod commands;
#[cfg(target_os = "linux")]
pub mod compat; pub mod compat;
pub mod process_manager; pub mod process_manager;

View File

@ -1,9 +1,9 @@
use std::{ use std::{
collections::HashMap, collections::HashMap,
fs::{File, OpenOptions}, fs::OpenOptions,
io::{self, Error}, io::{self},
path::{Path, PathBuf}, path::PathBuf,
process::{Child, Command, ExitStatus}, process::{Command, ExitStatus},
str::FromStr, str::FromStr,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
thread::spawn, thread::spawn,
@ -15,12 +15,14 @@ use log::{debug, info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use shared_child::SharedChild; use shared_child::SharedChild;
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
use umu_wrapper_lib::command_builder::UmuCommandBuilder;
use crate::{ use crate::{
database::{ database::{
db::{borrow_db_mut_checked, DATA_ROOT_DIR}, db::{borrow_db_mut_checked, DATA_ROOT_DIR},
models::data::{ApplicationTransientStatus, DownloadType, DownloadableMetadata, GameDownloadStatus, GameVersion}, models::data::{
ApplicationTransientStatus, DownloadType, DownloadableMetadata, GameDownloadStatus,
GameVersion,
},
}, },
error::process_error::ProcessError, error::process_error::ProcessError,
games::{library::push_game_update, state::GameStatusManager}, games::{library::push_game_update, state::GameStatusManager},
@ -46,7 +48,7 @@ impl ProcessManager<'_> {
current_platform: Platform::Windows, current_platform: Platform::Windows,
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
current_platform: Platform::macOS, current_platform: Platform::MacOs,
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
current_platform: Platform::Linux, current_platform: Platform::Linux,
@ -65,7 +67,7 @@ impl ProcessManager<'_> {
&NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static), &NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static),
), ),
( (
(Platform::macOS, Platform::macOS), (Platform::MacOs, Platform::MacOs),
&NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static), &NativeGameLauncher {} as &(dyn ProcessHandler + Sync + Send + 'static),
), ),
( (
@ -330,7 +332,7 @@ impl ProcessManager<'_> {
pub enum Platform { pub enum Platform {
Windows, Windows,
Linux, Linux,
macOS, MacOs,
} }
pub trait ProcessHandler: Send + 'static { pub trait ProcessHandler: Send + 'static {
@ -351,14 +353,14 @@ impl ProcessHandler for NativeGameLauncher {
_meta: &DownloadableMetadata, _meta: &DownloadableMetadata,
launch_command: String, launch_command: String,
args: Vec<String>, args: Vec<String>,
game_version: &GameVersion, _game_version: &GameVersion,
current_dir: &str, _current_dir: &str,
) -> String { ) -> String {
format!("\"{}\" {}", launch_command, args.join(" ")) format!("\"{}\" {}", launch_command, args.join(" "))
} }
} }
const UMU_LAUNCHER_EXECUTABLE: &str = "umu-run"; pub const UMU_LAUNCHER_EXECUTABLE: &str = "umu-run";
struct UMULauncher; struct UMULauncher;
impl ProcessHandler for UMULauncher { impl ProcessHandler for UMULauncher {
fn create_launch_process( fn create_launch_process(

View File

@ -1,21 +1,20 @@
use std::{collections::HashMap, env, sync::Mutex}; use std::{collections::HashMap, env};
use chrono::Utc; use chrono::Utc;
use droplet_rs::ssl::sign_nonce; use droplet_rs::ssl::sign_nonce;
use gethostname::gethostname; use gethostname::gethostname;
use log::{debug, error, warn}; use log::{debug, error, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use tauri::{AppHandle, Emitter};
use tauri::{AppHandle, Emitter, Manager};
use url::Url; use url::Url;
use crate::{ use crate::{
database::{ database::{
db::{borrow_db_checked, borrow_db_mut_checked, save_db, DatabaseImpls}, db::{borrow_db_checked, borrow_db_mut_checked, save_db},
models::data::DatabaseAuth, models::data::DatabaseAuth,
}, },
error::{drop_server_error::DropServerError, remote_access_error::RemoteAccessError}, error::{drop_server_error::DropServerError, remote_access_error::RemoteAccessError},
AppState, AppStatus, User, DB, AppStatus, User,
}; };
use super::{ use super::{

View File

@ -1,6 +1,7 @@
use std::sync::RwLockReadGuard; use crate::{
database::{db::borrow_db_checked, models::data::Database},
use crate::{database::{db::borrow_db_checked, models::data::Database}, error::remote_access_error::RemoteAccessError}; error::remote_access_error::RemoteAccessError,
};
use cacache::Integrity; use cacache::Integrity;
use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response}; use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};

View File

@ -6,11 +6,16 @@ use tauri::{AppHandle, Emitter, Manager};
use url::Url; use url::Url;
use crate::{ use crate::{
database::db::{borrow_db_checked, borrow_db_mut_checked, save_db}, error::remote_access_error::RemoteAccessError, remote::{auth::generate_authorization_header, requests::make_request}, AppState, AppStatus database::db::{borrow_db_checked, borrow_db_mut_checked, save_db},
error::remote_access_error::RemoteAccessError,
remote::{auth::generate_authorization_header, requests::make_request},
AppState, AppStatus,
}; };
use super::{ use super::{
auth::{auth_initiate_logic, recieve_handshake, setup}, cache::{cache_object, get_cached_object}, remote::use_remote_logic auth::{auth_initiate_logic, recieve_handshake, setup},
cache::{cache_object, get_cached_object},
remote::use_remote_logic,
}; };
#[tauri::command] #[tauri::command]
@ -36,24 +41,22 @@ pub fn gen_drop_url(path: String) -> Result<String, RemoteAccessError> {
#[tauri::command] #[tauri::command]
pub fn fetch_drop_object(path: String) -> Result<Vec<u8>, RemoteAccessError> { pub fn fetch_drop_object(path: String) -> Result<Vec<u8>, RemoteAccessError> {
let drop_url = gen_drop_url(path.clone()); let _drop_url = gen_drop_url(path.clone())?;
let req = make_request( let req = make_request(&Client::new(), &[&path], &[], |r| {
&Client::new(), r.header("Authorization", generate_authorization_header())
&[&path], })?
&[], .send();
|r| { r.header("Authorization", generate_authorization_header()) }
)?.send();
match req { match req {
Ok(data) => { Ok(data) => {
let data = data.bytes()?.to_vec(); let data = data.bytes()?.to_vec();
cache_object(&path, &data)?; cache_object(&path, &data)?;
Ok(data) Ok(data)
}, }
Err(e) => { Err(e) => {
debug!("{}", e); debug!("{}", e);
get_cached_object::<&str, Vec<u8>>(&path) get_cached_object::<&str, Vec<u8>>(&path)
}, }
} }
} }
#[tauri::command] #[tauri::command]

View File

@ -2,12 +2,13 @@ use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder};
use log::warn; use log::warn;
use tauri::UriSchemeResponder; use tauri::UriSchemeResponder;
use super::{auth::generate_authorization_header, cache::{cache_object, get_cached_object, ObjectCache}, requests::make_request}; use super::{
auth::generate_authorization_header,
cache::{cache_object, get_cached_object, ObjectCache},
requests::make_request,
};
pub fn fetch_object( pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeResponder) {
request: http::Request<Vec<u8>>,
responder: UriSchemeResponder,
) {
// Drop leading / // Drop leading /
let object_id = &request.uri().path()[1..]; let object_id = &request.uri().path()[1..];
@ -25,7 +26,7 @@ pub fn fetch_object(
Ok(data) => responder.respond(data.into()), Ok(data) => responder.respond(data.into()),
Err(e) => { Err(e) => {
warn!("{}", e) warn!("{}", e)
}, }
} }
return; return;
} }
@ -41,10 +42,7 @@ pub fn fetch_object(
responder.respond(resp); responder.respond(resp);
} }
pub fn fetch_object_offline( pub fn fetch_object_offline(request: http::Request<Vec<u8>>, responder: UriSchemeResponder) {
request: http::Request<Vec<u8>>,
responder: UriSchemeResponder,
) {
let object_id = &request.uri().path()[1..]; let object_id = &request.uri().path()[1..];
let data = get_cached_object::<&str, ObjectCache>(object_id); let data = get_cached_object::<&str, ObjectCache>(object_id);

View File

@ -5,4 +5,4 @@ pub mod commands;
pub mod fetch_object; pub mod fetch_object;
pub mod remote; pub mod remote;
pub mod requests; pub mod requests;
pub mod server_proto; pub mod server_proto;

View File

@ -1,10 +1,9 @@
use std::{path::PathBuf, str::FromStr}; use std::str::FromStr;
use http::{ use http::{
uri::{Authority, PathAndQuery}, uri::PathAndQuery,
Request, Response, StatusCode, Uri, Request, Response, StatusCode, Uri,
}; };
use log::info;
use reqwest::blocking::Client; use reqwest::blocking::Client;
use tauri::UriSchemeResponder; use tauri::UriSchemeResponder;

View File

@ -1,5 +1,4 @@
/* automatically generated by rust-bindgen 0.71.1 */ /* automatically generated by rust-bindgen 0.71.1 */
#[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)]
#[repr(C)] #[repr(C)]
pub struct __BindgenComplex<T> { pub struct __BindgenComplex<T> {