Skip to main content

romm_api/core/download/
extras_job.rs

1//! Composite extras download job state.
2
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5use crate::core::extras::DownloadAssetKind;
6
7/// Outcome of one item inside an [`ExtrasJob`].
8#[derive(Debug, Clone)]
9pub struct ExtrasItemResult {
10    pub title: String,
11    pub kind: DownloadAssetKind,
12    pub ok: bool,
13    pub error: Option<String>,
14}
15
16/// Terminal status for a composite extras download.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum ExtrasJobStatus {
19    Running,
20    Done,
21    /// Some items failed (`usize` = failure count).
22    PartialFailure(usize),
23    AllFailed,
24}
25
26/// One queued extras batch for a parent ROM (related files + cover + manual).
27#[derive(Debug, Clone)]
28pub struct ExtrasJob {
29    pub id: usize,
30    pub rom_id: u64,
31    pub name: String,
32    pub platform: String,
33    pub completed_items: usize,
34    pub total_items: usize,
35    pub status: ExtrasJobStatus,
36    pub item_results: Vec<ExtrasItemResult>,
37}
38
39static NEXT_EXTRAS_JOB_ID: AtomicUsize = AtomicUsize::new(0);
40
41impl ExtrasJob {
42    pub fn new(rom_id: u64, name: String, platform: String, total_items: usize) -> Self {
43        Self {
44            id: NEXT_EXTRAS_JOB_ID.fetch_add(1, Ordering::Relaxed),
45            rom_id,
46            name,
47            platform,
48            completed_items: 0,
49            total_items,
50            status: ExtrasJobStatus::Running,
51            item_results: Vec::new(),
52        }
53    }
54
55    /// Progress 0..=100 from completed item count only.
56    pub fn percent(&self) -> u16 {
57        if self.total_items == 0 {
58            return 100;
59        }
60        ((self.completed_items.saturating_mul(100)) / self.total_items).min(100) as u16
61    }
62}
63
64pub(crate) fn finalize_extras_job_status(results: &[ExtrasItemResult]) -> ExtrasJobStatus {
65    let n = results.len();
66    if n == 0 {
67        return ExtrasJobStatus::Done;
68    }
69    let failures = results.iter().filter(|r| !r.ok).count();
70    if failures == 0 {
71        ExtrasJobStatus::Done
72    } else if failures == n {
73        ExtrasJobStatus::AllFailed
74    } else {
75        ExtrasJobStatus::PartialFailure(failures)
76    }
77}