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

View File

@ -168,7 +168,7 @@
</div>
<div class="ml-3">
<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.
</h3>
</div>

View File

@ -11,7 +11,7 @@ use rustbreak::{DeSerError, DeSerializer, PathDatabase};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use url::Url;
use crate::DB;
use crate::{process::process_manager::Platform, DB};
#[derive(serde::Serialize, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
@ -26,11 +26,21 @@ pub struct DatabaseAuth {
#[serde(tag = "type")]
pub enum DatabaseGameStatus {
Remote {},
Queued { version_name: String },
Downloading { version_name: String },
SetupRequired { version_name: String },
Installed { version_name: String },
Updating { version_name: String },
Queued {
version_name: String,
},
Downloading {
version_name: String,
},
SetupRequired {
version_name: String,
},
Installed {
version_name: String,
},
Updating {
version_name: String,
},
Uninstalling {},
}
@ -41,7 +51,7 @@ pub struct GameVersion {
pub version_name: String,
pub launch_command: String,
pub setup_command: String,
pub platform: String,
pub platform: Platform,
}
#[derive(Serialize, Clone, Deserialize)]
@ -111,7 +121,10 @@ impl DatabaseImpls for DatabaseInterface {
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)
.expect("Database could not be created")
}

View File

@ -37,6 +37,8 @@ pub enum DownloadManagerSignal {
Error(GameDownloadError),
/// Pushes UI update
Update,
/// Causes the Download Agent status to be synced to disk
Sync(usize),
}
pub enum DownloadManagerStatus {
Downloading,

View File

@ -141,6 +141,8 @@ impl DownloadManagerBuilder {
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> {
self.download_queue.pop_front();
let download_agent = self.download_agent_registry.remove(game_id).unwrap();
@ -195,6 +197,9 @@ impl DownloadManagerBuilder {
DownloadManagerSignal::Update => {
self.push_manager_update();
}
DownloadManagerSignal::Sync(index) => {
self.sync_download_agent();
}
};
}
}

View File

@ -2,7 +2,8 @@ mod auth;
mod db;
mod downloads;
mod library;
// mod p2p;
mod process;
mod remote;
mod settings;
#[cfg(test)]
@ -25,6 +26,7 @@ use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::Config;
use process::process_manager::ProcessManager;
use remote::{gen_drop_url, use_remote};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
@ -64,6 +66,8 @@ pub struct AppState {
#[serde(skip_serializing)]
download_manager: Arc<DownloadManager>,
#[serde(skip_serializing)]
process_manager: Arc<ProcessManager>,
}
#[tauri::command]
@ -81,7 +85,7 @@ fn setup(handle: AppHandle) -> AppState {
.unwrap();
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();
let config = Config::builder()
@ -100,6 +104,7 @@ fn setup(handle: AppHandle) -> AppState {
let games = HashMap::new();
let download_manager = Arc::new(DownloadManagerBuilder::build(handle));
let process_manager = Arc::new(ProcessManager::new());
debug!("Checking if database is set up");
let is_set_up = DB.database_is_set_up();
@ -109,6 +114,7 @@ fn setup(handle: AppHandle) -> AppState {
user: None,
games,
download_manager,
process_manager,
};
}
@ -120,6 +126,7 @@ fn setup(handle: AppHandle) -> AppState {
user,
games,
download_manager,
process_manager,
}
}
@ -234,4 +241,6 @@ pub fn run() {
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
info!("exiting drop application...");
}

View File

@ -9,6 +9,7 @@ use crate::db::DatabaseGameStatus;
use crate::db::DatabaseImpls;
use crate::db::GameVersion;
use crate::downloads::download_manager::GameDownloadStatus;
use crate::process::process_manager::Platform;
use crate::remote::RemoteAccessError;
use crate::{auth::generate_authorization_header, AppState, DB};
@ -56,7 +57,7 @@ pub struct QueueUpdateEvent {
pub struct GameVersionOption {
version_index: usize,
version_name: String,
platform: String,
platform: Platform,
setup_command: String,
launch_command: String,
delta: bool,
@ -199,8 +200,9 @@ pub fn fetch_game_status(id: String) -> Result<DatabaseGameStatus, String> {
Ok(status)
}
fn fetch_game_verion_options_logic(
fn fetch_game_verion_options_logic<'a>(
game_id: String,
state: tauri::State<'_, Mutex<AppState>>,
) -> Result<Vec<GameVersionOption>, RemoteAccessError> {
let base_url = DB.fetch_base_url();
@ -222,12 +224,27 @@ fn fetch_game_verion_options_logic(
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)
}
#[tauri::command]
pub fn fetch_game_verion_options(game_id: String) -> Result<Vec<GameVersionOption>, String> {
fetch_game_verion_options_logic(game_id).map_err(|e| e.to_string())
pub fn fetch_game_verion_options<'a>(
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(

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!()
}
}

View File

@ -1 +0,0 @@
pub mod discovery;

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())
}

View File

@ -0,0 +1 @@
pub mod process_manager;

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;
});