Claude: An other extractor that doesn'T quite work

This commit is contained in:
Fiery Imp 2025-04-24 18:55:15 -04:00
parent 3d24ac8b57
commit da3ad2e7b7
4 changed files with 266 additions and 1 deletions

View File

@ -3,6 +3,7 @@ use std::path::PathBuf;
use std::sync::Arc;
use crate::installer::validator::*;
use crate::installer::downloader::DownloadManager;
use crate::installer::SevenZDearchiver;
use crate::ui::download_progress::download_progress;
use crate::ui::game_selection::game_selection;
use crate::ui::installation_progress::installation_progress;
@ -182,6 +183,7 @@ impl<> eframe::App for SinfarInstallerApp<> {
if self.state == InstallerState::Download {
self.start_download();
} else if self.state == InstallerState::Installing {
//self.start_extract();
self.start_installation();
}
}
@ -335,4 +337,40 @@ impl SinfarInstallerApp<> {
});
}
}
pub fn start_extract(&mut self) {
let dearchiver = crate::installer::SevenZDearchiver::new();
let download_state = self.download_state.clone();
let error_state = download_state.clone();
let eframe_ctx = self.eframe_ctx.clone().expect("eframe context should be set");
// Placeholder paths for testing
let archive_path = std::path::PathBuf::from("C:/Users/Samuel/AppData/Local/Temp/sinfar_installer/sinfar_all_files_v30.7z");
let output_dir = std::path::PathBuf::from("C:/Users/Samuel/AppData/Local/Temp/sinfar_installer/test");
self.runtime.spawn(async move {
if let Err(e) = dearchiver.extract(
&archive_path,
&output_dir,
move |progress, eta| {
if let Ok(mut state) = download_state.lock() {
state.progress = progress;
state.estimated_remaining = eta;
if state.progress == 1.0 {
state.completed = true;
}
else {
state.completed = false;
}
eframe_ctx.request_repaint();
}
}
).await {
if let Ok(mut state) = error_state.lock() {
state.error = Some(format!("Extraction failed: {}", e));
}
}
});
}
}

View File

