mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2026-06-22 04:11:37 +10:00
Fix for redownload invalid chunks (#84)
* feat: Redownloading invalid chunks Signed-off-by: quexeky <git@quexeky.dev> * fix: clippy * fix: clippy x2 --------- Signed-off-by: quexeky <git@quexeky.dev> Co-authored-by: quexeky <git@quexeky.dev>
This commit is contained in:
+1
-1
Submodule drop-base updated: 26698e5b06...04125e89be
@@ -242,43 +242,47 @@ impl DownloadManagerBuilder {
|
|||||||
let app_handle = self.app_handle.clone();
|
let app_handle = self.app_handle.clone();
|
||||||
|
|
||||||
*download_thread_lock = Some(spawn(move || {
|
*download_thread_lock = Some(spawn(move || {
|
||||||
match download_agent.download(&app_handle) {
|
loop {
|
||||||
// Ok(true) is for completed and exited properly
|
let download_result = match download_agent.download(&app_handle) {
|
||||||
Ok(true) => {
|
// Ok(true) is for completed and exited properly
|
||||||
debug!("download {:?} has completed", download_agent.metadata());
|
Ok(v) => v,
|
||||||
match download_agent.validate() {
|
Err(e) => {
|
||||||
Ok(true) => {
|
error!("download {:?} has error {}", download_agent.metadata(), &e);
|
||||||
download_agent.on_complete(&app_handle);
|
download_agent.on_error(&app_handle, &e);
|
||||||
sender
|
sender.send(DownloadManagerSignal::Error(e)).unwrap();
|
||||||
.send(DownloadManagerSignal::Completed(download_agent.metadata()))
|
return;
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
Ok(false) => {
|
|
||||||
download_agent.on_incomplete(&app_handle);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
error!(
|
|
||||||
"download {:?} has validation error {}",
|
|
||||||
download_agent.metadata(),
|
|
||||||
&e
|
|
||||||
);
|
|
||||||
download_agent.on_error(&app_handle, &e);
|
|
||||||
sender.send(DownloadManagerSignal::Error(e)).unwrap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
// Ok(false) is for incomplete but exited properly
|
|
||||||
Ok(false) => {
|
// If the download gets cancel
|
||||||
debug!("Donwload agent finished incomplete");
|
if !download_result {
|
||||||
download_agent.on_incomplete(&app_handle);
|
download_agent.on_incomplete(&app_handle);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
error!("download {:?} has error {}", download_agent.metadata(), &e);
|
let validate_result = match download_agent.validate() {
|
||||||
download_agent.on_error(&app_handle, &e);
|
Ok(v) => v,
|
||||||
sender.send(DownloadManagerSignal::Error(e)).unwrap();
|
Err(e) => {
|
||||||
|
error!(
|
||||||
|
"download {:?} has validation error {}",
|
||||||
|
download_agent.metadata(),
|
||||||
|
&e
|
||||||
|
);
|
||||||
|
download_agent.on_error(&app_handle, &e);
|
||||||
|
sender.send(DownloadManagerSignal::Error(e)).unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if validate_result {
|
||||||
|
download_agent.on_complete(&app_handle);
|
||||||
|
sender
|
||||||
|
.send(DownloadManagerSignal::Completed(download_agent.metadata()))
|
||||||
|
.unwrap();
|
||||||
|
sender.send(DownloadManagerSignal::UpdateUIQueue).unwrap();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sender.send(DownloadManagerSignal::UpdateUIQueue).unwrap();
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.set_status(DownloadManagerStatus::Downloading);
|
self.set_status(DownloadManagerStatus::Downloading);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use serde_with::SerializeDisplay;
|
|||||||
|
|
||||||
#[derive(SerializeDisplay)]
|
#[derive(SerializeDisplay)]
|
||||||
pub enum ProcessError {
|
pub enum ProcessError {
|
||||||
SetupRequired,
|
|
||||||
NotInstalled,
|
NotInstalled,
|
||||||
AlreadyRunning,
|
AlreadyRunning,
|
||||||
NotDownloaded,
|
NotDownloaded,
|
||||||
@@ -19,7 +18,6 @@ pub enum ProcessError {
|
|||||||
impl Display for ProcessError {
|
impl Display for ProcessError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let s = match self {
|
let s = match self {
|
||||||
ProcessError::SetupRequired => "Game not set up",
|
|
||||||
ProcessError::NotInstalled => "Game not installed",
|
ProcessError::NotInstalled => "Game not installed",
|
||||||
ProcessError::AlreadyRunning => "Game already running",
|
ProcessError::AlreadyRunning => "Game already running",
|
||||||
ProcessError::NotDownloaded => "Game not downloaded",
|
ProcessError::NotDownloaded => "Game not downloaded",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::remote::requests::make_request;
|
|||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
use rayon::ThreadPoolBuilder;
|
use rayon::ThreadPoolBuilder;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{create_dir_all, OpenOptions};
|
use std::fs::{OpenOptions, create_dir_all};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -26,7 +26,7 @@ use std::time::Instant;
|
|||||||
use tauri::{AppHandle, Emitter};
|
use tauri::{AppHandle, Emitter};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use rustix::fs::{fallocate, FallocateFlags};
|
use rustix::fs::{FallocateFlags, fallocate};
|
||||||
|
|
||||||
use super::download_logic::download_game_chunk;
|
use super::download_logic::download_game_chunk;
|
||||||
use super::drop_data::DropData;
|
use super::drop_data::DropData;
|
||||||
@@ -187,10 +187,7 @@ impl GameDownloadAgent {
|
|||||||
self.generate_contexts()?;
|
self.generate_contexts()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.context_map
|
*self.context_map.lock().unwrap() = self.stored_manifest.get_contexts();
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.extend(self.stored_manifest.get_contexts());
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -423,6 +420,7 @@ impl Downloadable for GameDownloadAgent {
|
|||||||
app_handle,
|
app_handle,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
println!("Attempting to redownload");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_cancelled(&self, _app_handle: &tauri::AppHandle) {}
|
fn on_cancelled(&self, _app_handle: &tauri::AppHandle) {}
|
||||||
|
|||||||
@@ -27,8 +27,9 @@ pub struct DropWriter<W: Write> {
|
|||||||
}
|
}
|
||||||
impl DropWriter<File> {
|
impl DropWriter<File> {
|
||||||
fn new(path: PathBuf) -> Self {
|
fn new(path: PathBuf) -> Self {
|
||||||
|
let destination = OpenOptions::new().write(true).create(true).truncate(false).open(&path).unwrap();
|
||||||
Self {
|
Self {
|
||||||
destination: OpenOptions::new().write(true).open(path).unwrap(),
|
destination,
|
||||||
hasher: Context::new(),
|
hasher: Context::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
collections::HashMap, fs::File, io::{Read, Write}, path::PathBuf
|
||||||
io::{Read, Write},
|
|
||||||
path::PathBuf,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
@@ -12,7 +10,7 @@ pub type DropData = v1::DropData;
|
|||||||
static DROP_DATA_PATH: &str = ".dropdata";
|
static DROP_DATA_PATH: &str = ".dropdata";
|
||||||
|
|
||||||
pub mod v1 {
|
pub mod v1 {
|
||||||
use std::{path::PathBuf, sync::Mutex};
|
use std::{collections::HashMap, path::PathBuf, sync::Mutex};
|
||||||
|
|
||||||
use native_model::native_model;
|
use native_model::native_model;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -22,7 +20,7 @@ pub mod v1 {
|
|||||||
pub struct DropData {
|
pub struct DropData {
|
||||||
pub game_id: String,
|
pub game_id: String,
|
||||||
pub game_version: String,
|
pub game_version: String,
|
||||||
pub contexts: Mutex<Vec<(String, bool)>>,
|
pub contexts: Mutex<HashMap<String, bool>>,
|
||||||
pub base_path: PathBuf,
|
pub base_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ pub mod v1 {
|
|||||||
base_path,
|
base_path,
|
||||||
game_id,
|
game_id,
|
||||||
game_version,
|
game_version,
|
||||||
contexts: Mutex::new(Vec::new()),
|
contexts: Mutex::new(HashMap::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,20 +83,23 @@ impl DropData {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn set_contexts(&self, completed_contexts: &[(String, bool)]) {
|
pub fn set_contexts(&self, completed_contexts: &[(String, bool)]) {
|
||||||
*self.contexts.lock().unwrap() = completed_contexts.to_owned();
|
*self.contexts.lock().unwrap() = completed_contexts.iter().map(|s| (s.0.clone(), s.1)).collect();
|
||||||
|
}
|
||||||
|
pub fn set_context(&self, context: String, state: bool) {
|
||||||
|
self.contexts.lock().unwrap().entry(context).insert_entry(state);
|
||||||
}
|
}
|
||||||
pub fn get_completed_contexts(&self) -> Vec<String> {
|
pub fn get_completed_contexts(&self) -> Vec<String> {
|
||||||
self.contexts
|
self.contexts
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|x| if x.1 { Some(x.0.clone()) } else { None })
|
.filter_map(|x| if *x.1 { Some(x.0.clone()) } else { None })
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
pub fn get_contexts(&self) -> Vec<(String, bool)> {
|
pub fn get_contexts(&self) -> HashMap<String, bool> {
|
||||||
info!(
|
info!(
|
||||||
"Any contexts which are complete? {}",
|
"Any contexts which are complete? {}",
|
||||||
self.contexts.lock().unwrap().iter().any(|x| x.1)
|
self.contexts.lock().unwrap().iter().any(|x| *x.1)
|
||||||
);
|
);
|
||||||
self.contexts.lock().unwrap().clone()
|
self.contexts.lock().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{self, BufWriter, Read, Seek, SeekFrom, Write},
|
io::{self, BufWriter, Read, Seek, SeekFrom, Write},
|
||||||
sync::{mpsc::Sender, Arc},
|
sync::{Arc, mpsc::Sender},
|
||||||
};
|
};
|
||||||
|
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info};
|
||||||
@@ -73,6 +73,7 @@ pub fn game_validate_logic(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// If there are any contexts left which are false
|
// If there are any contexts left which are false
|
||||||
if !invalid_chunks.is_empty() {
|
if !invalid_chunks.is_empty() {
|
||||||
info!(
|
info!(
|
||||||
@@ -80,6 +81,13 @@ pub fn game_validate_logic(
|
|||||||
dropdata.game_id.clone(),
|
dropdata.game_id.clone(),
|
||||||
invalid_chunks
|
invalid_chunks
|
||||||
);
|
);
|
||||||
|
|
||||||
|
for context in invalid_chunks.iter() {
|
||||||
|
dropdata.set_context(context.1.clone(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropdata.write();
|
||||||
|
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +109,9 @@ pub fn validate_game_chunk(
|
|||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut source = File::open(&ctx.path).unwrap();
|
let Ok(mut source) = File::open(&ctx.path) else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
|
|
||||||
if ctx.offset != 0 {
|
if ctx.offset != 0 {
|
||||||
source
|
source
|
||||||
|
|||||||
Reference in New Issue
Block a user