goat_cli/search/
mod.rs

1//!
2//! Invoked by calling:
3//! `goat-cli search <args>`
4
5use anyhow::{bail, Result};
6use futures::StreamExt;
7use reqwest;
8use reqwest::header::ACCEPT;
9
10use crate::utils::{cli_matches, utils};
11use crate::{count, IndexType};
12
13/// Execute the `search` subcommand from `goat-cli`. Print a TSV.
14pub async fn search(
15    matches: &clap::ArgMatches,
16    unique_ids: Vec<String>,
17    index_type: IndexType,
18) -> Result<()> {
19    let (_size_int, _url_vector, url_vector_api) =
20        cli_matches::process_cli_args(matches, "search", unique_ids.clone(), index_type)?;
21    let concurrent_requests = url_vector_api.len();
22
23    // print count warnings.
24    count::count(matches, false, true, unique_ids, index_type).await?;
25
26    let fetches = futures::stream::iter(url_vector_api.into_iter().map(|path| async move {
27        // possibly make a again::RetryPolicy
28        // to catch all the values in a *very* large request.
29        let client = reqwest::Client::new();
30
31        match again::retry(|| {
32            client
33                .get(&path)
34                .header(ACCEPT, "text/tab-separated-values")
35                .send()
36        })
37        .await
38        {
39            Ok(resp) => match resp.text().await {
40                Ok(body) => Ok(body),
41                Err(_) => bail!("ERROR reading {}", path),
42            },
43            Err(_) => bail!("ERROR downloading {}", path),
44        }
45    }))
46    .buffered(concurrent_requests)
47    .collect::<Vec<_>>();
48
49    let awaited_fetches = fetches.await;
50
51    utils::format_tsv_output(awaited_fetches)?;
52
53    Ok(())
54}