596 lines
27 KiB
C#
596 lines
27 KiB
C#
using System;
|
||
using System.Configuration;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using System.Threading;
|
||
using XP.Common.License.Configs;
|
||
using XP.Common.License.Enums;
|
||
using XP.Common.License.Interfaces;
|
||
using XP.Common.License.Native;
|
||
using XP.Common.Logging.Interfaces;
|
||
|
||
namespace XP.Common.License.Implementations
|
||
{
|
||
/// <summary>
|
||
/// 授权服务实现 | License service implementation
|
||
/// </summary>
|
||
public class LicenseService : ILicenseService, IDisposable
|
||
{
|
||
/// <summary>
|
||
/// 临时测试模式初始时间(秒)| Temporary test mode initial time (seconds)
|
||
/// </summary>
|
||
private const int TestModeInitialSeconds = 900;
|
||
|
||
/// <summary>
|
||
/// 授权配置 | License configuration
|
||
/// </summary>
|
||
private readonly LicenseConfig _config;
|
||
|
||
/// <summary>
|
||
/// 日志服务 | Logger service
|
||
/// </summary>
|
||
private readonly ILoggerService _logger;
|
||
|
||
/// <summary>
|
||
/// 同步锁对象 | Synchronization lock object
|
||
/// </summary>
|
||
private readonly object _lock = new object();
|
||
|
||
/// <summary>
|
||
/// 临时测试模式计时器 | Temporary test mode timer
|
||
/// </summary>
|
||
private Timer? _testModeTimer;
|
||
|
||
/// <summary>
|
||
/// 临时测试模式剩余时间(秒)| Temporary test mode remaining time (seconds)
|
||
/// </summary>
|
||
private int _remainingTestSeconds = TestModeInitialSeconds;
|
||
|
||
/// <summary>
|
||
/// 授权到期日期 | License expiration date
|
||
/// </summary>
|
||
private DateTime? _expirationDate;
|
||
|
||
/// <summary>
|
||
/// SMA到期日期 | SMA expiration date
|
||
/// </summary>
|
||
private DateTime? _smaDate;
|
||
|
||
/// <summary>
|
||
/// 浮动许可IP地址 | Floating license IP address
|
||
/// </summary>
|
||
private string? _floatingLicenseIp;
|
||
|
||
/// <summary>
|
||
/// 浮动许可端口 | Floating license port
|
||
/// </summary>
|
||
private string? _floatingLicensePort;
|
||
|
||
/// <summary>
|
||
/// 是否已释放 | Whether disposed
|
||
/// </summary>
|
||
private bool _disposed;
|
||
|
||
/// <summary>
|
||
/// 构造函数 | Constructor
|
||
/// </summary>
|
||
/// <param name="config">授权配置 | License configuration</param>
|
||
/// <param name="logger">日志服务 | Logger service</param>
|
||
public LicenseService(LicenseConfig config, ILoggerService logger)
|
||
{
|
||
_config = config ?? throw new ArgumentNullException(nameof(config));
|
||
_logger = logger?.ForModule<LicenseService>() ?? throw new ArgumentNullException(nameof(logger));
|
||
LicenseMode = (LicenseMode)_config.LicenseMode;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前会话是否已授权 | Whether the current session is authorized
|
||
/// </summary>
|
||
public bool IsAuthorized { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 当前授权模式 | Current license mode
|
||
/// </summary>
|
||
public LicenseMode LicenseMode { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 临时测试模式超时事件(到期时触发)| Temporary test mode timeout event (fires when expired)
|
||
/// </summary>
|
||
public event EventHandler? TestModeTimeout;
|
||
|
||
/// <summary>
|
||
/// 临时测试模式剩余5分钟警告事件 | Temporary test mode 5-minute warning event
|
||
/// </summary>
|
||
public event EventHandler? TestModeWarning5Min;
|
||
|
||
/// <summary>
|
||
/// 临时测试模式剩余1分钟警告事件 | Temporary test mode 1-minute warning event
|
||
/// </summary>
|
||
public event EventHandler? TestModeWarning1Min;
|
||
|
||
/// <summary>
|
||
/// 是否已触发5分钟警告 | Whether 5-minute warning has been fired
|
||
/// </summary>
|
||
private bool _warning5MinFired;
|
||
|
||
/// <summary>
|
||
/// 是否已触发1分钟警告 | Whether 1-minute warning has been fired
|
||
/// </summary>
|
||
private bool _warning1MinFired;
|
||
|
||
/// <summary>
|
||
/// 执行授权检查 | Perform authorization check
|
||
/// </summary>
|
||
/// <returns>授权检查结果 | License check result</returns>
|
||
public LicenseCheckResult CheckAuthorization()
|
||
{
|
||
lock (_lock)
|
||
{
|
||
_logger.Info("开始授权检查,模式={Mode} | Starting authorization check, mode={Mode}", (int)LicenseMode);
|
||
|
||
if (LicenseMode == Enums.LicenseMode.TemporaryTest)
|
||
{
|
||
return HandleTemporaryTestMode();
|
||
}
|
||
|
||
return HandleClmsAuthorization();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取授权到期日期 | Get license expiration date
|
||
/// </summary>
|
||
/// <returns>授权到期日期,未授权时返回 null | License expiration date, null if not authorized</returns>
|
||
public DateTime? GetExpirationDate()
|
||
{
|
||
lock (_lock)
|
||
{
|
||
return _expirationDate;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查模块是否授权 | Check if module is licensed
|
||
/// </summary>
|
||
/// <param name="moduleId">模块ID | Module ID</param>
|
||
/// <returns>模块是否授权 | Whether the module is licensed</returns>
|
||
public bool IsModuleLicensed(ushort moduleId)
|
||
{
|
||
lock (_lock)
|
||
{
|
||
if (!IsAuthorized)
|
||
return false;
|
||
|
||
try
|
||
{
|
||
ushort mod = moduleId;
|
||
ushort type = 0;
|
||
return NativeMethods.CLM_ModuleIsLicensed(ref mod, ref type);
|
||
}
|
||
catch (DllNotFoundException ex)
|
||
{
|
||
_logger.Error(ex, "MORCODE.dll 加载失败 | Failed to load MORCODE.dll");
|
||
return false;
|
||
}
|
||
catch (EntryPointNotFoundException ex)
|
||
{
|
||
_logger.Error(ex, "MORCODE.dll 中缺少入口点 | Missing entry point in MORCODE.dll");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取SMA到期日期 | Get SMA expiration date
|
||
/// </summary>
|
||
/// <returns>SMA到期日期,未启用时返回 null | SMA expiration date, null if not enabled</returns>
|
||
public DateTime? GetSmaDate()
|
||
{
|
||
lock (_lock)
|
||
{
|
||
return _smaDate;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取临时测试模式剩余时间 | Get remaining time in temporary test mode
|
||
/// </summary>
|
||
/// <returns>剩余时间(秒),非测试模式返回 -1 | Remaining time in seconds, -1 if not in test mode</returns>
|
||
public int GetRemainingTestTime()
|
||
{
|
||
if (LicenseMode != Enums.LicenseMode.TemporaryTest)
|
||
return -1;
|
||
|
||
return Interlocked.CompareExchange(ref _remainingTestSeconds, 0, 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 释放资源 | Release resources
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
if (_disposed)
|
||
return;
|
||
|
||
_disposed = true;
|
||
|
||
// 停止计时器 | Stop timer
|
||
_testModeTimer?.Dispose();
|
||
_testModeTimer = null;
|
||
|
||
// 尝试登出 | Try to logout
|
||
try
|
||
{
|
||
NativeMethods.CLM_Logout();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "CLM_Logout 调用失败 | CLM_Logout call failed");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理临时测试模式 | Handle temporary test mode
|
||
/// </summary>
|
||
/// <returns>授权检查结果 | License check result</returns>
|
||
private LicenseCheckResult HandleTemporaryTestMode()
|
||
{
|
||
IsAuthorized = true;
|
||
_remainingTestSeconds = TestModeInitialSeconds;
|
||
|
||
// 启动计时器,每秒递减 | Start timer, decrement every second
|
||
_testModeTimer?.Dispose();
|
||
_testModeTimer = new Timer(TestModeTimerCallback, null, 1000, 1000);
|
||
|
||
_logger.Info("临时测试模式已启动,剩余时间={Seconds}秒 | Temporary test mode started, remaining time={Seconds}s", TestModeInitialSeconds);
|
||
|
||
WriteLicenseStateToConfig(LicenseState.Success);
|
||
|
||
return new LicenseCheckResult(
|
||
isAuthorized: true,
|
||
message: "临时测试模式已启动,有效时间15分钟 | Temporary test mode started, valid for 15 minutes",
|
||
licenseMode: Enums.LicenseMode.TemporaryTest,
|
||
moduleId: _config.ModuleId,
|
||
expirationDate: null,
|
||
smaDate: null,
|
||
floatingLicenseIp: null,
|
||
floatingLicensePort: null);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 临时测试模式计时器回调 | Temporary test mode timer callback
|
||
/// </summary>
|
||
/// <param name="state">状态对象 | State object</param>
|
||
private void TestModeTimerCallback(object? state)
|
||
{
|
||
int remaining = Interlocked.Decrement(ref _remainingTestSeconds);
|
||
|
||
// 剩余5分钟(300秒)时触发警告 | Fire warning at 5 minutes (300 seconds) remaining
|
||
if (remaining <= 300 && !_warning5MinFired)
|
||
{
|
||
_warning5MinFired = true;
|
||
_logger.Warn("临时测试模式剩余5分钟 | Temporary test mode: 5 minutes remaining");
|
||
TestModeWarning5Min?.Invoke(this, EventArgs.Empty);
|
||
}
|
||
|
||
// 剩余1分钟(60秒)时触发警告 | Fire warning at 1 minute (60 seconds) remaining
|
||
if (remaining <= 60 && !_warning1MinFired)
|
||
{
|
||
_warning1MinFired = true;
|
||
_logger.Warn("临时测试模式剩余1分钟 | Temporary test mode: 1 minute remaining");
|
||
TestModeWarning1Min?.Invoke(this, EventArgs.Empty);
|
||
}
|
||
|
||
// 到期时触发超时事件 | Fire timeout event when expired
|
||
if (remaining <= 0)
|
||
{
|
||
// 停止计时器 | Stop timer
|
||
_testModeTimer?.Dispose();
|
||
_testModeTimer = null;
|
||
|
||
_logger.Info("临时测试模式已超时 | Temporary test mode has timed out");
|
||
|
||
// 触发超时事件 | Raise timeout event
|
||
TestModeTimeout?.Invoke(this, EventArgs.Empty);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理 CLMS 正式授权流程 | Handle CLMS formal authorization flow
|
||
/// 兼容新旧版本 SDK:对可能不存在的入口点使用 TryInvoke 优雅降级 |
|
||
/// Compatible with old/new SDK: gracefully degrades for missing entry points via TryInvoke
|
||
/// </summary>
|
||
/// <returns>授权检查结果 | License check result</returns>
|
||
private LicenseCheckResult HandleClmsAuthorization()
|
||
{
|
||
try
|
||
{
|
||
// 步骤 1:检查系统时间(可选,老版本 SDK 可能不支持)| Step 1: Check system time (optional, old SDK may not support)
|
||
if (!TryInvokeOptional(() => NativeMethods.CLM_CheckSystemTime(), "CLM_CheckSystemTime", out bool checkTimeResult))
|
||
{
|
||
// 入口点不存在,跳过此步骤 | Entry point not found, skip this step
|
||
_logger.Warn("CLM_CheckSystemTime 入口点不存在,跳过系统时间检查(SDK版本较旧)| CLM_CheckSystemTime entry point not found, skipping system time check (older SDK version)");
|
||
}
|
||
else if (!checkTimeResult)
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_CheckSystemTime"), "系统时间检查异常 | System time check anomaly");
|
||
return CreateFailureResult("系统时间检查异常 | System time check anomaly");
|
||
}
|
||
else
|
||
{
|
||
_logger.Info("系统时间检查正常 | System time check: OK");
|
||
}
|
||
|
||
// 步骤 2:登录验证(核心,必须存在)| Step 2: Login verification (core, must exist)
|
||
StringBuilder password = new StringBuilder("FnEoFWSNLpVeoNWYhVoHLfgITRvieSszJfylVsXOTsLkphgkPzPhbLQzQrvRbNOkVVIQyMWkyGVjWSaiYUEksfQsRmklksLxrmeTksKKNMoZoWfZeDaLDSyWwEmtQakvSNxBMBLHoLEZHtaoXNpTWiaUGaSLQdsHFZnbRyPehytarNTKpaNNqnjFNggqWifhFsrZasDsWbIGWDrhnGrdtUNDMjJdhlTunsssxCzYpsLQrWBxUkuUUEJraSbTlbuX");
|
||
if (!NativeMethods.CLM_Login(password))
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_Login"), "CLM_Login 登录验证失败 | CLM_Login verification failed");
|
||
return CreateFailureResult("CLM_Login 登录验证失败 | CLM_Login verification failed");
|
||
}
|
||
_logger.Info("CLM_Login 登录验证成功 | CLM_Login verification: OK");
|
||
|
||
// 步骤 3:检查许可范围(核心,必须存在)| Step 3: Check license scope (core, must exist)
|
||
if (!NativeMethods.CLM_Login_Scope())
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_Login_Scope"), "CLM_Login_Scope 许可范围检查失败 | CLM_Login_Scope scope check failed");
|
||
return CreateFailureResult("CLM_Login_Scope 许可范围检查失败 | CLM_Login_Scope scope check failed");
|
||
}
|
||
_logger.Info("CLM_Login_Scope 许可范围检查成功 | CLM_Login_Scope scope check: OK");
|
||
|
||
// 步骤 4:SMA 验证(如果启用,可选入口点)| Step 4: SMA validation (if enabled, optional entry point)
|
||
if (_config.UseSma)
|
||
{
|
||
var smaResult = ValidateSma();
|
||
if (smaResult != null)
|
||
return smaResult;
|
||
}
|
||
else
|
||
{
|
||
_logger.Info("放弃检查SMA | SMA check skipped");
|
||
}
|
||
|
||
// 步骤 5:获取浮动许可IP和端口(可选,老版本 SDK 可能不支持)| Step 5: Get floating license IP and port (optional, old SDK may not support)
|
||
StringBuilder ip = new StringBuilder(256);
|
||
StringBuilder port = new StringBuilder(256);
|
||
if (!TryInvokeOptional(() => NativeMethods.CLM_GetIP(ip, port), "CLM_GetIP", out bool getIpResult))
|
||
{
|
||
_logger.Warn("CLM_GetIP 入口点不存在,跳过浮动许可IP获取(SDK版本较旧)| CLM_GetIP entry point not found, skipping floating license IP retrieval (older SDK version)");
|
||
}
|
||
else if (!getIpResult)
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_GetIP"), "CLM_GetIP 获取浮动许可IP失败 | CLM_GetIP floating license IP retrieval failed");
|
||
return CreateFailureResult("CLM_GetIP 获取浮动许可IP失败 | CLM_GetIP floating license IP retrieval failed");
|
||
}
|
||
else
|
||
{
|
||
_floatingLicenseIp = ip.ToString();
|
||
_floatingLicensePort = port.ToString();
|
||
_logger.Info("CLM_GetIP 成功: ip={Ip}/port={Port} | CLM_GetIP success: ip={Ip}/port={Port}", _floatingLicenseIp, _floatingLicensePort);
|
||
}
|
||
|
||
// 步骤 6:获取错误信息(可选,老版本 SDK 可能不支持)| Step 6: Get error message (optional, old SDK may not support)
|
||
StringBuilder error = new StringBuilder(512);
|
||
if (!TryInvokeOptional(() => NativeMethods.CLM_GetError(error), "CLM_GetError", out bool getErrorResult))
|
||
{
|
||
_logger.Warn("CLM_GetError 入口点不存在,跳过错误信息获取(SDK版本较旧)| CLM_GetError entry point not found, skipping error retrieval (older SDK version)");
|
||
}
|
||
else if (!getErrorResult)
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_GetError"), "CLM_GetError 获取错误信息失败 | CLM_GetError error retrieval failed");
|
||
return CreateFailureResult("CLM_GetError 获取错误信息失败 | CLM_GetError error retrieval failed");
|
||
}
|
||
else
|
||
{
|
||
_logger.Info("CLM_GetError 成功: {Error} | CLM_GetError success: {Error}", error.ToString());
|
||
}
|
||
|
||
// 步骤 7:检查模块授权(核心,必须存在)| Step 7: Check module authorization (core, must exist)
|
||
ushort moduleId = _config.ModuleId;
|
||
ushort type = 0;
|
||
if (!NativeMethods.CLM_ModuleIsLicensed(ref moduleId, ref type))
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_ModuleIsLicensed"), "模块号码{ModuleId}不可用 | Module {ModuleId} unavailable", moduleId);
|
||
return CreateFailureResult($"模块号码{moduleId}不可用 | Module {moduleId} unavailable");
|
||
}
|
||
_logger.Info("模块号码{ModuleId}有效 | Module {ModuleId} available", moduleId);
|
||
|
||
// 步骤 8:获取授权到期日期(核心,必须存在)| Step 8: Get warranty expiration date (core, must exist)
|
||
int month = 0, day = 0, year = 0;
|
||
if (!NativeMethods.CLM_GetWarrantyExpiration(ref month, ref day, ref year))
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_GetWarrantyExpiration"), "获取授权到期日期失败 | Failed to get warranty expiration date");
|
||
return CreateFailureResult("获取授权到期日期失败 | Failed to get warranty expiration date");
|
||
}
|
||
|
||
_expirationDate = new DateTime(year, month, day);
|
||
_logger.Info("CLM_GetWarrantyExpiration 成功: {Year}/{Month}/{Day} | CLM_GetWarrantyExpiration success: {Year}/{Month}/{Day}", year, month, day);
|
||
|
||
// 检查是否在30天内到期 | Check if expiring within 30 days
|
||
string warningMessage = string.Empty;
|
||
TimeSpan timeToExpiry = _expirationDate.Value - DateTime.Now;
|
||
if (timeToExpiry.Days <= 30)
|
||
{
|
||
warningMessage = $"软件授权将于{year}年{month}月{day}日到期,请尽快联系海克斯康 | Software license will expire on {year}-{month}-{day}, please contact Hexagon";
|
||
_logger.Warn(warningMessage);
|
||
}
|
||
|
||
// 授权成功 | Authorization successful
|
||
IsAuthorized = true;
|
||
WriteLicenseStateToConfig(LicenseState.Success);
|
||
|
||
string successMessage = string.IsNullOrEmpty(warningMessage)
|
||
? "授权检查成功 | Authorization check successful"
|
||
: $"授权检查成功(警告:{warningMessage})| Authorization check successful (Warning: {warningMessage})";
|
||
|
||
_logger.Info("授权检查完成 | Authorization check completed: Mode={Mode}, State={State}, Expiration={Expiration}",
|
||
(int)LicenseMode,
|
||
(int)LicenseState.Success,
|
||
_expirationDate?.ToString("yyyy-MM-dd") ?? "N/A");
|
||
|
||
return new LicenseCheckResult(
|
||
isAuthorized: true,
|
||
message: successMessage,
|
||
licenseMode: LicenseMode,
|
||
moduleId: _config.ModuleId,
|
||
expirationDate: _expirationDate,
|
||
smaDate: _smaDate,
|
||
floatingLicenseIp: _floatingLicenseIp,
|
||
floatingLicensePort: _floatingLicensePort);
|
||
}
|
||
catch (DllNotFoundException ex)
|
||
{
|
||
_logger.Error(ex, "MORCODE.dll 加载失败 | Failed to load MORCODE.dll");
|
||
return CreateFailureResult("CLMS SDK 不可用 | CLMS SDK unavailable");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试调用可选的 SDK 方法,兼容老版本 SDK 中不存在的入口点 |
|
||
/// Try to invoke an optional SDK method, compatible with missing entry points in older SDK versions
|
||
/// </summary>
|
||
/// <param name="action">要调用的方法委托 | Method delegate to invoke</param>
|
||
/// <param name="methodName">方法名称(用于日志)| Method name (for logging)</param>
|
||
/// <param name="result">方法返回值,入口点不存在时为 default | Method return value, default if entry point not found</param>
|
||
/// <returns>true: 入口点存在并已调用; false: 入口点不存在(EntryPointNotFoundException)| true: entry point exists and was invoked; false: entry point not found</returns>
|
||
private bool TryInvokeOptional(Func<bool> action, string methodName, out bool result)
|
||
{
|
||
try
|
||
{
|
||
result = action();
|
||
return true;
|
||
}
|
||
catch (EntryPointNotFoundException)
|
||
{
|
||
result = default;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 验证 SMA | Validate SMA
|
||
/// 兼容老版本 SDK:CLM_GetSmaDate 入口点不存在时跳过 SMA 验证 |
|
||
/// Compatible with old SDK: skips SMA validation if CLM_GetSmaDate entry point not found
|
||
/// </summary>
|
||
/// <returns>失败时返回失败结果,成功或跳过时返回 null | Returns failure result on failure, null on success or skip</returns>
|
||
private LicenseCheckResult? ValidateSma()
|
||
{
|
||
int yearSma = 0, monthSma = 0, daySma = 0;
|
||
|
||
// CLM_GetSmaDate 在老版本 SDK 中可能不存在 | CLM_GetSmaDate may not exist in older SDK
|
||
try
|
||
{
|
||
if (!NativeMethods.CLM_GetSmaDate(ref monthSma, ref daySma, ref yearSma))
|
||
{
|
||
_logger.Error(new InvalidOperationException("CLM_GetSmaDate"), "检查SMA失败 | SMA check failed");
|
||
return CreateFailureResult("检查SMA失败 | SMA check failed");
|
||
}
|
||
}
|
||
catch (EntryPointNotFoundException)
|
||
{
|
||
_logger.Warn("CLM_GetSmaDate 入口点不存在,跳过SMA验证(SDK版本较旧)| CLM_GetSmaDate entry point not found, skipping SMA validation (older SDK version)");
|
||
return null;
|
||
}
|
||
|
||
_logger.Info("CLM_GetSmaDate 成功: {Year}/{Month}/{Day} | CLM_GetSmaDate success: {Year}/{Month}/{Day}", yearSma, monthSma, daySma);
|
||
|
||
// 获取软件版本信息 | Get software version information
|
||
var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||
int major = version?.Major ?? 0;
|
||
int minor = version?.Minor ?? 0;
|
||
|
||
// SMA 年份 < 软件主版本号 → 失败 | SMA year < software major version → failure
|
||
if (yearSma < major)
|
||
{
|
||
string msg = $"CLMS授权中SMA年份{yearSma}小于软件主版本号(年份){major},请联系海克斯康升级许可 | SMA year {yearSma} is less than software major version {major}, please contact Hexagon to upgrade license";
|
||
_logger.Error(new InvalidOperationException("SMA验证失败"), msg);
|
||
return CreateFailureResult(msg);
|
||
}
|
||
|
||
// SMA 年份 == 软件主版本号时,校验季度 | When SMA year == software major version, validate quarter
|
||
if (yearSma == major)
|
||
{
|
||
try
|
||
{
|
||
DateTime smaDate = new DateTime(yearSma, monthSma, daySma);
|
||
int smaQuarter = (smaDate.Month - 1) / 3 + 1;
|
||
|
||
if (minor > smaQuarter)
|
||
{
|
||
string msg = $"CLMS授权日期{yearSma}/{monthSma}/{daySma}属于{yearSma}年第{smaQuarter}季度,不支持当前{major}年第{minor}季度的软件版本 | SMA date {yearSma}/{monthSma}/{daySma} is in Q{smaQuarter} of {yearSma}, does not support current Q{minor} of {major} software version";
|
||
_logger.Error(new InvalidOperationException("SMA季度验证失败"), msg);
|
||
return CreateFailureResult(msg);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
string msg = $"SMA授权日期{yearSma}/{monthSma}/{daySma}不合法 | SMA date {yearSma}/{monthSma}/{daySma} is invalid: {ex.Message}";
|
||
_logger.Error(ex, msg);
|
||
return CreateFailureResult(msg);
|
||
}
|
||
}
|
||
|
||
_smaDate = new DateTime(yearSma, monthSma, daySma);
|
||
_logger.Info("SMA校验成功,SMA有效期至{Year}/{Month}/{Day} | SMA validation successful, valid until {Year}/{Month}/{Day}", yearSma, monthSma, daySma);
|
||
return null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 创建失败结果 | Create failure result
|
||
/// </summary>
|
||
/// <param name="message">失败消息 | Failure message</param>
|
||
/// <returns>授权检查失败结果 | License check failure result</returns>
|
||
private LicenseCheckResult CreateFailureResult(string message)
|
||
{
|
||
IsAuthorized = false;
|
||
WriteLicenseStateToConfig(LicenseState.Fail);
|
||
|
||
_logger.Info("授权检查完成 | Authorization check completed: Mode={Mode}, State={State}, Expiration={Expiration}",
|
||
(int)LicenseMode,
|
||
(int)LicenseState.Fail,
|
||
"N/A");
|
||
|
||
return new LicenseCheckResult(
|
||
isAuthorized: false,
|
||
message: message,
|
||
licenseMode: LicenseMode,
|
||
moduleId: _config.ModuleId,
|
||
expirationDate: null,
|
||
smaDate: _smaDate,
|
||
floatingLicenseIp: _floatingLicenseIp,
|
||
floatingLicensePort: _floatingLicensePort);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 写入授权状态到配置文件 | Write license state to configuration file
|
||
/// </summary>
|
||
/// <param name="state">授权状态 | License state</param>
|
||
private void WriteLicenseStateToConfig(LicenseState state)
|
||
{
|
||
try
|
||
{
|
||
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
|
||
var settings = config.AppSettings.Settings;
|
||
|
||
if (settings["License:LicenseState"] == null)
|
||
{
|
||
settings.Add("License:LicenseState", ((int)state).ToString());
|
||
}
|
||
else
|
||
{
|
||
settings["License:LicenseState"].Value = ((int)state).ToString();
|
||
}
|
||
|
||
config.Save(ConfigurationSaveMode.Modified);
|
||
ConfigurationManager.RefreshSection("appSettings");
|
||
|
||
_logger.Info("授权状态已写入配置: {State} | License state written to config: {State}", (int)state);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.Error(ex, "写入授权状态到配置失败 | Failed to write license state to config");
|
||
}
|
||
}
|
||
}
|
||
}
|