// Error codes for selfhosted + BitAnswer licensing use crate::CraftResult; #[derive(Debug, Clone, PartialEq)] pub enum LicenseError { // ── 通用 ── Success, ConfigMissing(&'static str), Network(String), NotInitialized, // ── 签名 / 加密 ── InvalidFormat(&'static str), InvalidSignature, SignatureMismatch, CryptoError, DecryptionFailed, CorruptedPayload, LicenseIdMismatch, // ── 许可状态 ── NotYetValid, Expired, NoCachedLicense, OfflineGraceExceeded { days_offline: u32, max_days: u32 }, InvalidLicense, LicenseRevoked, DeviceLimitReached, ConcurrentUserLimitReached, ActivationLimitReached, // ── 兼容比特 ── BitAnswerStatus(u32), // ── 未知 ── UnknownStatus(u16), } impl LicenseError { /// Map BitAnswer BIT_STATUS (u32) → LicenseError (双线共存保留) pub fn from_bit_status(status: u32) -> Self { match status { 0x0000 => LicenseError::Success, 0x0101 => LicenseError::Network("bitanswer network error".into()), 0x0102 => LicenseError::ConfigMissing("bitanswer wrong handle"), 0x0103 => LicenseError::ConfigMissing("bitanswer invalid parameter"), 0x0105 => LicenseError::ConfigMissing("bitanswer application data error"), 0x0114 => LicenseError::InvalidLicense, 0x011C => LicenseError::InvalidLicense, 0x0701 => LicenseError::Expired, 0x0705 => LicenseError::LicenseRevoked, 0x0706 => LicenseError::InvalidLicense, 0x0712 => LicenseError::DeviceLimitReached, 0x0123 => LicenseError::LicenseRevoked, 0x0503 => LicenseError::InvalidLicense, 0x0504 => LicenseError::InvalidLicense, 0x0509 => LicenseError::Expired, 0x0107 => LicenseError::Network("bitanswer server busy".into()), 0x0108 => LicenseError::Network("bitanswer server down".into()), 0x0141 => LicenseError::Network("bitanswer timeout".into()), _ => LicenseError::BitAnswerStatus(status), } } pub fn message(&self) -> &'static str { match self { LicenseError::Success => "ok", LicenseError::ConfigMissing(_) => "config missing", LicenseError::Network(_) => "network error", LicenseError::NotInitialized => "not initialized", LicenseError::InvalidFormat(_) => "invalid format", LicenseError::InvalidSignature => "invalid signature", LicenseError::SignatureMismatch => "signature verification failed", LicenseError::CryptoError => "crypto error", LicenseError::DecryptionFailed => "decryption failed", LicenseError::CorruptedPayload => "corrupted payload", LicenseError::LicenseIdMismatch => "license id mismatch", LicenseError::NotYetValid => "license not yet valid", LicenseError::Expired => "license expired", LicenseError::NoCachedLicense => "no cached license", LicenseError::OfflineGraceExceeded { .. } => "offline grace period exceeded", LicenseError::InvalidLicense => "invalid license", LicenseError::LicenseRevoked => "license revoked", LicenseError::DeviceLimitReached => "device limit reached", LicenseError::ConcurrentUserLimitReached => "concurrent user limit reached", LicenseError::ActivationLimitReached => "activation limit reached", LicenseError::BitAnswerStatus(_) => "bitanswer error", LicenseError::UnknownStatus(_) => "unknown error", } } pub fn is_success(&self) -> bool { matches!(self, LicenseError::Success) } } /// Convert LicenseError to C ABI CraftResult pub fn to_craft_result(error: LicenseError) -> CraftResult { if error.is_success() { CraftResult { success: 1, message: std::ptr::null() } } else { let msg = format!("{}\0", error.message()); let msg_ptr = msg.as_ptr() as *const std::os::raw::c_char; std::mem::forget(msg); CraftResult { success: 0, message: msg_ptr } } }