Skip to main content

microsandbox_image/
progress.rs

1//! Pull progress reporting.
2
3use std::sync::Arc;
4
5use tokio::sync::mpsc;
6
7//--------------------------------------------------------------------------------------------------
8// Constants
9//--------------------------------------------------------------------------------------------------
10
11/// Default channel capacity.
12const DEFAULT_PROGRESS_CHANNEL_CAPACITY: usize = 256;
13
14//--------------------------------------------------------------------------------------------------
15// Types
16//--------------------------------------------------------------------------------------------------
17
18/// Progress events emitted during image pull and layer extraction.
19#[derive(Debug, Clone)]
20pub enum PullProgress {
21    /// Resolving the image reference.
22    Resolving {
23        /// The image reference being resolved.
24        reference: Arc<str>,
25    },
26
27    /// Manifest parsed. Layer count and total sizes now known.
28    Resolved {
29        /// The image reference.
30        reference: Arc<str>,
31        /// Resolved manifest digest.
32        manifest_digest: Arc<str>,
33        /// Number of layers.
34        layer_count: usize,
35        /// Sum of compressed layer sizes. `None` if manifest omits sizes.
36        total_download_bytes: Option<u64>,
37    },
38
39    /// Byte-level download progress for a single layer.
40    LayerDownloadProgress {
41        /// Layer index (0-based).
42        layer_index: usize,
43        /// Layer digest.
44        digest: Arc<str>,
45        /// Bytes downloaded so far.
46        downloaded_bytes: u64,
47        /// Total bytes (if known).
48        total_bytes: Option<u64>,
49    },
50
51    /// A single layer download completed and verified.
52    LayerDownloadComplete {
53        /// Layer index.
54        layer_index: usize,
55        /// Layer digest.
56        digest: Arc<str>,
57        /// Total downloaded bytes.
58        downloaded_bytes: u64,
59    },
60
61    /// Layer extraction started.
62    LayerExtractStarted {
63        /// Layer index.
64        layer_index: usize,
65        /// Layer diff ID.
66        diff_id: Arc<str>,
67    },
68
69    /// Byte-level extraction progress for a single layer.
70    /// Tracks compressed bytes read from the layer tarball.
71    LayerExtractProgress {
72        /// Layer index (0-based).
73        layer_index: usize,
74        /// Compressed bytes read so far.
75        bytes_read: u64,
76        /// Total compressed file size.
77        total_bytes: u64,
78    },
79
80    /// Layer extraction completed.
81    LayerExtractComplete {
82        /// Layer index.
83        layer_index: usize,
84        /// Layer diff ID.
85        diff_id: Arc<str>,
86    },
87
88    /// Sidecar index generation started for a layer.
89    LayerIndexStarted {
90        /// Layer index.
91        layer_index: usize,
92    },
93
94    /// Sidecar index generation completed for a layer.
95    LayerIndexComplete {
96        /// Layer index.
97        layer_index: usize,
98    },
99
100    /// Entire image pull completed.
101    Complete {
102        /// The image reference.
103        reference: Arc<str>,
104        /// Number of layers.
105        layer_count: usize,
106    },
107}
108
109/// Receiver for progress events.
110pub struct PullProgressHandle {
111    rx: mpsc::Receiver<PullProgress>,
112}
113
114/// Emits progress events. Uses `try_send` — never blocks downloads.
115#[derive(Clone)]
116pub struct PullProgressSender {
117    tx: mpsc::Sender<PullProgress>,
118}
119
120//--------------------------------------------------------------------------------------------------
121// Methods
122//--------------------------------------------------------------------------------------------------
123
124impl PullProgressHandle {
125    /// Receive the next event. Returns `None` when the pull completes.
126    pub async fn recv(&mut self) -> Option<PullProgress> {
127        self.rx.recv().await
128    }
129
130    /// Convert into the underlying receiver for use with `tokio::select!`.
131    pub fn into_receiver(self) -> mpsc::Receiver<PullProgress> {
132        self.rx
133    }
134}
135
136impl PullProgressSender {
137    /// Emit a progress event. Silently discards if receiver is full or dropped.
138    pub fn send(&self, event: PullProgress) {
139        let _ = self.tx.try_send(event);
140    }
141}
142
143//--------------------------------------------------------------------------------------------------
144// Functions
145//--------------------------------------------------------------------------------------------------
146
147/// Create a progress channel pair.
148pub fn progress_channel() -> (PullProgressHandle, PullProgressSender) {
149    let (tx, rx) = mpsc::channel(DEFAULT_PROGRESS_CHANNEL_CAPACITY);
150    (PullProgressHandle { rx }, PullProgressSender { tx })
151}