@ -0,0 +1,112 @@
use anyhow::Result;
use std::path::Path;
use std::sync::Arc;
use tokio::sync::{Mutex, watch};
use std::io::{Read, Seek};
use std::fs;
use std::time::{Duration, Instant};
pub struct SevenZDearchiver {
cancel_tx: watch::Sender<bool>,
cancel_rx: watch::Receiver<bool>,
}
impl SevenZDearchiver {
pub fn new() -> Self {
let (cancel_tx, cancel_rx) = watch::channel(false);
Self {
cancel_tx,
cancel_rx,
}
}
pub fn cancel(&self) {
let _ = self.cancel_tx.send(true);
}
pub async fn extract<F>(&self, archive_path: &Path, output_dir: &Path, progress_callback: F) -> Result<()>
where
F: Fn(f32, Duration) + Send + Sync + 'static
{
// Create wrapper for progress tracking
struct ProgressReader<R: Read + Seek> {
inner: R,
bytes_read: u64,
total_size: u64,
last_update: Instant,
cancel_signal: watch::Receiver<bool>,
progress_callback: Arc<Box<dyn Fn(f32, Duration) + Send + Sync>>,
}
impl<R: Read + Seek> Read for ProgressReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
// Check cancellation
if *self.cancel_signal.borrow() {
return Ok(0); // Return 0 to indicate EOF and stop extraction
}
let bytes = self.inner.read(buf)?;
self.bytes_read += bytes as u64;
let now = Instant::now();
let elapsed = now.duration_since(self.last_update);
// Update progress every 100ms
if elapsed.as_millis() > 100 {
let progress = self.bytes_read as f32 / self.total_size as f32;
// Calculate estimated time remaining
let speed = self.bytes_read as f64 / elapsed.as_secs_f64();
let remaining_bytes = self.total_size - self.bytes_read;
let eta = if speed > 0.0 {
Duration::from_secs_f64(remaining_bytes as f64 / speed)
} else {
Duration::from_secs(0)
};
(self.progress_callback)(progress, eta);
self.last_update = now;
}
Ok(bytes)
}
}
impl<R: Read + Seek> Seek for ProgressReader<R> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.inner.seek(pos)
}
}
// Start extraction in blocking task
let cancel_rx = self.cancel_rx.clone();
let progress_cb = Arc::new(Box::new(progress_callback) as Box<dyn Fn(f32, Duration) + Send + Sync>);
let archive_path = archive_path.to_owned();
let output_dir = output_dir.to_owned();
tokio::task::spawn_blocking(move || -> Result<()> {
let file = fs::File::open(&archive_path)?;
let file_size = file.metadata()?.len();
let progress_reader = ProgressReader {
inner: file,
bytes_read: 0,
total_size: file_size,
last_update: Instant::now(),
cancel_signal: cancel_rx,
progress_callback: progress_cb,
};
sevenz_rust::decompress(progress_reader, &output_dir)?;
Ok(())
}).await??;
Ok(())
}
}
impl Default for SevenZDearchiver {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,4 +1,7 @@
pub mod downloader;
pub mod extractor;
pub mod validator;
pub mod shortcut;
pub mod shortcut;
pub mod seven_z_dearchiver;
pub use seven_z_dearchiver::SevenZDearchiver;

View File

@ -0,0 +1,112 @@
use anyhow::Result;
use std::path::Path;
use std::sync::Arc;
use tokio::sync::{Mutex, watch};
use std::io::{Read, Seek};
use std::fs;
use std::time::{Duration, Instant};
pub struct SevenZDearchiver {
cancel_tx: watch::Sender<bool>,
cancel_rx: watch::Receiver<bool>,
}
impl SevenZDearchiver {
pub fn new() -> Self {
let (cancel_tx, cancel_rx) = watch::channel(false);
Self {
cancel_tx,
cancel_rx,
}
}
pub fn cancel(&self) {
let _ = self.cancel_tx.send(true);
}
pub async fn extract<F>(&self, archive_path: &Path, output_dir: &Path, progress_callback: F) -> Result<()>
where
F: Fn(f32, Duration) + Send + Sync + 'static
{
// Create wrapper for progress tracking
struct ProgressReader<R: Read + Seek> {
inner: R,
bytes_read: u64,
total_size: u64,
last_update: Instant,
cancel_signal: watch::Receiver<bool>,
progress_callback: Arc<Box<dyn Fn(f32, Duration) + Send + Sync>>,
}
impl<R: Read + Seek> Read for ProgressReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
// Check cancellation
if *self.cancel_signal.borrow() {
return Ok(0); // Return 0 to indicate EOF and stop extraction
}
let bytes = self.inner.read(buf)?;
self.bytes_read += bytes as u64;
let now = Instant::now();
let elapsed = now.duration_since(self.last_update);
// Update progress every 100ms
if elapsed.as_millis() > 100 {
let progress = self.bytes_read as f32 / self.total_size as f32;
// Calculate estimated time remaining
let speed = self.bytes_read as f64 / elapsed.as_secs_f64();
let remaining_bytes = self.total_size - self.bytes_read;
let eta = if speed > 0.0 {
Duration::from_secs_f64(remaining_bytes as f64 / speed)
} else {
Duration::from_secs(0)
};
(self.progress_callback)(progress, eta);
self.last_update = now;
}
Ok(bytes)
}
}
impl<R: Read + Seek> Seek for ProgressReader<R> {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.inner.seek(pos)
}
}
// Start extraction in blocking task
let cancel_rx = self.cancel_rx.clone();
let progress_cb = Arc::new(Box::new(progress_callback) as Box<dyn Fn(f32, Duration) + Send + Sync>);
let archive_path = archive_path.to_owned();
let output_dir = output_dir.to_owned();
tokio::task::spawn_blocking(move || -> Result<()> {
let file = fs::File::open(&archive_path)?;
let file_size = file.metadata()?.len();
let progress_reader = ProgressReader {
inner: file,
bytes_read: 0,
total_size: file_size,
last_update: Instant::now(),
cancel_signal: cancel_rx,
progress_callback: progress_cb,
};
sevenz_rust::decompress(progress_reader, &output_dir)?;
Ok(())
}).await??;
Ok(())
}
}
impl Default for SevenZDearchiver {
fn default() -> Self {
Self::new()
}
}