use crate::{
activation::{ActivationRequest, ActivationResponse},
error::LicenseError,
license::License,
};
use reqwest::{Client, StatusCode};
use tracing::{debug, error, info, warn};
#[derive(Debug, Clone)]
pub struct LicenseClient {
base_url: String,
client: Client,
api_key: Option<String>,
}
impl LicenseClient {
pub fn new(base_url: &str) -> Self {
info!("Initializing LicenseClient with base URL: {}", base_url);
Self {
base_url: base_url.to_string(),
client: Client::new(),
api_key: None,
}
}
pub fn with_api_key(mut self, api_key: &str) -> Self {
self.api_key = Some(api_key.to_string());
self
}
pub async fn activate_license(
&self,
request: &ActivationRequest,
) -> Result<ActivationResponse, LicenseError> {
info!("Activating license: {}", request.license_id);
debug!("Activation request: {:?}", request);
let url = format!("{}/api/v1/licenses/activate", self.base_url);
let mut req = self.client.post(&url).json(request);
if let Some(api_key) = &self.api_key {
req = req.bearer_auth(api_key);
}
let response = req.send().await?;
match response.status() {
StatusCode::OK => {
let activation: ActivationResponse = response.json().await?;
info!(
"License activated successfully: {}",
activation.activation_id
);
Ok(activation)
}
StatusCode::FORBIDDEN => {
error!("Activation forbidden - license may be invalid or expired");
Err(LicenseError::InvalidLicense(
"Activation forbidden".to_string(),
))
}
StatusCode::TOO_MANY_REQUESTS => {
error!("Activation limit exceeded");
Err(LicenseError::ActivationLimitExceeded)
}
_ => {
let error_text = response.text().await.unwrap_or_default();
error!("Activation failed: {}", error_text);
Err(LicenseError::ServerError(error_text))
}
}
}
pub async fn validate_license(
&self,
license_id: &uuid::Uuid,
activation_token: &str,
) -> Result<License, LicenseError> {
info!("Validating license: {}", license_id);
let url = format!("{}/api/v1/licenses/{}/validate", self.base_url, license_id);
let response = self
.client
.get(&url)
.bearer_auth(activation_token)
.send()
.await?;
if response.status().is_success() {
let license: License = response.json().await?;
debug!("License validation successful");
Ok(license)
} else {
let error_text = response.text().await.unwrap_or_default();
error!("License validation failed: {}", error_text);
Err(LicenseError::ValidationFailed(error_text))
}
}
pub async fn check_revocation(&self, license_id: &uuid::Uuid) -> Result<bool, LicenseError> {
debug!("Checking revocation status for license: {}", license_id);
let url = format!("{}/api/v1/licenses/{}/revoked", self.base_url, license_id);
let response = self.client.get(&url).send().await?;
if response.status().is_success() {
let revoked: bool = response.json().await?;
if revoked {
warn!("License {} is revoked", license_id);
}
Ok(revoked)
} else {
error!("Failed to check revocation status");
Ok(false)
}
}
}