fix: assorted fixes

This commit is contained in:
DecDuck
2025-01-20 11:42:09 +11:00
parent 92729701c3
commit 89ea34c94e
16 changed files with 166 additions and 109 deletions

View File

@ -1,7 +1,8 @@
use std::{
collections::HashMap,
fs::{self, create_dir_all},
path::PathBuf,
hash::Hash,
path::{Path, PathBuf},
sync::{LazyLock, Mutex, RwLockReadGuard, RwLockWriteGuard},
};
@ -91,10 +92,18 @@ impl Database {
Self {
applications: DatabaseApplications {
install_dirs: vec![games_base_dir.into()],
..Default::default()
game_statuses: HashMap::new(),
game_versions: HashMap::new(),
installed_game_version: HashMap::new(),
transient_statuses: HashMap::new(),
},
prev_database,
..Default::default()
base_url: "".to_owned(),
auth: None,
settings: Settings {
autostart: false,
max_download_threads: 4,
},
}
}
}

View File

@ -350,6 +350,8 @@ impl DownloadManagerBuilder {
meta: DownloadableMetadata::clone(key),
status: val.status(),
progress: val.progress().get_progress(),
current: val.progress().sum(),
max: val.progress().get_max(),
}
})
.collect();

View File

@ -23,7 +23,7 @@ pub struct ProgressObject {
//last_update: Arc<RwLock<Instant>>,
last_update_time: Arc<AtomicInstant>,
bytes_last_update: Arc<AtomicUsize>,
rolling: RollingProgressWindow<256>,
rolling: RollingProgressWindow<250>,
}
pub struct ProgressHandle {
@ -46,6 +46,15 @@ impl ProgressHandle {
.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
calculate_update(&self.progress_object);
}
pub fn skip(&self, amount: usize) {
self.progress
.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
// Offset the bytes at last offset by this amount
self.progress_object
.bytes_last_update
.fetch_add(amount, Ordering::Relaxed);
// Dont' fire update
}
}
impl ProgressObject {
@ -97,15 +106,15 @@ impl ProgressObject {
}
#[throttle(1, Duration::from_millis(20))]
pub fn calculate_update(progress_object: &ProgressObject) {
let last_update_time = progress_object
pub fn calculate_update(progress: &ProgressObject) {
let last_update_time = progress
.last_update_time
.swap(Instant::now(), Ordering::SeqCst);
let time_since_last_update = Instant::now().duration_since(last_update_time).as_millis();
let current_bytes_downloaded = progress_object.sum();
let max = progress_object.get_max();
let bytes_at_last_update = progress_object
let current_bytes_downloaded = progress.sum();
let max = progress.get_max();
let bytes_at_last_update = progress
.bytes_last_update
.swap(current_bytes_downloaded, Ordering::Relaxed);
@ -115,8 +124,8 @@ pub fn calculate_update(progress_object: &ProgressObject) {
let bytes_remaining = max - current_bytes_downloaded; // bytes
progress_object.update_window(kilobytes_per_second);
push_update(progress_object, bytes_remaining);
progress.update_window(kilobytes_per_second);
push_update(progress, bytes_remaining);
}
#[throttle(1, Duration::from_millis(500))]

View File

@ -127,25 +127,17 @@ impl GameDownloadAgent {
}
fn download_manifest(&self) -> Result<(), ApplicationDownloadError> {
let base_url = DB.fetch_base_url();
let manifest_url = base_url
.join(
format!(
"/api/v1/client/game/manifest?id={}&version={}",
self.id,
encode(&self.version)
)
.as_str(),
)
.unwrap();
let header = generate_authorization_header();
let client = reqwest::blocking::Client::new();
let response = client
.get(manifest_url.to_string())
.header("Authorization", header)
.send()
.unwrap();
let response = make_request(
&client,
&["/api/v1/client/game/manifest"],
&[("id", &self.id), ("version", &self.version)],
|f| f.header("Authorization", header),
)
.map_err(|e| ApplicationDownloadError::Communication(e))?
.send()
.map_err(|e| ApplicationDownloadError::Communication(e.into()))?;
if response.status() != 200 {
return Err(ApplicationDownloadError::Communication(
@ -266,9 +258,10 @@ impl GameDownloadAgent {
let progress = self.progress.get(index);
let progress_handle = ProgressHandle::new(progress, self.progress.clone());
// If we've done this one already, skip it
if self.completed_contexts.lock().unwrap().contains(&index) {
progress_handle.add(context.length);
progress_handle.skip(context.length);
continue;
}
@ -319,8 +312,10 @@ impl GameDownloadAgent {
// If we're not out of contexts, we're not done, so we don't fire completed
if completed_lock_len != contexts.len() {
info!(
"download agent for {} exited without completing",
self.id.clone()
"download agent for {} exited without completing ({}/{})",
self.id.clone(),
completed_lock_len,
contexts.len(),
);
self.stored_manifest
.set_completed_contexts(self.completed_contexts.lock().unwrap().as_slice());
@ -385,6 +380,7 @@ impl Downloadable for GameDownloadAgent {
.unwrap();
}
// TODO: fix this function. It doesn't restart the download properly, nor does it reset the state properly
fn on_incomplete(&self, app_handle: &tauri::AppHandle) {
let meta = self.metadata();
*self.status.lock().unwrap() = DownloadStatus::Queued;

View File

@ -133,7 +133,6 @@ pub fn download_game_chunk(
if response.status() != 200 {
let err = response.json().unwrap();
warn!("{:?}", err);
return Err(ApplicationDownloadError::Communication(
RemoteAccessError::InvalidResponse(err),
));

View File

@ -53,6 +53,8 @@ pub struct QueueUpdateEventQueueData {
pub meta: DownloadableMetadata,
pub status: DownloadStatus,
pub progress: f64,
pub current: usize,
pub max: usize,
}
#[derive(serde::Serialize, Clone)]
@ -81,16 +83,13 @@ pub struct GameVersionOption {
}
pub fn fetch_library_logic(app: AppHandle) -> Result<Vec<Game>, RemoteAccessError> {
let base_url = DB.fetch_base_url();
let library_url = base_url.join("/api/v1/client/user/library")?;
let header = generate_authorization_header();
let client = reqwest::blocking::Client::new();
let response = client
.get(library_url.to_string())
.header("Authorization", header)
.send()?;
let response = make_request(&client, &["/api/v1/client/user/library"], &[], |f| {
f.header("Authorization", header)
})?
.send()?;
if response.status() != 200 {
let err = response.json().unwrap();
@ -290,26 +289,23 @@ pub fn on_game_complete(
app_handle: &AppHandle,
) -> Result<(), RemoteAccessError> {
// Fetch game version information from remote
let base_url = DB.fetch_base_url();
if meta.version.is_none() {
return Err(RemoteAccessError::GameNotFound);
}
let endpoint = base_url.join(
format!(
"/api/v1/client/metadata/version?id={}&version={}",
meta.id,
encode(meta.version.as_ref().unwrap())
)
.as_str(),
)?;
let header = generate_authorization_header();
let client = reqwest::blocking::Client::new();
let response = client
.get(endpoint.to_string())
.header("Authorization", header)
.send()?;
let response = make_request(
&client,
&["/api/v1/client/metadata/version"],
&[
("id", &meta.id),
("version", meta.version.as_ref().unwrap()),
],
|f| f.header("Authorization", header),
)?
.send()?;
let data: GameVersion = response.json()?;

View File

@ -46,6 +46,7 @@ use remote::auth::{self, generate_authorization_header, recieve_handshake};
use remote::commands::{
auth_initiate, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote,
};
use remote::requests::make_request;
use serde::{Deserialize, Serialize};
use std::path::Path;
use std::sync::Arc;
@ -355,23 +356,16 @@ pub fn run() {
Ok(())
})
.register_asynchronous_uri_scheme_protocol("object", move |_ctx, request, responder| {
let base_url = DB.fetch_base_url();
// Drop leading /
let object_id = &request.uri().path()[1..];
let object_url = base_url
.join("/api/v1/client/object/")
.unwrap()
.join(object_id)
.unwrap();
let header = generate_authorization_header();
let client: reqwest::blocking::Client = reqwest::blocking::Client::new();
let response = client
.get(object_url.to_string())
.header("Authorization", header)
.send();
let response = make_request(&client, &["/api/v1/client/object/", object_id], &[], |f| {
f.header("Authorization", header)
})
.unwrap()
.send();
if response.is_err() {
warn!(
"failed to fetch object with error: {}",

View File

@ -15,6 +15,8 @@ use crate::{
AppState, AppStatus, User, DB,
};
use super::requests::make_request;
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
struct InitiateRequestBody {
@ -67,16 +69,15 @@ pub fn generate_authorization_header() -> String {
pub fn fetch_user() -> Result<User, RemoteAccessError> {
let base_url = DB.fetch_base_url();
let endpoint = base_url.join("/api/v1/client/user")?;
let header = generate_authorization_header();
let client = reqwest::blocking::Client::new();
let response = client
.get(endpoint.to_string())
.header("Authorization", header)
.send()?;
let response = make_request(&client, &["/api/v1/client/user"], &[], |f| {
f.header("Authorization", header)
})?
.send()?;
if response.status() != 200 {
let err: DropServerError = response.json().unwrap();
let err: DropServerError = response.json()?;
warn!("{:?}", err);
if err.status_message == "Nonce expired" {

View File

@ -4,17 +4,17 @@ use crate::{database::db::DatabaseImpls, error::remote_access_error::RemoteAcces
pub fn make_request<T: AsRef<str>, F: FnOnce(RequestBuilder) -> RequestBuilder>(
client: &Client,
endpoints: &[T],
params: &[(T, T)],
path_components: &[T],
query: &[(T, T)],
f: F,
) -> Result<RequestBuilder, RemoteAccessError> {
let mut base_url = DB.fetch_base_url();
for endpoint in endpoints {
for endpoint in path_components {
base_url = base_url.join(endpoint.as_ref())?;
}
{
let mut queries = base_url.query_pairs_mut();
for (param, val) in params {
for (param, val) in query {
queries.append_pair(param.as_ref(), val.as_ref());
}
}