Claude: The file are now extracting, albeit slowly
This commit is contained in:
parent
6aea40bfce
commit
98def5fa73
@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use log::{info, error};
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
use std::io::{Read, Seek};
|
||||
use crate::app::GameType;
|
||||
|
||||
pub struct ExtractionManager {
|
||||
@ -35,7 +35,7 @@ impl ExtractionManager {
|
||||
return Err(anyhow::anyhow!("Archive file does not exist"));
|
||||
}
|
||||
|
||||
// Validate 7z signature
|
||||
// Validate 7z signature and get archive size
|
||||
let mut file = fs::File::open(&archive_path)?;
|
||||
let mut signature = [0u8; 6];
|
||||
file.read_exact(&mut signature)?;
|
||||
@ -54,8 +54,8 @@ impl ExtractionManager {
|
||||
}
|
||||
|
||||
// Get file size for progress calculation
|
||||
let file_size = fs::metadata(archive_path)?.len();
|
||||
info!("Archive size: {} bytes", file_size);
|
||||
let archive_size = fs::metadata(archive_path)?.len();
|
||||
info!("Archive size: {} bytes", archive_size);
|
||||
|
||||
// We'll handle extraction in a blocking task since sevenz-rust is synchronous
|
||||
let archive_path = archive_path.to_path_buf();
|
||||
@ -64,12 +64,58 @@ impl ExtractionManager {
|
||||
|
||||
info!("Starting blocking extraction task");
|
||||
tokio::task::spawn_blocking(move || -> Result<()> {
|
||||
info!("Opening archive file for reading");
|
||||
// Open the archive for processing
|
||||
let archive_file = fs::File::open(&archive_path)?;
|
||||
|
||||
// Create a wrapper around the file that tracks read progress
|
||||
struct ProgressReader<R: Read + Seek> {
|
||||
inner: R,
|
||||
bytes_read: u64,
|
||||
total_size: u64,
|
||||
last_progress: f32,
|
||||
progress_callback: Arc<Mutex<Box<dyn Fn(f32, &str) + Send + Sync>>>,
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> Read for ProgressReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let bytes = self.inner.read(buf)?;
|
||||
self.bytes_read += bytes as u64;
|
||||
|
||||
// Calculate progress as a percentage
|
||||
let progress = self.bytes_read as f32 / self.total_size as f32;
|
||||
|
||||
// Only update progress if it has changed by at least 1%
|
||||
if progress - self.last_progress >= 0.01 {
|
||||
self.last_progress = progress;
|
||||
let progress_callback_clone = self.progress_callback.clone();
|
||||
tokio::runtime::Handle::current().block_on(async move {
|
||||
let callback = progress_callback_clone.lock().await;
|
||||
callback(progress, "Extracting...");
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
let progress_reader = ProgressReader {
|
||||
inner: archive_file,
|
||||
bytes_read: 0,
|
||||
total_size: archive_size,
|
||||
last_progress: 0.0,
|
||||
progress_callback: progress_callback.clone(),
|
||||
};
|
||||
|
||||
info!("Starting decompression to: {}", output_dir.display());
|
||||
// decompress takes a Read + Seek and a destination directory
|
||||
match decompress(&archive_file, &output_dir) {
|
||||
|
||||
// Decompress using our progress-tracking reader
|
||||
match decompress(progress_reader, &output_dir) {
|
||||
Ok(_) => info!("Decompression completed successfully"),
|
||||
Err(e) => {
|
||||
error!("Decompression failed: {}", e);
|
||||
@ -77,25 +123,11 @@ impl ExtractionManager {
|
||||
}
|
||||
}
|
||||
|
||||
// List contents of output directory to verify extraction
|
||||
if let Ok(entries) = fs::read_dir(&output_dir) {
|
||||
info!("Listing extracted contents:");
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
info!(" {}", entry.path().display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call progress update with 100% after decompression
|
||||
let filename = archive_path.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or("archive");
|
||||
|
||||
let progress_callback_clone = progress_callback.clone();
|
||||
tokio::runtime::Handle::current().block_on(async move {
|
||||
let callback = progress_callback_clone.lock().await;
|
||||
callback(1.0, filename); // 100% done
|
||||
callback(1.0, "Complete");
|
||||
});
|
||||
|
||||
info!("Extraction task completed successfully");
|
||||
@ -124,32 +156,72 @@ impl ExtractionManager {
|
||||
let file = fs::File::open(&archive_path)?;
|
||||
let mut archive = zip::ZipArchive::new(file)?;
|
||||
|
||||
let total_entries = archive.len();
|
||||
info!("ZIP archive contains {} entries", total_entries);
|
||||
// Calculate total uncompressed size
|
||||
let total_size: u64 = {
|
||||
let mut size = 0;
|
||||
for i in 0..archive.len() {
|
||||
if let Ok(file) = archive.by_index(i) {
|
||||
size += file.size();
|
||||
}
|
||||
}
|
||||
size
|
||||
};
|
||||
|
||||
for i in 0..total_entries {
|
||||
info!("ZIP archive total uncompressed size: {} bytes", total_size);
|
||||
|
||||
let mut processed_bytes: u64 = 0;
|
||||
|
||||
// Process files in batches for better performance
|
||||
let mut pending_dirs = Vec::new();
|
||||
|
||||
// First pass: create all directories (this prevents race conditions)
|
||||
for i in 0..archive.len() {
|
||||
let file = archive.by_index(i)?;
|
||||
let outpath = match file.enclosed_name() {
|
||||
Some(path) => output_dir.join(path),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
if file.name().ends_with('/') {
|
||||
pending_dirs.push(outpath);
|
||||
} else if let Some(p) = outpath.parent() {
|
||||
pending_dirs.push(p.to_path_buf());
|
||||
}
|
||||
}
|
||||
|
||||
// Create all directories at once
|
||||
for dir in pending_dirs.iter().collect::<std::collections::HashSet<_>>() {
|
||||
fs::create_dir_all(dir)?;
|
||||
}
|
||||
|
||||
// Second pass: extract all files
|
||||
for i in 0..archive.len() {
|
||||
let mut file = archive.by_index(i)?;
|
||||
let outpath = match file.enclosed_name() {
|
||||
Some(path) => output_dir.join(path),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// Update progress
|
||||
let progress = (i + 1) as f32 / total_entries as f32;
|
||||
let filename = outpath.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or("unknown");
|
||||
|
||||
if (*file.name()).ends_with('/') {
|
||||
fs::create_dir_all(&outpath)?;
|
||||
} else {
|
||||
if let Some(p) = outpath.parent() {
|
||||
if !p.exists() {
|
||||
fs::create_dir_all(p)?;
|
||||
}
|
||||
}
|
||||
if !file.name().ends_with('/') {
|
||||
let mut outfile = fs::File::create(&outpath)?;
|
||||
let file_size = file.size();
|
||||
std::io::copy(&mut file, &mut outfile)?;
|
||||
processed_bytes += file_size;
|
||||
|
||||
// Update progress based on processed bytes
|
||||
let progress = processed_bytes as f32 / total_size as f32;
|
||||
let filename = outpath.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or("unknown");
|
||||
|
||||
// Update progress less frequently to reduce overhead
|
||||
if i % 10 == 0 || progress >= 1.0 {
|
||||
let progress_callback_clone = progress_callback.clone();
|
||||
tokio::runtime::Handle::current().block_on(async move {
|
||||
let callback = progress_callback_clone.lock().await;
|
||||
callback(progress, filename);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fix file permissions on Unix
|
||||
@ -160,15 +232,15 @@ impl ExtractionManager {
|
||||
fs::set_permissions(&outpath, fs::Permissions::from_mode(mode))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Update progress on the tokio runtime
|
||||
let progress_callback_clone = progress_callback.clone();
|
||||
tokio::runtime::Handle::current().block_on(async move {
|
||||
let callback = progress_callback_clone.lock().await;
|
||||
callback(progress, filename);
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure we show 100% at the end
|
||||
let progress_callback_clone = progress_callback.clone();
|
||||
tokio::runtime::Handle::current().block_on(async move {
|
||||
let callback = progress_callback_clone.lock().await;
|
||||
callback(1.0, "Complete");
|
||||
});
|
||||
|
||||
info!("ZIP extraction completed successfully");
|
||||
Ok(())
|
||||
}).await??;
|
||||
|
Loading…
x
Reference in New Issue
Block a user