use std::collections::HashMap;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("configuration error: {0}")]
Configuration(String),
#[error("product_slug is required - set it in Config")]
ProductSlugRequired,
#[error("api_key is required - set it in Config")]
ApiKeyRequired,
#[error("no active license - call activate() first")]
NoActiveLicense,
#[error("API error ({status}): {message}")]
Api {
status: u16,
code: Option<String>,
message: String,
details: Option<HashMap<String, serde_json::Value>>,
},
#[error("network error: {0}")]
Network(#[from] reqwest::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[cfg(feature = "offline")]
#[error("crypto error: {0}")]
Crypto(String),
#[error("offline token expired")]
OfflineTokenExpired,
#[error("offline token verification failed: {0}")]
OfflineVerificationFailed(String),
#[error("clock tampering detected: system time appears to have been manipulated")]
ClockTamperingDetected,
#[error("offline grace period exceeded: last online validation was {days} days ago")]
GracePeriodExceeded {
days: u32,
},
#[error("cache error: {0}")]
Cache(String),
#[error("URL error: {0}")]
Url(#[from] url::ParseError),
}
impl Error {
pub fn api(
status: u16,
code: Option<String>,
message: impl Into<String>,
details: Option<HashMap<String, serde_json::Value>>,
) -> Self {
Self::Api {
status,
code,
message: message.into(),
details,
}
}
pub fn is_network_error(&self) -> bool {
match self {
Self::Network(_) => true,
Self::Api { status, .. } => {
*status == 0 || *status == 408 || (500..600).contains(status)
}
_ => false,
}
}
pub fn is_business_error(&self) -> bool {
match self {
Self::Api { status, .. } => {
(400..500).contains(status) && *status != 401 && *status != 429
}
_ => false,
}
}
pub fn code(&self) -> Option<&str> {
match self {
Self::Api { code, .. } => code.as_deref(),
_ => None,
}
}
pub fn status(&self) -> Option<u16> {
match self {
Self::Api { status, .. } => Some(*status),
_ => None,
}
}
}
pub mod codes {
pub const LICENSE_NOT_FOUND: &str = "license_not_found";
pub const LICENSE_EXPIRED: &str = "license_expired";
pub const LICENSE_SUSPENDED: &str = "license_suspended";
pub const LICENSE_REVOKED: &str = "license_revoked";
pub const SEAT_LIMIT_EXCEEDED: &str = "seat_limit_exceeded";
pub const DEVICE_MISMATCH: &str = "device_mismatch";
pub const PRODUCT_MISMATCH: &str = "product_mismatch";
pub const ALREADY_DEACTIVATED: &str = "already_deactivated";
pub const INVALID_API_KEY: &str = "invalid_api_key";
}