s3m-core 0.18.0

Reusable S3 client and streaming engine behind the s3m CLI
Documentation
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
use std::time::Duration;

// "█▉▊▋▌▍▎▏  ·"
const PROGRES_CHARS: &str =
    "\u{2588}\u{2589}\u{258a}\u{258b}\u{258c}\u{258d}\u{258e}\u{258f}  \u{b7}";

const PROGRES_CHARS_SPINNER: &[&str] = &["◜", "◠", "◝", "◞", "◡", "◟"];

#[derive(Default, Debug)]
pub struct Bar {
    pub progress: Option<ProgressBar>,
}

pub struct StreamBars {
    _multi: MultiProgress,
    pub staging: ProgressBar,
    pub status: ProgressBar,
}

impl Bar {
    #[must_use]
    pub fn new(file_size: u64) -> Self {
        let pb = ProgressBar::new(file_size);

        let style_result = ProgressStyle::default_bar()
            .template("[{elapsed_precise}] {bar:50.green/blue} {bytes}/{total_bytes} ({bytes_per_sec} - {eta})");

        let style = match style_result {
            Ok(style) => style,
            Err(err) => {
                eprintln!("Error creating progress bar style: {err}");
                return Self { progress: None };
            }
        };

        pb.set_style(style.progress_chars(PROGRES_CHARS));

        Self { progress: Some(pb) }
    }

    #[must_use]
    pub fn new_spinner() -> Self {
        let pb = ProgressBar::new_spinner();

        pb.enable_steady_tick(Duration::from_millis(200));

        let style_result = ProgressStyle::default_spinner()
            .tick_strings(PROGRES_CHARS_SPINNER)
            .template("checksum: {spinner:.green}");

        let style = match style_result {
            Ok(s) => s,
            Err(err) => {
                eprintln!("Error creating spinner style: {err}");
                return Self { progress: None };
            }
        };

        pb.set_style(style);

        Self { progress: Some(pb) }
    }

    #[must_use]
    pub fn new_stream(buffer_size: u64) -> Option<StreamBars> {
        let multi = MultiProgress::new();

        let staging = multi.add(ProgressBar::new(buffer_size));
        let staging_style = match ProgressStyle::with_template(
            "[{elapsed_precise}] buffering {bytes}/{total_bytes}",
        ) {
            Ok(style) => style,
            Err(err) => {
                eprintln!("Error creating staging progress style: {err}");
                return None;
            }
        };
        staging.set_style(staging_style);

        let status = multi.add(ProgressBar::new_spinner());
        status.enable_steady_tick(Duration::from_millis(200));

        let uploaded_style = match ProgressStyle::default_spinner()
            .tick_strings(PROGRES_CHARS_SPINNER)
            .template("[{elapsed_precise}] {msg} {spinner:.green}")
        {
            Ok(style) => style,
            Err(err) => {
                eprintln!("Error creating uploaded progress style: {err}");
                return None;
            }
        };
        status.set_style(uploaded_style);

        Some(StreamBars {
            _multi: multi,
            staging,
            status,
        })
    }
}