Skip to main content

forge/output/
progress.rs

1use crate::output::OutputConfig;
2use indicatif::{ProgressBar, ProgressStyle};
3use std::time::Duration;
4
5/// Handles progress reporting during conversion
6pub struct ProgressReporter {
7    bar: Option<ProgressBar>,
8}
9
10impl ProgressReporter {
11    pub fn new(config: &OutputConfig) -> Self {
12        let bar = if config.interactive {
13            Some(Self::create_progress_bar(config.use_colors))
14        } else {
15            None
16        };
17
18        Self { bar }
19    }
20
21    /// Start the conversion process
22    pub fn start_conversion(&self) {
23        if let Some(ref bar) = self.bar {
24            bar.set_message("Initializing conversion...");
25            bar.set_position(0);
26        }
27    }
28
29    /// Update progress for file reading
30    pub fn reading_file(&self, filename: &str) {
31        if let Some(ref bar) = self.bar {
32            bar.set_message(format!("Reading PFX file: {}", filename));
33            bar.set_position(1);
34        }
35    }
36
37    /// Update progress for parsing
38    pub fn parsing(&self) {
39        if let Some(ref bar) = self.bar {
40            bar.set_message("Parsing PFX structure...");
41            bar.set_position(2);
42        }
43    }
44
45    /// Update progress for key extraction
46    pub fn extracting_key(&self) {
47        if let Some(ref bar) = self.bar {
48            bar.set_message("Extracting private key...");
49            bar.set_position(3);
50        }
51    }
52
53    /// Update progress for certificate extraction
54    pub fn extracting_cert(&self) {
55        if let Some(ref bar) = self.bar {
56            bar.set_message("Extracting certificate...");
57            bar.set_position(4);
58        }
59    }
60
61    /// Update progress for chain extraction
62    pub fn extracting_chain(&self, count: usize) {
63        if let Some(ref bar) = self.bar {
64            bar.set_message(format!("Extracting certificate chain ({} certs)...", count));
65            bar.set_position(5);
66        }
67    }
68
69    /// Update progress for file writing
70    pub fn writing_files(&self) {
71        if let Some(ref bar) = self.bar {
72            bar.set_message("Writing PEM files...");
73            bar.set_position(6);
74        }
75    }
76
77    /// Complete the process
78    pub fn complete(&self) {
79        if let Some(ref bar) = self.bar {
80            bar.set_message("Conversion completed!");
81            bar.set_position(7);
82            bar.finish();
83        }
84    }
85
86    /// Handle errors
87    pub fn error(&self, message: &str) {
88        if let Some(ref bar) = self.bar {
89            bar.abandon_with_message(format!("Error: {}", message));
90        }
91    }
92
93    /// Create a styled progress bar
94    fn create_progress_bar(use_colors: bool) -> ProgressBar {
95        let bar = ProgressBar::new(7);
96
97        if use_colors {
98            bar.set_style(
99                ProgressStyle::default_bar()
100                    .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {pos}/{len} {msg}")
101                    .unwrap()
102                    .progress_chars("█▉▊▋▌▍▎▏  "),
103            );
104        } else {
105            bar.set_style(
106                ProgressStyle::default_bar()
107                    .template("{spinner} [{elapsed_precise}] [{bar:40}] {pos}/{len} {msg}")
108                    .unwrap()
109                    .progress_chars("#>-"),
110            );
111        }
112
113        bar.enable_steady_tick(Duration::from_millis(100));
114        bar
115    }
116}
117
118impl Drop for ProgressReporter {
119    fn drop(&mut self) {
120        if let Some(ref bar) = self.bar {
121            bar.finish_and_clear();
122        }
123    }
124}