mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2026-06-22 04:11:37 +10:00
feat: torrential setup
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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(©_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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user