feat: torrential setup

This commit is contained in:
DecDuck
2025-12-03 11:54:20 +11:00
parent fe4f295fcd
commit 510013d4fa
8 changed files with 40 additions and 25 deletions
+1 -1
View File
@@ -57,7 +57,7 @@ impl Display for ApplicationDownloadError {
format_size(*required, BINARY),
format_size(*available, BINARY),
),
ApplicationDownloadError::Communication(error) => write!(f, "{error}"),
ApplicationDownloadError::Communication(error) => write!(f, "{error:?}"),
ApplicationDownloadError::Lock => write!(
f,
"failed to acquire lock. Something has gone very wrong internally. Please restart the application"
@@ -36,13 +36,13 @@ use crate::downloads::validate::validate_game_chunk;
use crate::library::{on_game_complete, push_game_update, set_partially_installed};
use crate::state::GameStatusManager;
use super::download_logic::download_game_bucket;
use super::download_logic::download_game_chunk;
use super::drop_data::DropData;
static RETRY_COUNT: usize = 3;
const TARGET_BUCKET_SIZE: usize = 63 * 1000 * 1000;
const MAX_FILES_PER_BUCKET: usize = (1024 / 4) - 1;
const MAX_FILES_PER_BUCKET: usize = 1; // (1024 / 4) - 1;
pub struct GameDownloadAgent {
pub id: String,
@@ -283,6 +283,7 @@ impl GameDownloadAgent {
for (index, length) in chunk.lengths.iter().enumerate() {
let drop = DownloadDrop {
filename: raw_path.to_string(),
id: chunk.ids[index].clone(),
start: file_running_offset,
length: *length,
checksum: chunk.checksums[index].clone(),
@@ -465,7 +466,7 @@ impl GameDownloadAgent {
// 3 attempts
for i in 0..RETRY_COUNT {
let loop_progress_handle = progress_handle.clone();
match download_game_bucket(
match download_game_chunk(
&bucket,
download_context,
&self.control_flag,
+22 -13
View File
@@ -3,7 +3,7 @@ use std::io::Read;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use std::sync::Arc;
use std::time::Instant;
use std::time::{Duration, Instant};
use std::{
fs::{File, OpenOptions},
io::{self, BufWriter, Seek, SeekFrom, Write},
@@ -105,7 +105,8 @@ impl<'a> DropDownloadPipeline<'a, Response, File> {
})
}
fn copy(&mut self) -> Result<bool, io::Error> {
fn copy(&mut self) -> Result<(bool, usize), io::Error> {
let mut total_copied = 0;
let mut copy_buffer = [0u8; MAX_PACKET_LENGTH];
for (index, drop) in self.drops.iter().enumerate() {
let destination = self
@@ -127,13 +128,14 @@ impl<'a> DropDownloadPipeline<'a, Response, File> {
})?;
remaining -= size;
last_bump += size;
// total_copied += size;
destination.write_all(&copy_buffer[0..size])?;
if last_bump > BUMP_SIZE {
last_bump -= BUMP_SIZE;
if self.control_flag.get() == DownloadThreadControlFlag::Stop {
return Ok(false);
return Ok((false, 0));
}
}
@@ -143,11 +145,11 @@ impl<'a> DropDownloadPipeline<'a, Response, File> {
}
if self.control_flag.get() == DownloadThreadControlFlag::Stop {
return Ok(false);
return Ok((false, 0));
}
}
Ok(true)
Ok((true, total_copied))
}
#[allow(dead_code)]
@@ -167,7 +169,7 @@ impl<'a> DropDownloadPipeline<'a, Response, File> {
}
}
pub fn download_game_bucket(
pub fn download_game_chunk(
bucket: &DownloadBucket,
ctx: &DownloadContext,
control_flag: &DownloadThreadControl,
@@ -183,14 +185,20 @@ pub fn download_game_bucket(
let header = generate_authorization_header();
let url = generate_url(&["/api/v2/client/chunk"], &[])
.map_err(ApplicationDownloadError::Communication)?;
if bucket.drops.len() > 1 {
panic!("lol");
}
let body = ChunkBody::create(ctx, &bucket.drops);
let drop = bucket.drops.first().unwrap();
let bits = ["/api/v1/depot/", &bucket.game_id, &bucket.version, &drop.id];
let url = generate_url(&bits, &[]).unwrap();
// let body = ChunkBody::create(ctx, &bucket.drops);
let response = DROP_CLIENT_SYNC
.post(url)
.json(&body)
.get(url)
//.json(&body)
.header("Authorization", header)
.send()
.map_err(|e| ApplicationDownloadError::Communication(e.into()))?;
@@ -210,7 +218,7 @@ pub fn download_game_bucket(
RemoteAccessError::UnparseableResponse(raw_res),
));
}
/*
let lengths = response
.headers()
.get("Content-Lengths")
@@ -255,6 +263,7 @@ pub fn download_game_bucket(
));
}
}
*/
let timestep = start.elapsed().as_millis();
@@ -264,7 +273,7 @@ pub fn download_game_bucket(
DropDownloadPipeline::new(response, bucket.drops.clone(), control_flag, progress)
.map_err(|e| ApplicationDownloadError::IoError(Arc::new(e)))?;
let completed = pipeline
let (completed, _) = pipeline
.copy()
.map_err(|e| ApplicationDownloadError::IoError(Arc::new(e)))?;
if !completed {
@@ -6,6 +6,7 @@ use std::path::PathBuf;
// Drops go in buckets
pub struct DownloadDrop {
pub index: usize,
pub id: String,
pub filename: String,
pub path: PathBuf,
pub start: usize,
+2 -1
View File
@@ -10,7 +10,7 @@ use download_manager::{
progress_object::ProgressHandle,
},
};
use log::debug;
use log::{debug, info};
use md5::Context;
use crate::downloads::manifest::DropValidateContext;
@@ -52,6 +52,7 @@ pub fn validate_game_chunk(
let res = hex::encode(hasher.finalize().0);
if res != ctx.checksum {
info!("{} doesn't match", ctx.path.display());
return Ok(false);
}
+2 -2
View File
@@ -9,7 +9,7 @@ use remote::{
utils::DROP_CLIENT_SYNC,
};
use serde::{Deserialize, Serialize};
use std::fs::remove_dir_all;
use std::fs::{exists, remove_dir_all};
use std::thread::spawn;
use tauri::AppHandle;
use utils::app_emit;
@@ -154,7 +154,7 @@ pub fn uninstall_game_logic(meta: DownloadableMetadata, app_handle: &AppHandle)
let app_handle = app_handle.clone();
spawn(move || {
if let Err(e) = remove_dir_all(install_dir) {
if exists(install_dir.clone()).unwrap_or(false) && let Err(e) = remove_dir_all(install_dir) {
error!("{e}");
} else {
let mut db_handle = borrow_db_mut_checked();
+6 -4
View File
@@ -1,4 +1,6 @@
use database::{DB, interface::DatabaseImpls};
use log::info;
use url::Url;
use crate::{
@@ -9,10 +11,10 @@ pub fn generate_url<T: AsRef<str>>(
path_components: &[T],
query: &[(T, T)],
) -> Result<Url, RemoteAccessError> {
let mut base_url = DB.fetch_base_url();
for endpoint in path_components {
base_url = base_url.join(endpoint.as_ref())?;
}
let components = path_components.iter().map(|v| v.as_ref()).map(|v| v.trim_matches('/')).collect::<Vec<&str>>();
let mut base_url = DB
.fetch_base_url()
.join(&components.join("/"))?;
{
let mut queries = base_url.query_pairs_mut();
for (param, val) in query {
+2 -1
View File
@@ -1,7 +1,7 @@
use std::{
fs::{self, File},
io::Read,
sync::LazyLock,
sync::LazyLock, time::Duration,
};
use database::db::DATA_ROOT_DIR;
@@ -91,6 +91,7 @@ pub fn get_client_sync() -> reqwest::blocking::Client {
}
client
.use_rustls_tls()
.connect_timeout(Duration::from_millis(1500))
.build()
.expect("Failed to build synchronous client")
}