Skip to main content

evm_selectors/
download.rs

1use crate::EvmSelectors;
2use anyhow::Result;
3use reqwest::Client;
4use std::{fs, path::Path, time::Duration};
5
6impl EvmSelectors {
7    /// Downloads the latest known selectors from the [OpenChain API].
8    /// The result is returned as string and not persisted.
9    /// Note that the download speed can differ significantly, from seconds to an hour or more.
10    /// A timeout can be specified to limit the time the request is allowed to take.
11    ///
12    /// # Errors
13    ///
14    /// This function will return an error if the HTTP request fails.
15    ///
16    /// [OpenChain API]: https://docs.openchain.xyz/
17    pub async fn download(timeout: Option<Duration>) -> Result<String> {
18        let url = "https://api.openchain.xyz/signature-database/v1/export";
19        let client = Client::new();
20        let mut request = client.get(url);
21        if let Some(timeout) = timeout {
22            request = request.timeout(timeout);
23        }
24
25        let response = request.send().await?;
26
27        if !response.status().is_success() {
28            return Err(anyhow::anyhow!(
29                "Failed to download from {}: Request returned bad status code {}",
30                url,
31                response.status()
32            ));
33        }
34
35        Ok(response.text().await?)
36    }
37
38    /// Downloads the latest known selectors from the [OpenChain API] and persists them to the file at `path`.
39    /// If the file exists, it will be overwritten. The directory structure will be created if it does not exist.
40    /// Note that the download speed can differ significantly, from seconds to an hour or more.
41    /// A timeout can be specified to limit the time the request is allowed to take.
42    ///
43    /// # Errors
44    ///
45    /// This function will return an error if the HTTP request fails, or if writing to the file fails.
46    ///
47    /// [OpenChain API]: https://docs.openchain.xyz/
48    pub async fn download_to_file(path: &Path, timeout: Option<Duration>) -> Result<()> {
49        let raw = Self::download(timeout).await?;
50        if let Some(parent) = path.parent() {
51            fs::create_dir_all(parent)?;
52        }
53        fs::write(path, raw)?;
54        Ok(())
55    }
56}