Skip to main content

kernel/install/
event.rs

1//! The progress and event types an install emits.
2
3use serde::{Deserialize, Serialize};
4
5/// Download progress for an install: bytes so far, the total (when known), and
6/// which file is in flight.
7///
8/// Serializable because a detached pull writes it into its `status.json`, which
9/// is the only way an attached client learns how far along the transfer is.
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
11pub struct InstallProgress {
12    /// Bytes downloaded so far.
13    #[serde(default)]
14    pub bytes_downloaded: i64,
15    /// The total to download, if known.
16    #[serde(skip_serializing_if = "Option::is_none", default)]
17    pub total_bytes: Option<i64>,
18    /// Whether `total_bytes` is a partial/growing estimate (so no fraction).
19    #[serde(default)]
20    pub total_is_partial: bool,
21    /// The file currently downloading, if any.
22    #[serde(skip_serializing_if = "Option::is_none", default)]
23    pub current_file: Option<String>,
24}
25
26impl InstallProgress {
27    /// The completed fraction in `[0, 1]`, or `None` when the total is unknown,
28    /// zero, or only a partial estimate.
29    pub fn fraction(&self) -> Option<f64> {
30        let total = self.total_bytes?;
31        if total <= 0 || self.total_is_partial {
32            return None;
33        }
34        Some((self.bytes_downloaded as f64 / total as f64).clamp(0.0, 1.0))
35    }
36}
37
38/// A lifecycle event for an install job.
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub enum InstallEvent {
41    /// Waiting to start.
42    Queued,
43    /// Resolving the plan before transfer.
44    Preparing,
45    /// A human-readable status line.
46    Status(String),
47    /// Download progress.
48    Progress(InstallProgress),
49    /// Completed successfully.
50    Done,
51    /// Failed, with a message.
52    Failed {
53        /// Why it failed.
54        message: String,
55    },
56    /// Cancelled by the user.
57    Cancelled,
58}
59
60impl InstallEvent {
61    /// Whether this event ends the job (done/failed/cancelled).
62    pub fn is_terminal(&self) -> bool {
63        matches!(
64            self,
65            InstallEvent::Done | InstallEvent::Failed { .. } | InstallEvent::Cancelled
66        )
67    }
68}
69
70/// What a provider's transfer emits while running (before the terminal event is
71/// synthesized by the install service).
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
73pub enum InstallStreamEvent {
74    /// A status line.
75    Status(String),
76    /// Download progress.
77    Progress(InstallProgress),
78}