use std::path::Path;
use anyhow::Context;
use cfg_match::cfg_match;
use reqwest::{Client, IntoUrl, Url};
use serde::de::DeserializeOwned;
cfg_match! {
target_os = "windows" => {
pub const FD_SENSIBLE_LIMIT: usize = 64;
}
_ => {
pub const FD_SENSIBLE_LIMIT: usize = 16;
}
}
pub async fn download(url: impl IntoUrl, client: &Client) -> anyhow::Result<reqwest::Response> {
let resp = client
.get(url)
.send()
.await
.context("Failed to send request")?
.error_for_status()
.context("Server reported an error")?;
Ok(resp)
}
pub async fn text(url: impl IntoUrl, client: &Client) -> anyhow::Result<String> {
let text = download(url, client)
.await
.context("Failed to download")?
.text()
.await
.context("Failed to convert download to text")?;
Ok(text)
}
pub async fn bytes(url: impl IntoUrl, client: &Client) -> anyhow::Result<bytes::Bytes> {
let bytes = download(url, client)
.await
.context("Failed to download")?
.bytes()
.await
.context("Failed to convert download to raw bytes")?;
Ok(bytes)
}
pub async fn file(url: impl IntoUrl, path: &Path, client: &Client) -> anyhow::Result<()> {
let bytes = bytes(url, client)
.await
.context("Failed to download data")?;
tokio::fs::write(path, bytes).await.with_context(|| {
format!(
"Failed to write downloaded contents to path {}",
path.display()
)
})?;
Ok(())
}
pub async fn json<T: DeserializeOwned>(url: impl IntoUrl, client: &Client) -> anyhow::Result<T> {
download(url, client)
.await
.context("Failed to download JSON data")?
.json()
.await
.context("Failed to parse JSON")
}
pub fn validate_url(url: &str) -> anyhow::Result<()> {
Url::parse(url).context(
"It may help to make sure that either http:// or https:// is before the domain name",
)?;
Ok(())
}