use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Product {
pub slug: String,
pub name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Entitlement {
pub key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LicenseResponse {
pub object: String,
pub key: String,
pub status: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub starts_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<DateTime<Utc>>,
pub mode: String,
pub plan_key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub seat_limit: Option<u32>,
pub active_seats: u32,
pub active_entitlements: Vec<Entitlement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
pub product: Product,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ActivationResponse {
pub object: String,
pub id: String,
pub device_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub device_name: Option<String>,
pub license_key: String,
pub activated_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deactivated_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ip_address: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
pub license: LicenseResponse,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct DeactivationResponse {
pub object: String,
pub activation_id: String,
pub deactivated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ValidationWarning {
pub code: String,
pub message: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ActivationNested {
pub id: String,
pub device_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub device_name: Option<String>,
pub license_key: String,
pub activated_at: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub deactivated_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub ip_address: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ValidationResult {
pub object: String,
pub valid: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub code: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub warnings: Option<Vec<ValidationWarning>>,
pub license: LicenseResponse,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub activation: Option<ActivationNested>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HeartbeatResponse {
pub object: String,
pub received_at: DateTime<Utc>,
pub license: LicenseResponse,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HealthResponse {
pub object: String,
pub status: String,
pub api_version: String,
pub timestamp: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct License {
pub license_key: String,
pub device_id: String,
pub activation_id: String,
pub activated_at: DateTime<Utc>,
pub last_validated: DateTime<Utc>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub validation: Option<ValidationResult>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LicenseStatus {
Inactive {
message: String,
},
Pending {
message: String,
},
Invalid {
message: String,
},
Active {
details: LicenseStatusDetails,
},
OfflineValid {
details: LicenseStatusDetails,
},
OfflineInvalid {
message: String,
},
}
impl LicenseStatus {
pub fn is_active(&self) -> bool {
matches!(self, Self::Active { .. } | Self::OfflineValid { .. })
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct LicenseStatusDetails {
pub license: String,
pub device: String,
pub activated_at: DateTime<Utc>,
pub last_validated: DateTime<Utc>,
pub entitlements: Vec<Entitlement>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EntitlementStatus {
pub active: bool,
pub reason: Option<EntitlementReason>,
pub expires_at: Option<DateTime<Utc>>,
pub entitlement: Option<Entitlement>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EntitlementReason {
NoLicense,
NotFound,
Expired,
}
#[cfg(feature = "offline")]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OfflineTokenResponse {
pub object: String,
pub token: OfflineTokenPayload,
pub signature: OfflineTokenSignature,
pub canonical: String,
}
#[cfg(feature = "offline")]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OfflineTokenPayload {
pub schema_version: u32,
pub license_key: String,
pub product_slug: String,
pub plan_key: String,
pub mode: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub seat_limit: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub device_id: Option<String>,
pub iat: i64,
pub exp: i64,
pub nbf: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license_expires_at: Option<i64>,
pub kid: String,
pub entitlements: Vec<OfflineEntitlement>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[cfg(feature = "offline")]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct OfflineEntitlement {
pub key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub expires_at: Option<i64>,
}
#[cfg(feature = "offline")]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct OfflineTokenSignature {
pub algorithm: String,
pub key_id: String,
pub value: String,
}
#[cfg(feature = "offline")]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SigningKeyResponse {
pub object: String,
pub key_id: String,
pub algorithm: String,
pub public_key: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub created_at: Option<DateTime<Utc>>,
pub status: String,
}