mega-cli 0.1.3

A command-line tool for interacting with MEGA
use std::process::ExitCode;
use std::sync::Arc;
use std::time::Duration;

use clap::Parser;
use color_eyre::eyre::{Context, ContextCompat};
use dialoguer::theme::ColorfulTheme;
use dialoguer::{Input, Password};
use indicatif::ProgressBar;

use crate::config::{Config, CONFIG_NAME};
use crate::utils;
use crate::utils::terminal::USER_ATTENDED;
use crate::Result;

#[derive(Debug, Clone, PartialEq, Parser)]
#[command(author, rename_all = "kebab-case")]
pub struct Opts {}

impl Opts {
    pub fn may_need_user_session(&self) -> bool {
        true
    }
}

pub async fn handle(mut config: Config, mega: &mut Arc<mega::Client>, _: Opts) -> Result<ExitCode> {
    let theme = ColorfulTheme::default();

    let email: String = Input::with_theme(&theme)
        .with_prompt("Enter email address")
        .interact_text()?;

    let password: String = Password::with_theme(&theme)
        .with_prompt("Enter password")
        .interact()?;

    let maybe_bar = USER_ATTENDED.then(|| {
        let bar = ProgressBar::new_spinner();
        bar.set_style(utils::terminal::spinner_style());
        bar.set_message("logging in to MEGA...");
        bar.enable_steady_tick(Duration::from_millis(75));
        bar
    });

    let mega = Arc::get_mut(mega).context("could not mutably borrow MEGA client")?;

    let result = mega.login(&email, &password, None).await;

    if let Some(bar) = maybe_bar {
        bar.finish_and_clear();
    }

    if let Err(mega::Error::MegaError {
        code: mega::ErrorCode::EMFAREQUIRED,
    }) = result
    {
        let mfa: String = Input::with_theme(&theme)
            .with_prompt("Enter MFA code")
            .interact_text()?;

        let maybe_bar = USER_ATTENDED.then(|| {
            let bar = ProgressBar::new_spinner();
            bar.set_style(utils::terminal::spinner_style());
            bar.set_message("logging in to MEGA...");
            bar.enable_steady_tick(Duration::from_millis(75));
            bar
        });

        mega.login(&email, &password, Some(&mfa))
            .await
            .context("could not log in to MEGA")?;

        if let Some(bar) = maybe_bar {
            bar.finish_and_clear();
        }
    } else {
        result.context("could not log in to MEGA")?;
    }

    let session = mega
        .serialize_session()
        .await
        .context("could not serialize MEGA session")?;

    match config {
        Config::V1(ref mut config) => {
            config.auth.session = Some(session);
        }
    }

    confy::store(CONFIG_NAME, None, config).context("could not save configuration")?;

    crate::success!(to: std::io::stdout(), "successfully logged in to MEGA !")?;

    Ok(ExitCode::SUCCESS)
}