5bfcbcb8e9
Remaining P3 item: - tangent_pull: maintain G1 tangency when pulling faces System infrastructure: - Unified ErrorCode (0-7xxx): ErrorInfo with Chinese messages - Version system: VDE_VERSION_MAJOR/MINOR/PATCH macros, vde_version() → VersionInfo, vde_version_string() - License management: LicenseTier (Community/Professional/Enterprise), LicenseKey (VDE-XXXX-XXXX, Base32 + HMAC-SHA256 signature), LicenseManager singleton with trial support - Convenience header: vde/vde_version.h Tests: 43 total (26 license + 17 version)
279 lines
10 KiB
C++
279 lines
10 KiB
C++
#pragma once
|
||
/**
|
||
* @file license_manager.h
|
||
* @brief ViewDesignEngine 许可证管理系统
|
||
*
|
||
* 提供三层许可证体系:
|
||
* - Community(社区版):基础 B-Rep + STEP/IGES 导入导出
|
||
* - Professional(专业版):+ 5轴CAM + 高级曲面 + GD&T
|
||
* - Enterprise(企业版):+ 技术支持 + 自定义格式
|
||
*
|
||
* LicenseKey 格式:VDE-XXXX-XXXX-XXXX(Base32编码)
|
||
* 包含:版本号 + tier + 过期时间 + 签名(HMAC-SHA256)
|
||
*
|
||
* @ingroup core
|
||
*/
|
||
|
||
#include <cstdint>
|
||
#include <string>
|
||
#include <vector>
|
||
#include <set>
|
||
#include <ctime>
|
||
#include <mutex>
|
||
|
||
namespace vde::core {
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// LicenseTier 枚举
|
||
// ═══════════════════════════════════════════════════════════════
|
||
|
||
/// 许可证层级
|
||
enum class LicenseTier : int {
|
||
Community = 0, ///< 社区版
|
||
Professional = 1, ///< 专业版
|
||
Enterprise = 2, ///< 企业版
|
||
};
|
||
|
||
/// 将 LicenseTier 转为字符串
|
||
inline const char* license_tier_name(LicenseTier tier) {
|
||
switch (tier) {
|
||
case LicenseTier::Community: return "Community";
|
||
case LicenseTier::Professional: return "Professional";
|
||
case LicenseTier::Enterprise: return "Enterprise";
|
||
}
|
||
return "Unknown";
|
||
}
|
||
|
||
/// 从字符串解析 LicenseTier,失败返回 -1
|
||
int parse_license_tier(const std::string& name);
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// Feature 枚举(按 tier 区分)
|
||
// ═══════════════════════════════════════════════════════════════
|
||
|
||
/// 功能特性标识
|
||
enum class Feature : int {
|
||
// Community 级别
|
||
BASIC_BREP = 0, ///< 基础B-Rep建模
|
||
STEP_IMPORT_EXPORT = 1, ///< STEP导入导出
|
||
IGES_IMPORT_EXPORT = 2, ///< IGES导入导出
|
||
BASE_IO_FORMATS = 3, ///< 基础格式IO(OBJ/STL/PLY)
|
||
MESH_OPERATIONS = 4, ///< 基本网格操作
|
||
SKETCH_SOLVER = 5, ///< 草图约束求解
|
||
|
||
// Professional 级别
|
||
CAM_5AXIS = 10, ///< 5轴CAM加工
|
||
ADVANCED_SURFACING = 11, ///< 高级曲面建模(A级曲面等)
|
||
GD_T = 12, ///< GD&T 几何尺寸和公差
|
||
PMI_MBD = 13, ///< PMI / 基于模型的定义
|
||
ASSEMBLY_DESIGN = 14, ///< 装配设计
|
||
SHEET_METAL = 15, ///< 钣金设计
|
||
ADVANCED_HEALING = 16, ///< 高级修复
|
||
FEA_MESH = 17, ///< FEA网格生成
|
||
IGA_ANALYSIS = 18, ///< IGA等几何分析
|
||
COLLISION_DETECTION = 19, ///< 碰撞检测
|
||
DIRECT_MODELING = 20, ///< 直接建模
|
||
SURFACE_FAIRING = 21, ///< 曲面光顺
|
||
|
||
// Enterprise 级别
|
||
TECHNICAL_SUPPORT = 30, ///< 技术支持
|
||
CUSTOM_FORMATS = 31, ///< 自定义格式支持
|
||
SCRIPTING_API = 32, ///< 脚本API
|
||
GPU_ACCELERATION = 33, ///< GPU加速
|
||
CLOUD_COLLABORATION = 34, ///< 云端协作
|
||
SDF_MODELING = 35, ///< SDF隐式建模
|
||
LICENSE_MANAGER_SDK = 36, ///< License SDK分发
|
||
};
|
||
|
||
/// Feature 转字符串
|
||
const char* feature_name(Feature f);
|
||
|
||
/// 字符串转 Feature,失败返回 -1
|
||
int parse_feature(const std::string& name);
|
||
|
||
/// 获取指定 tier 包含的所有 feature
|
||
std::set<Feature> features_for_tier(LicenseTier tier);
|
||
|
||
/// 检查某个 feature 是否属于指定 tier
|
||
bool feature_available_in_tier(Feature f, LicenseTier tier);
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// LicenseInfo 结构体
|
||
// ═══════════════════════════════════════════════════════════════
|
||
|
||
/// 许可证信息
|
||
struct LicenseInfo {
|
||
LicenseTier tier; ///< 层级
|
||
std::string licensee; ///< 被许可方(公司/个人名称)
|
||
std::time_t expiry; ///< 过期时间(Unix时间戳,0=永久)
|
||
std::set<Feature> features; ///< 启用的功能列表
|
||
std::string key_string; ///< 原始License Key字符串
|
||
int version; ///< License版本号
|
||
|
||
/// 默认构造(Community试用版)
|
||
LicenseInfo()
|
||
: tier(LicenseTier::Community)
|
||
, licensee("Trial User")
|
||
, expiry(0)
|
||
, version(1) {}
|
||
|
||
/// 是否已过期
|
||
[[nodiscard]] bool is_expired() const;
|
||
|
||
/// 距离过期还剩多少天(返回 -1 表示永久有效)
|
||
[[nodiscard]] int days_until_expiry() const;
|
||
};
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// LicenseKey 类
|
||
// ═══════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief LicenseKey 生成/验证/解析类
|
||
*
|
||
* License Key 格式:VDE-XXXX-XXXX-XXXX
|
||
* 其中 XXXX 段为 Base32 编码的二进制数据。
|
||
*
|
||
* 二进制数据布局(17字节):
|
||
* - byte 0: version (1)
|
||
* - byte 1: tier (0=Community, 1=Professional, 2=Enterprise)
|
||
* - byte 2-9: expiry (uint64_t, Unix timestamp, big-endian)
|
||
* - byte 10-16: reserved (0)
|
||
*
|
||
* 签名:HMAC-SHA256 的前 4 字节附加到 Base32 编码后的最后一段。
|
||
*
|
||
* 完整的 Key 编码流程:
|
||
* payload(17B) → HMAC-SHA256 → 取前4B → payload+signature(21B) → Base32 → VDE-XXXX-XXXX-XXXX
|
||
*/
|
||
class LicenseKey {
|
||
public:
|
||
/// 默认构造(无效Key)
|
||
LicenseKey() = default;
|
||
|
||
/**
|
||
* @brief 从字符串解析 LicenseKey
|
||
* @param key_str 如 "VDE-ABCD-EFGH-IJKL"
|
||
* @return 如果格式有效返回 true
|
||
*/
|
||
bool parse(const std::string& key_str);
|
||
|
||
/**
|
||
* @brief 生成 LicenseKey
|
||
* @param tier 许可证层级
|
||
* @param expiry 过期时间(Unix时间戳,0=永久)
|
||
* @param licensee 被许可方名称
|
||
* @return 格式化的License Key字符串
|
||
*/
|
||
static std::string generate(LicenseTier tier, std::time_t expiry,
|
||
const std::string& licensee);
|
||
|
||
/**
|
||
* @brief 验证 LicenseKey 是否有效
|
||
* @param key_str License Key 字符串
|
||
* @return 有效则返回 true
|
||
*/
|
||
static bool validate(const std::string& key_str);
|
||
|
||
/// 获取解析后的 LicenseInfo
|
||
[[nodiscard]] const LicenseInfo& info() const { return info_; }
|
||
|
||
/// 原始 Key 字符串
|
||
[[nodiscard]] const std::string& key_string() const { return key_string_; }
|
||
|
||
/// 签名验证是否通过
|
||
[[nodiscard]] bool signature_valid() const { return sig_valid_; }
|
||
|
||
private:
|
||
/// Base32 编解码(RFC 4648,无填充)
|
||
static std::string base32_encode(const std::vector<uint8_t>& data);
|
||
static std::vector<uint8_t> base32_decode(const std::string& encoded);
|
||
|
||
/// HMAC-SHA256 简化实现(使用占位密钥)
|
||
static std::vector<uint8_t> compute_hmac(const std::vector<uint8_t>& data);
|
||
|
||
LicenseInfo info_;
|
||
std::string key_string_;
|
||
bool sig_valid_ = false;
|
||
};
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// LicenseManager 单例
|
||
// ═══════════════════════════════════════════════════════════════
|
||
|
||
/**
|
||
* @brief LicenseManager 全局许可证管理器(单例)
|
||
*
|
||
* 管理当前运行时使用的许可证,提供功能查询接口。
|
||
*
|
||
* 用法:
|
||
* @code
|
||
* auto& mgr = LicenseManager::instance();
|
||
* mgr.set_license("VDE-ABCD-EFGH-IJKL");
|
||
* if (mgr.has_feature("CAM_5AXIS")) { ... }
|
||
* if (mgr.is_expired()) { ... }
|
||
* @endcode
|
||
*/
|
||
class LicenseManager {
|
||
public:
|
||
/// 获取单例实例
|
||
static LicenseManager& instance();
|
||
|
||
// ── 禁止拷贝和移动 ──────────────────────────────
|
||
LicenseManager(const LicenseManager&) = delete;
|
||
LicenseManager& operator=(const LicenseManager&) = delete;
|
||
|
||
/**
|
||
* @brief 设置 License Key
|
||
* @param key License Key 字符串
|
||
* @return true 设置成功(Key有效且未过期)
|
||
*/
|
||
bool set_license(const std::string& key);
|
||
|
||
/**
|
||
* @brief 进入试用模式(30天Community试用)
|
||
* @param days 试用天数(默认30)
|
||
*/
|
||
void start_trial(int days = 30);
|
||
|
||
/// 当前许可证层级
|
||
[[nodiscard]] LicenseTier current_tier() const;
|
||
|
||
/**
|
||
* @brief 检查是否拥有某个功能
|
||
* @param feature_name 功能名称字符串(如 "CAM_5AXIS")
|
||
* @return true 表示该功能可用
|
||
*/
|
||
[[nodiscard]] bool has_feature(const std::string& feature_name) const;
|
||
|
||
/**
|
||
* @brief 检查 Feature 枚举是否可用
|
||
* @param f Feature 枚举值
|
||
* @return true 表示该功能可用
|
||
*/
|
||
[[nodiscard]] bool has_feature(Feature f) const;
|
||
|
||
/// 许可证是否已过期
|
||
[[nodiscard]] bool is_expired() const;
|
||
|
||
/// 试用剩余天数(-1 表示已过期或无试用)
|
||
[[nodiscard]] int trial_days_left() const;
|
||
|
||
/// 获取当前许可证信息
|
||
[[nodiscard]] const LicenseInfo& current_license() const;
|
||
|
||
/// 是否处于试用模式
|
||
[[nodiscard]] bool is_trial() const;
|
||
|
||
private:
|
||
LicenseManager();
|
||
~LicenseManager() = default;
|
||
|
||
LicenseInfo current_;
|
||
bool trial_mode_ = false;
|
||
std::time_t trial_start_ = 0;
|
||
int trial_days_ = 30;
|
||
mutable std::mutex mutex_;
|
||
};
|
||
|
||
} // namespace vde::core
|