use std::fs::{self, OpenOptions};
use std::io::{BufRead, BufReader, Write};
use std::path::PathBuf;
use super::downloads::{DownloadEntry, DownloadStatus};
#[derive(Debug, Clone)]
pub struct StashedEntry {
pub url: String,
pub temp_dest: PathBuf,
pub final_dest: PathBuf,
pub filename: String,
}
fn stash_path() -> PathBuf {
let mut p = home_dir();
p.push("toolkit-zero");
p.push("pending-downloads.stash");
p
}
fn home_dir() -> PathBuf {
std::env::var_os("HOME")
.or_else(|| std::env::var_os("USERPROFILE"))
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("."))
}
pub fn save_stash(downloads: &[DownloadEntry]) {
let path = stash_path();
if let Some(dir) = path.parent() {
let _ = fs::create_dir_all(dir);
}
let in_progress: Vec<&DownloadEntry> = downloads
.iter()
.filter(|d| d.status == DownloadStatus::InProgress)
.collect();
let result = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&path)
.and_then(|mut f| {
for d in &in_progress {
writeln!(
f,
"{}\t{}\t{}\t{}",
d.url.replace('\t', " "),
d.temp_dest.to_string_lossy().replace('\t', " "),
d.final_dest.to_string_lossy().replace('\t', " "),
d.filename.replace('\t', " "),
)?;
}
Ok(())
});
if let Err(e) = result {
eprintln!("[stash] save failed: {e}");
}
}
pub fn load_stash() -> Vec<StashedEntry> {
let path = stash_path();
let file = match fs::File::open(&path) {
Ok(f) => f,
Err(_) => return Vec::new(),
};
let entries: Vec<StashedEntry> = BufReader::new(file)
.lines()
.filter_map(|line| {
let line = line.ok()?;
let line = line.trim();
if line.is_empty() {
return None;
}
let mut parts = line.splitn(4, '\t');
let url = parts.next()?.to_string();
let temp_dest = PathBuf::from(parts.next()?);
let final_dest = PathBuf::from(parts.next()?);
let filename = parts.next()?.to_string();
Some(StashedEntry { url, temp_dest, final_dest, filename })
})
.filter(|e| e.temp_dest.exists()) .collect();
let _ = fs::write(&path, "");
entries
}