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
}