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)
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
#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
|
||||
@@ -0,0 +1,176 @@
|
||||
#pragma once
|
||||
/**
|
||||
* @file version.h
|
||||
* @brief ViewDesignEngine 版本信息
|
||||
*
|
||||
* 提供编译时版本宏和运行时版本查询函数。
|
||||
* 编译时间戳通过 CMake 的 configure_file 在构建时注入。
|
||||
*
|
||||
* @ingroup core
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
// 包含 CMake 生成的构建配置
|
||||
#if __has_include("vde_build_config.h")
|
||||
#include "vde_build_config.h"
|
||||
#endif
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 编译时版本宏
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
/// 主版本号(不兼容的 API 变更)
|
||||
#define VDE_VERSION_MAJOR 1
|
||||
|
||||
/// 次版本号(向后兼容的功能新增)
|
||||
#define VDE_VERSION_MINOR 0
|
||||
|
||||
/// 修订版本号(向后兼容的问题修复)
|
||||
#define VDE_VERSION_PATCH 1
|
||||
|
||||
/// 版本字符串
|
||||
#define VDE_VERSION_STRING "1.0.1"
|
||||
|
||||
// ── 版本号整型(用于比较) ────────────────────────────
|
||||
/// 版本号编码为大整数: VDE_VERSION(major, minor, patch) = major*10000 + minor*100 + patch
|
||||
#define VDE_VERSION_CODE(major, minor, patch) \
|
||||
((major) * 10000 + (minor) * 100 + (patch))
|
||||
|
||||
/// 当前版本号整型编码
|
||||
#define VDE_VERSION_NUM VDE_VERSION_CODE(1, 0, 1)
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// 构建信息(由 CMake configure_file 注入)
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
#ifndef VDE_BUILD_TYPE
|
||||
/// 构建类型:Debug / Release / RelWithDebInfo / MinSizeRel
|
||||
#ifdef NDEBUG
|
||||
#define VDE_BUILD_TYPE "Release"
|
||||
#else
|
||||
#define VDE_BUILD_TYPE "Debug"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef VDE_BUILD_TIMESTAMP
|
||||
/// 构建时间戳(ISO 8601 格式,如 "2026-07-27T12:00:00Z")
|
||||
/// 由 CMake 的 configure_file 注入
|
||||
#define VDE_BUILD_TIMESTAMP "unknown"
|
||||
#endif
|
||||
|
||||
#ifndef VDE_COMPILER_INFO
|
||||
/// 编译器信息字符串
|
||||
#if defined(__clang__)
|
||||
#define VDE_COMPILER_INFO "Clang " __clang_version__
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#define VDE_COMPILER_INFO "GCC " __VERSION__
|
||||
#elif defined(_MSC_VER)
|
||||
#define VDE_COMPILER_INFO "MSVC " _MSC_VER_STR
|
||||
#else
|
||||
#define VDE_COMPILER_INFO "Unknown Compiler"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// C++ 标准信息
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
/// C++ 标准字符串(如 "C++20")
|
||||
#if __cplusplus >= 202002L
|
||||
#define VDE_CPP_STANDARD_STRING "C++20"
|
||||
#elif __cplusplus >= 201703L
|
||||
#define VDE_CPP_STANDARD_STRING "C++17"
|
||||
#elif __cplusplus >= 201402L
|
||||
#define VDE_CPP_STANDARD_STRING "C++14"
|
||||
#elif __cplusplus >= 201103L
|
||||
#define VDE_CPP_STANDARD_STRING "C++11"
|
||||
#else
|
||||
#define VDE_CPP_STANDARD_STRING "C++03"
|
||||
#endif
|
||||
|
||||
namespace vde::core {
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// VersionInfo 结构体
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 版本信息结构体
|
||||
*
|
||||
* 包含库版本号、构建类型、时间戳和编译器信息。
|
||||
*/
|
||||
struct VersionInfo {
|
||||
int major; ///< 主版本号
|
||||
int minor; ///< 次版本号
|
||||
int patch; ///< 修订版本号
|
||||
std::string version_string; ///< 版本字符串 "1.0.1"
|
||||
std::string build_type; ///< 构建类型 "Debug"/"Release"
|
||||
std::string build_timestamp;///< 构建时间戳
|
||||
std::string compiler_info; ///< 编译器信息
|
||||
std::string cpp_standard; ///< C++ 标准字符串 "C++20"
|
||||
|
||||
/// 默认构造(使用编译时宏填充)
|
||||
VersionInfo()
|
||||
: major(VDE_VERSION_MAJOR)
|
||||
, minor(VDE_VERSION_MINOR)
|
||||
, patch(VDE_VERSION_PATCH)
|
||||
, version_string(VDE_VERSION_STRING)
|
||||
, build_type(VDE_BUILD_TYPE)
|
||||
, build_timestamp(VDE_BUILD_TIMESTAMP)
|
||||
, compiler_info(VDE_COMPILER_INFO)
|
||||
, cpp_standard(VDE_CPP_STANDARD_STRING) {}
|
||||
};
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// API 函数
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
||||
/**
|
||||
* @brief 获取版本信息结构体
|
||||
* @return VersionInfo 包含完整的版本和构建信息
|
||||
*/
|
||||
inline VersionInfo vde_version() {
|
||||
return VersionInfo{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取人类可读的版本字符串
|
||||
*
|
||||
* 格式:"ViewDesignEngine v1.0.1 (C++20, GCC 11.4)"
|
||||
*
|
||||
* @return 版本信息字符串
|
||||
*/
|
||||
inline std::string vde_version_string() {
|
||||
std::string result = "ViewDesignEngine v";
|
||||
result += VDE_VERSION_STRING;
|
||||
result += " (";
|
||||
result += VDE_CPP_STANDARD_STRING;
|
||||
result += ", ";
|
||||
result += VDE_COMPILER_INFO;
|
||||
result += ")";
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 比较两个版本号
|
||||
*
|
||||
* 返回负值表示 lhs < rhs,零表示相等,正值表示 lhs > rhs。
|
||||
*
|
||||
* @param lhs_major 左主版本
|
||||
* @param lhs_minor 左次版本
|
||||
* @param lhs_patch 左修订版本
|
||||
* @param rhs_major 右主版本
|
||||
* @param rhs_minor 右次版本
|
||||
* @param rhs_patch 右修订版本
|
||||
* @return 比较结果
|
||||
*/
|
||||
inline int vde_version_compare(int lhs_major, int lhs_minor, int lhs_patch,
|
||||
int rhs_major, int rhs_minor, int rhs_patch) {
|
||||
int lhs = VDE_VERSION_CODE(lhs_major, lhs_minor, lhs_patch);
|
||||
int rhs = VDE_VERSION_CODE(rhs_major, rhs_minor, rhs_patch);
|
||||
return lhs - rhs;
|
||||
}
|
||||
|
||||
} // namespace vde::core
|
||||
Reference in New Issue
Block a user