use anyhow::{Context, Result};
use std::time::{Duration, Instant};
use wme_client::{Tokens, WmeClient};
use crate::config::Config;
pub async fn build_client(config: &Config, token_override: Option<String>) -> Result<WmeClient> {
if let Some(token) = token_override {
return build_client_with_token(token).await;
}
if let (Some(access_token), Some(refresh_token), Some(expires_at_str), Some(username)) = (
&config.access_token,
&config.refresh_token,
&config.token_expires_at,
&config.username,
) {
let expires_at = chrono::DateTime::parse_from_rfc3339(expires_at_str)
.map_err(|e| anyhow::anyhow!("Invalid token expiration time in config: {}", e))?
.with_timezone(&chrono::Utc);
let now = chrono::Utc::now();
let expires_in = if expires_at > now {
expires_at
.signed_duration_since(now)
.to_std()
.unwrap_or(Duration::from_secs(0))
} else {
Duration::from_secs(0)
};
let expires_at_instant = Instant::now() + expires_in;
let client = WmeClient::builder()
.credentials(username, "unused")
.build()
.await
.context("Failed to create WME client")?;
if let Some(token_manager) = client.token_manager() {
let tokens = Tokens {
id_token: String::new(), access_token: access_token.clone(),
refresh_token: refresh_token.clone(),
expires_at: expires_at_instant,
};
token_manager.set_tokens(tokens);
}
return Ok(client);
}
Err(anyhow::anyhow!(
"No authentication token available.\n\
Please run 'wme auth login' or provide a token with --token"
))
}
async fn build_client_with_token(token: String) -> Result<WmeClient> {
let client = WmeClient::builder()
.credentials("token_auth", "unused")
.build()
.await
.context("Failed to create WME client")?;
if let Some(token_manager) = client.token_manager() {
let tokens = Tokens {
id_token: String::new(),
access_token: token,
refresh_token: String::new(), expires_at: Instant::now() + Duration::from_secs(365 * 24 * 60 * 60), };
token_manager.set_tokens(tokens);
}
Ok(client)
}
pub async fn build_client_with_credentials(
username: impl Into<String>,
password: impl Into<String>,
) -> Result<WmeClient> {
let client = WmeClient::builder()
.credentials(username, password)
.build()
.await
.context("Failed to create WME client")?;
Ok(client)
}
pub fn map_client_error(e: wme_client::ClientError) -> anyhow::Error {
match e {
wme_client::ClientError::Auth(msg) => anyhow::anyhow!("Authentication failed: {}", msg),
wme_client::ClientError::TokenExpired => {
anyhow::anyhow!("Token expired. Please run 'wme auth login' to re-authenticate.")
}
wme_client::ClientError::SnapshotNotFound { id } => {
anyhow::anyhow!("Snapshot '{}' not found", id)
}
wme_client::ClientError::ArticleNotFound { name } => {
anyhow::anyhow!("Article '{}' not found", name)
}
wme_client::ClientError::RateLimited { retry_after } => {
if let Some(secs) = retry_after {
anyhow::anyhow!("Rate limited. Please retry after {} seconds", secs)
} else {
anyhow::anyhow!("Rate limited. Please retry later")
}
}
wme_client::ClientError::Network(msg) => anyhow::anyhow!("Network error: {}", msg),
wme_client::ClientError::Http(msg) => anyhow::anyhow!("HTTP error: {}", msg),
wme_client::ClientError::JsonParse(msg) => anyhow::anyhow!("Parse error: {}", msg),
wme_client::ClientError::Io(msg) => anyhow::anyhow!("IO error: {}", msg),
wme_client::ClientError::Stream(msg) => anyhow::anyhow!("Stream error: {}", msg),
wme_client::ClientError::Config(msg) => anyhow::anyhow!("Configuration error: {}", msg),
}
}