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 = 1024;
13
14//--------------------------------------------------------------------------------------------------
15// Types
16//--------------------------------------------------------------------------------------------------
17
18/// Progress events emitted during image pull and EROFS materialization.
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 download completed and the blob is being verified.
62    LayerDownloadVerifying {
63        /// Layer index.
64        layer_index: usize,
65        /// Layer digest.
66        digest: Arc<str>,
67    },
68
69    /// Layer EROFS materialization started.
70    LayerMaterializeStarted {
71        /// Layer index.
72        layer_index: usize,
73        /// Layer diff ID.
74        diff_id: Arc<str>,
75    },
76
77    /// Byte-level materialization progress for a single layer.
78    LayerMaterializeProgress {
79        /// Layer index (0-based).
80        layer_index: usize,
81        /// Bytes read so far.
82        bytes_read: u64,
83        /// Total bytes.
84        total_bytes: u64,
85    },
86
87    /// Layer tar ingest is complete and the EROFS image is being written.
88    LayerMaterializeWriting {
89        /// Layer index.
90        layer_index: usize,
91    },
92
93    /// Layer EROFS materialization completed.
94    LayerMaterializeComplete {
95        /// Layer index.
96        layer_index: usize,
97        /// Layer diff ID.
98        diff_id: Arc<str>,
99    },
100
101    /// Merging per-layer trees into the unified rootfs view.
102    StitchMergingTrees {
103        /// Number of layers being merged.
104        layer_count: usize,
105    },
106
107    /// Writing the fsmeta EROFS image (metadata-only merged view).
108    StitchWritingFsmeta,
109
110    /// Writing the VMDK descriptor that stitches fsmeta + layer EROFSes.
111    StitchWritingVmdk,
112
113    /// Stitching phase finished — fsmeta + VMDK are on disk.
114    StitchComplete,
115
116    /// Entire image pull completed.
117    Complete {
118        /// The image reference.
119        reference: Arc<str>,
120        /// Number of layers.
121        layer_count: usize,
122    },
123}
124
125/// Receiver for progress events.
126pub struct PullProgressHandle {
127    rx: mpsc::Receiver<PullProgress>,
128}
129
130/// Emits progress events. Uses `try_send` — never blocks downloads.
131#[derive(Clone)]
132pub struct PullProgressSender {
133    tx: mpsc::Sender<PullProgress>,
134}
135
136//--------------------------------------------------------------------------------------------------
137// Methods
138//--------------------------------------------------------------------------------------------------
139
140impl PullProgressHandle {
141    /// Receive the next event. Returns `None` when the pull completes.
142    pub async fn recv(&mut self) -> Option<PullProgress> {
143        self.rx.recv().await
144    }
145
146    /// Convert into the underlying receiver for use with `tokio::select!`.
147    pub fn into_receiver(self) -> mpsc::Receiver<PullProgress> {
148        self.rx
149    }
150}
151
152impl PullProgressSender {
153    /// Emit a progress event. Silently discards if receiver is full or dropped.
154    pub fn send(&self, event: PullProgress) {
155        let _ = self.tx.try_send(event);
156    }
157}
158
159//--------------------------------------------------------------------------------------------------
160// Functions
161//--------------------------------------------------------------------------------------------------
162
163/// Create a progress channel pair.
164pub fn progress_channel() -> (PullProgressHandle, PullProgressSender) {
165    let (tx, rx) = mpsc::channel(DEFAULT_PROGRESS_CHANNEL_CAPACITY);
166    (PullProgressHandle { rx }, PullProgressSender { tx })
167}