87 lines
2.7 KiB
Rust
87 lines
2.7 KiB
Rust
|
|
//! Client to download data from malie.io
|
||
|
|
|
||
|
|
use anyhow::{Context, Result, anyhow};
|
||
|
|
use camino::Utf8PathBuf;
|
||
|
|
use tokio::fs::File;
|
||
|
|
use tokio_stream::StreamExt;
|
||
|
|
use tokio_util::io::StreamReader;
|
||
|
|
use tracing::debug;
|
||
|
|
|
||
|
|
use super::models::Index;
|
||
|
|
use crate::directories::data_cache_directory;
|
||
|
|
|
||
|
|
/// Client to download data from mallie.io
|
||
|
|
pub struct Client {
|
||
|
|
client: reqwest::Client,
|
||
|
|
data_cache_directory: Utf8PathBuf,
|
||
|
|
}
|
||
|
|
|
||
|
|
const TCGL_BASE_URL: &str = "https://cdn.malie.io/file/malie-io/tcgl/export";
|
||
|
|
|
||
|
|
impl Client {
|
||
|
|
/// Create a new `Client`
|
||
|
|
pub async fn new() -> Result<Self> {
|
||
|
|
Ok(Self {
|
||
|
|
client: reqwest::Client::new(),
|
||
|
|
data_cache_directory: data_cache_directory().await?,
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn download_all_data(&self) -> Result<()> {
|
||
|
|
self.download_tcgl_index_json().await?;
|
||
|
|
let index = self.load_tcgl_index().await?;
|
||
|
|
println!("{index:?}");
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
pub async fn download_tcgl_index_json(&self) -> Result<()> {
|
||
|
|
let file_path = self.data_cache_directory.join("tcgl_index.json");
|
||
|
|
let url = format!("{TCGL_BASE_URL}/index.json");
|
||
|
|
self.download_if_not_exists(file_path, &url).await?;
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
async fn load_tcgl_index(&self) -> Result<Index> {
|
||
|
|
let file_path = self.data_cache_directory.join("tcgl_index.json");
|
||
|
|
let index = tokio::fs::read_to_string(&file_path)
|
||
|
|
.await
|
||
|
|
.with_context(|| format!("Failed to read {file_path}"))?;
|
||
|
|
let index: Index =
|
||
|
|
serde_json::from_str(&index).with_context(|| format!("Couldn't parse {file_path}"))?;
|
||
|
|
Ok(index)
|
||
|
|
}
|
||
|
|
|
||
|
|
async fn download_if_not_exists(&self, file_path: Utf8PathBuf, url: &str) -> Result<()> {
|
||
|
|
if let Ok(true) = tokio::fs::try_exists(&file_path).await {
|
||
|
|
debug!("Found {}, skipping download", &file_path);
|
||
|
|
return Ok(());
|
||
|
|
}
|
||
|
|
|
||
|
|
let response = self.client.get(url).send().await?;
|
||
|
|
if !response.status().is_success() {
|
||
|
|
return Err(anyhow!(
|
||
|
|
"Error {} when downloading: {}",
|
||
|
|
response.status(),
|
||
|
|
url
|
||
|
|
));
|
||
|
|
}
|
||
|
|
|
||
|
|
let mut file = File::create_new(&file_path)
|
||
|
|
.await
|
||
|
|
.with_context(|| format!("Couldn't create file {file_path}"))?;
|
||
|
|
tokio::io::copy_buf(
|
||
|
|
&mut StreamReader::new(
|
||
|
|
response
|
||
|
|
.bytes_stream()
|
||
|
|
.map(|result| result.map_err(std::io::Error::other)),
|
||
|
|
),
|
||
|
|
&mut file,
|
||
|
|
)
|
||
|
|
.await
|
||
|
|
.with_context(|| format!("While writing to file {file_path}"))?;
|
||
|
|
file.sync_all().await?;
|
||
|
|
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
}
|