use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct ManagedDownload {
pub id: usize,
pub url: String,
pub dest: PathBuf,
pub mod_name: Option<String>,
pub state: DownloadState,
}
#[derive(Debug, Clone)]
pub enum DownloadState {
Queued,
Active { progress: f64 },
Paused { bytes: u64 },
Complete { path: PathBuf },
Failed { error: String },
}
pub struct DownloadManager {
downloads: Vec<ManagedDownload>,
max_concurrent: usize,
next_id: usize,
}
impl DownloadManager {
pub fn new(max_concurrent: usize) -> Self {
Self {
downloads: Vec::new(),
max_concurrent,
next_id: 0,
}
}
pub fn enqueue(&mut self, url: String, dest: PathBuf, mod_name: Option<String>) -> usize {
let id = self.next_id;
self.next_id += 1;
self.downloads.push(ManagedDownload {
id,
url,
dest,
mod_name,
state: DownloadState::Queued,
});
id
}
pub fn pause(&mut self, id: usize, bytes_so_far: u64) {
if let Some(dl) = self.get_mut(id) {
if matches!(dl.state, DownloadState::Active { .. }) {
dl.state = DownloadState::Paused {
bytes: bytes_so_far,
};
}
}
}
pub fn resume(&mut self, id: usize) {
if let Some(dl) = self.get_mut(id) {
if matches!(dl.state, DownloadState::Paused { .. }) {
dl.state = DownloadState::Queued;
}
}
}
pub fn cancel(&mut self, id: usize) {
self.downloads.retain(|dl| dl.id != id);
}
pub fn active_count(&self) -> usize {
self.downloads
.iter()
.filter(|dl| matches!(dl.state, DownloadState::Active { .. }))
.count()
}
pub fn max_concurrent(&self) -> usize {
self.max_concurrent
}
pub fn all(&self) -> &[ManagedDownload] {
&self.downloads
}
pub fn get_mut(&mut self, id: usize) -> Option<&mut ManagedDownload> {
self.downloads.iter_mut().find(|dl| dl.id == id)
}
pub fn get(&self, id: usize) -> Option<&ManagedDownload> {
self.downloads.iter().find(|dl| dl.id == id)
}
pub fn can_start_more(&self) -> bool {
self.active_count() < self.max_concurrent
}
pub fn next_queued(&self) -> Vec<usize> {
let budget = self.max_concurrent.saturating_sub(self.active_count());
self.downloads
.iter()
.filter(|dl| matches!(dl.state, DownloadState::Queued))
.take(budget)
.map(|dl| dl.id)
.collect()
}
}