use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use crate::error::{MtgjsonError, Result};
use crate::MtgjsonSdk;
pub struct AsyncMtgjsonSdkBuilder {
cache_dir: Option<PathBuf>,
offline: bool,
timeout: Duration,
}
impl Default for AsyncMtgjsonSdkBuilder {
fn default() -> Self {
Self {
cache_dir: None,
offline: false,
timeout: Duration::from_secs(120),
}
}
}
impl AsyncMtgjsonSdkBuilder {
pub fn cache_dir<P: AsRef<Path>>(mut self, path: P) -> Self {
self.cache_dir = Some(path.as_ref().to_path_buf());
self
}
pub fn offline(mut self, offline: bool) -> Self {
self.offline = offline;
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub async fn build(self) -> Result<AsyncMtgjsonSdk> {
tokio::task::spawn_blocking(move || {
let mut builder = MtgjsonSdk::builder();
if let Some(dir) = self.cache_dir {
builder = builder.cache_dir(dir);
}
builder = builder.offline(self.offline).timeout(self.timeout);
let sdk = builder.build()?;
Ok(AsyncMtgjsonSdk {
inner: Arc::new(Mutex::new(sdk)),
})
})
.await
.map_err(|e| MtgjsonError::InvalidArgument(format!("Task join error: {e}")))?
}
}
pub struct AsyncMtgjsonSdk {
inner: Arc<Mutex<MtgjsonSdk>>,
}
impl AsyncMtgjsonSdk {
pub fn builder() -> AsyncMtgjsonSdkBuilder {
AsyncMtgjsonSdkBuilder::default()
}
pub async fn run<F, T>(&self, f: F) -> Result<T>
where
F: FnOnce(&MtgjsonSdk) -> Result<T> + Send + 'static,
T: Send + 'static,
{
let sdk = self.inner.clone();
tokio::task::spawn_blocking(move || {
let guard = sdk
.lock()
.map_err(|_| MtgjsonError::InvalidArgument("SDK lock poisoned".into()))?;
f(&guard)
})
.await
.map_err(|e| MtgjsonError::InvalidArgument(format!("Task join error: {e}")))?
}
pub async fn sql(
&self,
query: &str,
params: &[String],
) -> Result<Vec<HashMap<String, serde_json::Value>>> {
let query = query.to_string();
let params = params.to_vec();
self.run(move |s| s.sql(&query, ¶ms)).await
}
pub async fn meta(&self) -> Result<serde_json::Value> {
self.run(|s| s.meta()).await
}
pub async fn refresh(&self) -> Result<bool> {
self.run(|s| s.refresh()).await
}
pub async fn views(&self) -> Result<Vec<String>> {
self.run(|s| Ok(s.views())).await
}
pub async fn close(self) -> Result<()> {
tokio::task::spawn_blocking(move || {
let sdk = self
.inner
.lock()
.map_err(|_| MtgjsonError::InvalidArgument("SDK lock poisoned".into()))?;
drop(sdk);
Ok(())
})
.await
.map_err(|e| MtgjsonError::InvalidArgument(format!("Task join error: {e}")))?
}
}