mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-14 16:51:18 +10:00
fix: assorted fixes
This commit is contained in:
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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))]
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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),
|
||||
));
|
||||
|
||||
@ -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()?;
|
||||
|
||||
|
||||
@ -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: {}",
|
||||
|
||||
@ -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" {
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user