dynasty 1.4.1

Dynasty Reader's CLI downloader
Documentation
use std::{sync::Arc, time::Duration};

use anyhow::Result;
use tokio::sync::Semaphore;
use tryhard::{backoff_strategies::FixedBackoff, NoOnRetry, RetryFutureConfig};

use crate::{downloader, parser::ParsedArgumentValue, resolver, Cli};

pub type DefaultRetryConfig = RetryFutureConfig<FixedBackoff, NoOnRetry>;

#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct RunnerConfig {
    pub semaphore: Arc<Semaphore>,
    pub retry_config: DefaultRetryConfig,
    #[cfg(feature = "archiver")]
    pub archiver: Option<crate::archiver::Archiver>,
}

impl From<&Cli> for RunnerConfig {
    fn from(cli: &Cli) -> Self {
        let semaphore = Arc::new(Semaphore::new(cli.max_concurrent_request as usize));
        let retry_config =
            RetryFutureConfig::new(cli.max_retry as u32).fixed_backoff(Duration::from_secs(5));

        #[cfg(feature = "archiver")]
        let archiver = cli.archive.map(|archive_kind| crate::archiver::Archiver {
            keep_archived: cli.keep_archived,
            kind: archive_kind,
        });

        RunnerConfig {
            retry_config,
            semaphore,
            #[cfg(feature = "archiver")]
            archiver,
        }
    }
}

pub async fn execute(cli: &Cli) -> Result<()> {
    let config = &cli.into();

    #[cfg(feature = "search")]
    if cli.targets.is_empty() {
        let crate::Commands::Search(value) = &cli.commands;

        run(
            ParsedArgumentValue::Search(value.clone().try_into()?),
            cli,
            config,
        )
        .await?;
    }

    for target in &cli.targets {
        run(target.clone(), cli, config).await?;
    }

    Ok(())
}

async fn run(target: ParsedArgumentValue, cli: &Cli, config: &RunnerConfig) -> Result<()> {
    let (downloadable, client) = resolver::resolve(target, cli, config).await?;

    downloader::download(downloadable, client, cli, config).await
}