diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8e498ad..0a81563 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1021,6 +1021,7 @@ dependencies = [ "ciborium", "directories", "env_logger", + "gxhash", "hex", "http", "log", @@ -1696,6 +1697,15 @@ dependencies = [ "syn 2.0.79", ] +[[package]] +name = "gxhash" +version = "3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a197c9b654827513cf53842c5c6d3da2b4b35a785f8e0eff78bdf8e445aba1bb" +dependencies = [ + "rustversion", +] + [[package]] name = "h2" version = "0.4.6" @@ -3410,6 +3420,12 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustversion" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + [[package]] name = "ryu" version = "1.0.18" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 21ada3f..915e854 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -41,6 +41,7 @@ tokio = { version = "1.40.0", features = ["rt", "tokio-macros"] } versions = { version = "6.3.2", features = ["serde"] } urlencoding = "2.1.3" rustix = "0.38.37" +gxhash = "3.4.1" [dependencies.uuid] version = "1.10.0" diff --git a/src-tauri/src/downloads/download_agent.rs b/src-tauri/src/downloads/download_agent.rs index 43bf9da..487f388 100644 --- a/src-tauri/src/downloads/download_agent.rs +++ b/src-tauri/src/downloads/download_agent.rs @@ -44,11 +44,7 @@ pub enum GameDownloadError { pub enum SystemError { MutexLockFailed, } -#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd)] -#[serde(rename_all = "camelCase")] -pub struct GameChunkCtx { - chunk_id: usize, -} + impl GameDownloadAgent { pub fn new(id: String, version: String) -> Self { Self { @@ -94,7 +90,7 @@ impl GameDownloadAgent { .join( format!( "/api/v1/client/metadata/manifest?id={}&version={}", - encode(&self.id), encode(&self.version) + self.id, encode(&self.version) ) .as_str(), ) @@ -158,6 +154,7 @@ impl GameDownloadAgent { index: i, game_id: game_id.to_string(), path: path.clone(), + checksum: chunk.checksums[i].clone() }); running_offset += *length as u64; } diff --git a/src-tauri/src/downloads/download_logic.rs b/src-tauri/src/downloads/download_logic.rs index d8e2ddb..06b7641 100644 --- a/src-tauri/src/downloads/download_logic.rs +++ b/src-tauri/src/downloads/download_logic.rs @@ -2,10 +2,42 @@ use crate::auth::generate_authorization_header; use crate::db::DatabaseImpls; use crate::downloads::manifest::DropDownloadContext; use crate::DB; +use gxhash::GxHasher; use log::info; -use std::{fs::OpenOptions, io::{BufWriter, Seek, SeekFrom, Write}}; +use std::{fs::{File, OpenOptions}, hash::Hasher, io::{BufWriter, Seek, SeekFrom, Write}, path::PathBuf}; use urlencoding::encode; +pub struct FileWriter { + file: File, + hasher: GxHasher +} +impl FileWriter { + fn new(path: PathBuf) -> Self { + Self { + file: OpenOptions::new().write(true).open(path).unwrap(), + hasher: GxHasher::with_seed(0) + } + } + fn finish(mut self) -> u128 { + self.flush(); + self.hasher.finish_u128() + } +} +impl Write for FileWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.hasher.write(buf); + self.file.write(buf) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.file.flush() + } +} +impl Seek for FileWriter { + fn seek(&mut self, pos: SeekFrom) -> std::io::Result { + self.file.seek(pos) + } +} pub fn download_game_chunk(ctx: DropDownloadContext) { let base_url = DB.fetch_base_url(); @@ -29,7 +61,7 @@ pub fn download_game_chunk(ctx: DropDownloadContext) { .send() .unwrap(); - let mut file = OpenOptions::new().write(true).open(ctx.path).unwrap(); + let mut file = FileWriter::new(ctx.path); if ctx.offset != 0 { file @@ -39,7 +71,16 @@ pub fn download_game_chunk(ctx: DropDownloadContext) { // let mut stream = BufWriter::with_capacity(1024, file); + // Writing directly to disk to avoid write spikes that delay everything + response.copy_to(&mut file).unwrap(); + let res = hex::encode(file.finish().to_le_bytes()); + if res == ctx.checksum { + info!("Matched Checksum {}", res); + } + else { + info!("Checksum failed {}", res); + } // stream.flush().unwrap(); } diff --git a/src-tauri/src/downloads/manifest.rs b/src-tauri/src/downloads/manifest.rs index 88f365e..895d3ab 100644 --- a/src-tauri/src/downloads/manifest.rs +++ b/src-tauri/src/downloads/manifest.rs @@ -21,4 +21,5 @@ pub struct DropDownloadContext { pub offset: u64, pub game_id: String, pub path: PathBuf, + pub checksum: String }