Files
ViewDesignEngine/include/vde/core/license_manager.h
T
茂之钳 5bfcbcb8e9
CI / Build & Test (push) Failing after 39s
CI / Release Build (push) Failing after 33s
Build & Test / build-and-test (push) Has been cancelled
Build & Test / python-bindings (push) Has been cancelled
feat(v1.0.1): tangent_pull + error codes + version + license management
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)
2026-07-27 21:54:46 +08:00

279 lines
10 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
/**
* @file license_manager.h
* @brief ViewDesignEngine 许可证管理系统
*
* 提供三层许可证体系:
* - Community(社区版):基础 B-Rep + STEP/IGES 导入导出
* - Professional(专业版):+ 5轴CAM + 高级曲面 + GD&T
* - Enterprise(企业版):+ 技术支持 + 自定义格式
*
* LicenseKey 格式:VDE-XXXX-XXXX-XXXXBase32编码)
* 包含:版本号 + 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, ///< 基础格式IOOBJ/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