feat(download manager): only allow downloads for supported platforms

This commit is contained in:
DecDuck
2024-12-15 16:15:11 +11:00
parent 52436942eb
commit 269dcbb6f3
11 changed files with 107 additions and 59 deletions
+1 -1
View File
@@ -168,7 +168,7 @@
</div> </div>
<div class="ml-3"> <div class="ml-3">
<h3 class="text-sm font-medium text-red-600"> <h3 class="text-sm font-medium text-red-600">
There are no versions to install. Please contact your There are no supported versions to install. Please contact your
server admin or try again later. server admin or try again later.
</h3> </h3>
</div> </div>
+21 -8
View File
@@ -11,7 +11,7 @@ use rustbreak::{DeSerError, DeSerializer, PathDatabase};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url; use url::Url;
use crate::DB; use crate::{process::process_manager::Platform, DB};
#[derive(serde::Serialize, Clone, Deserialize)] #[derive(serde::Serialize, Clone, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@@ -26,11 +26,21 @@ pub struct DatabaseAuth {
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum DatabaseGameStatus { pub enum DatabaseGameStatus {
Remote {}, Remote {},
Queued { version_name: String }, Queued {
Downloading { version_name: String }, version_name: String,
SetupRequired { version_name: String }, },
Installed { version_name: String }, Downloading {
Updating { version_name: String }, version_name: String,
},
SetupRequired {
version_name: String,
},
Installed {
version_name: String,
},
Updating {
version_name: String,
},
Uninstalling {}, Uninstalling {},
} }
@@ -41,7 +51,7 @@ pub struct GameVersion {
pub version_name: String, pub version_name: String,
pub launch_command: String, pub launch_command: String,
pub setup_command: String, pub setup_command: String,
pub platform: String, pub platform: Platform,
} }
#[derive(Serialize, Clone, Deserialize)] #[derive(Serialize, Clone, Deserialize)]
@@ -111,7 +121,10 @@ impl DatabaseImpls for DatabaseInterface {
game_versions: HashMap::new(), game_versions: HashMap::new(),
}, },
}; };
debug!("Creating database at path {}", db_path.as_os_str().to_str().unwrap()); debug!(
"Creating database at path {}",
db_path.as_os_str().to_str().unwrap()
);
PathDatabase::create_at_path(db_path, default) PathDatabase::create_at_path(db_path, default)
.expect("Database could not be created") .expect("Database could not be created")
} }
@@ -37,6 +37,8 @@ pub enum DownloadManagerSignal {
Error(GameDownloadError), Error(GameDownloadError),
/// Pushes UI update /// Pushes UI update
Update, Update,
/// Causes the Download Agent status to be synced to disk
Sync(usize),
} }
pub enum DownloadManagerStatus { pub enum DownloadManagerStatus {
Downloading, Downloading,
@@ -141,6 +141,8 @@ impl DownloadManagerBuilder {
self.app_handle.emit("update_queue", event_data).unwrap(); self.app_handle.emit("update_queue", event_data).unwrap();
} }
fn sync_download_agent(&self) {}
fn remove_and_cleanup_game(&mut self, game_id: &String) -> Arc<GameDownloadAgent> { fn remove_and_cleanup_game(&mut self, game_id: &String) -> Arc<GameDownloadAgent> {
self.download_queue.pop_front(); self.download_queue.pop_front();
let download_agent = self.download_agent_registry.remove(game_id).unwrap(); let download_agent = self.download_agent_registry.remove(game_id).unwrap();
@@ -195,6 +197,9 @@ impl DownloadManagerBuilder {
DownloadManagerSignal::Update => { DownloadManagerSignal::Update => {
self.push_manager_update(); self.push_manager_update();
} }
DownloadManagerSignal::Sync(index) => {
self.sync_download_agent();
}
}; };
} }
} }
+11 -2
View File
@@ -2,7 +2,8 @@ mod auth;
mod db; mod db;
mod downloads; mod downloads;
mod library; mod library;
// mod p2p;
mod process;
mod remote; mod remote;
mod settings; mod settings;
#[cfg(test)] #[cfg(test)]
@@ -25,6 +26,7 @@ use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Root}; use log4rs::config::{Appender, Root};
use log4rs::encode::pattern::PatternEncoder; use log4rs::encode::pattern::PatternEncoder;
use log4rs::Config; use log4rs::Config;
use process::process_manager::ProcessManager;
use remote::{gen_drop_url, use_remote}; use remote::{gen_drop_url, use_remote};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
@@ -64,6 +66,8 @@ pub struct AppState {
#[serde(skip_serializing)] #[serde(skip_serializing)]
download_manager: Arc<DownloadManager>, download_manager: Arc<DownloadManager>,
#[serde(skip_serializing)]
process_manager: Arc<ProcessManager>,
} }
#[tauri::command] #[tauri::command]
@@ -81,7 +85,7 @@ fn setup(handle: AppHandle) -> AppState {
.unwrap(); .unwrap();
let console = ConsoleAppender::builder() let console = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new("{d} | {l} | {f} - {m}{n}\n"))) .encoder(Box::new(PatternEncoder::new("{t}|{l}|{f} - {m}{n}")))
.build(); .build();
let config = Config::builder() let config = Config::builder()
@@ -100,6 +104,7 @@ fn setup(handle: AppHandle) -> AppState {
let games = HashMap::new(); let games = HashMap::new();
let download_manager = Arc::new(DownloadManagerBuilder::build(handle)); let download_manager = Arc::new(DownloadManagerBuilder::build(handle));
let process_manager = Arc::new(ProcessManager::new());
debug!("Checking if database is set up"); debug!("Checking if database is set up");
let is_set_up = DB.database_is_set_up(); let is_set_up = DB.database_is_set_up();
@@ -109,6 +114,7 @@ fn setup(handle: AppHandle) -> AppState {
user: None, user: None,
games, games,
download_manager, download_manager,
process_manager,
}; };
} }
@@ -120,6 +126,7 @@ fn setup(handle: AppHandle) -> AppState {
user, user,
games, games,
download_manager, download_manager,
process_manager,
} }
} }
@@ -234,4 +241,6 @@ pub fn run() {
}) })
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
info!("exiting drop application...");
} }
+21 -4
View File
@@ -9,6 +9,7 @@ use crate::db::DatabaseGameStatus;
use crate::db::DatabaseImpls; use crate::db::DatabaseImpls;
use crate::db::GameVersion; use crate::db::GameVersion;
use crate::downloads::download_manager::GameDownloadStatus; use crate::downloads::download_manager::GameDownloadStatus;
use crate::process::process_manager::Platform;
use crate::remote::RemoteAccessError; use crate::remote::RemoteAccessError;
use crate::{auth::generate_authorization_header, AppState, DB}; use crate::{auth::generate_authorization_header, AppState, DB};
@@ -56,7 +57,7 @@ pub struct QueueUpdateEvent {
pub struct GameVersionOption { pub struct GameVersionOption {
version_index: usize, version_index: usize,
version_name: String, version_name: String,
platform: String, platform: Platform,
setup_command: String, setup_command: String,
launch_command: String, launch_command: String,
delta: bool, delta: bool,
@@ -199,8 +200,9 @@ pub fn fetch_game_status(id: String) -> Result<DatabaseGameStatus, String> {
Ok(status) Ok(status)
} }
fn fetch_game_verion_options_logic( fn fetch_game_verion_options_logic<'a>(
game_id: String, game_id: String,
state: tauri::State<'_, Mutex<AppState>>,
) -> Result<Vec<GameVersionOption>, RemoteAccessError> { ) -> Result<Vec<GameVersionOption>, RemoteAccessError> {
let base_url = DB.fetch_base_url(); let base_url = DB.fetch_base_url();
@@ -222,12 +224,27 @@ fn fetch_game_verion_options_logic(
let data = response.json::<Vec<GameVersionOption>>()?; let data = response.json::<Vec<GameVersionOption>>()?;
let state_lock = state.lock().unwrap();
let data = data
.into_iter()
.filter(|v| {
state_lock
.process_manager
.valid_platform(&v.platform)
.unwrap()
})
.collect::<Vec<GameVersionOption>>();
drop(state_lock);
Ok(data) Ok(data)
} }
#[tauri::command] #[tauri::command]
pub fn fetch_game_verion_options(game_id: String) -> Result<Vec<GameVersionOption>, String> { pub fn fetch_game_verion_options<'a>(
fetch_game_verion_options_logic(game_id).map_err(|e| e.to_string()) game_id: String,
state: tauri::State<'_, Mutex<AppState>>,
) -> Result<Vec<GameVersionOption>, String> {
fetch_game_verion_options_logic(game_id, state).map_err(|e| e.to_string())
} }
pub fn on_game_complete( pub fn on_game_complete(
-26
View File
@@ -1,26 +0,0 @@
use serde::{Deserialize, Serialize};
use url::Url;
#[derive(Serialize, Deserialize, Debug)]
pub struct P2PManager {
peers: Vec<Peer>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Peer {
endpoints: Vec<Url>,
current_endpoint: usize,
// TODO: Implement Wireguard tunnels
}
impl Peer {
pub fn get_current_endpoint(&self) -> Url {
self.endpoints[self.current_endpoint].clone()
}
pub fn connect(&mut self) {
todo!()
}
pub fn disconnect(&mut self) {
todo!()
}
}
-1
View File
@@ -1 +0,0 @@
pub mod discovery;
-17
View File
@@ -1,17 +0,0 @@
use crate::{auth::generate_authorization_header, db::DatabaseImpls, remote::RemoteAccessError, DB};
pub async fn register() -> Result<String, RemoteAccessError> {
let base_url = DB.fetch_base_url();
let registration_url = base_url.join("/api/v1/client/capability").unwrap();
let header = generate_authorization_header();
let client = reqwest::blocking::Client::new();
client
.post(registration_url)
.header("Authorization", header)
.send()?;
return Ok(String::new())
}
+1
View File
@@ -0,0 +1 @@
pub mod process_manager;
+45
View File
@@ -0,0 +1,45 @@
use std::{collections::HashMap, sync::LazyLock};
use serde::{Deserialize, Serialize};
pub struct ProcessManager {
current_platform: Platform,
}
impl ProcessManager {
pub fn new() -> Self {
ProcessManager {
current_platform: if cfg!(windows) {
Platform::Windows
} else {
Platform::Linux
},
}
}
pub fn valid_platform(&self, platform: &Platform) -> Result<bool, String> {
let current = &self.current_platform;
let valid_platforms = PROCESS_COMPATABILITY_MATRIX
.get(current)
.ok_or("Incomplete platform compatability matrix.")?;
Ok(valid_platforms.contains(platform))
}
}
#[derive(Eq, Hash, PartialEq, Serialize, Deserialize, Clone)]
pub enum Platform {
Windows,
Linux,
}
pub type ProcessCompatabilityMatrix = HashMap<Platform, Vec<Platform>>;
pub static PROCESS_COMPATABILITY_MATRIX: LazyLock<ProcessCompatabilityMatrix> =
LazyLock::new(|| {
let mut matrix: ProcessCompatabilityMatrix = HashMap::new();
matrix.insert(Platform::Windows, vec![Platform::Windows]);
matrix.insert(Platform::Linux, vec![Platform::Linux]); // TODO: add Proton support
return matrix;
});