KyrosDev's picture
重新實施機器名稱綁定功能
b37d8d7
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace KSTools.Licensing
{
/// <summary>
/// KSTools 授權 API 客戶端
/// 負責與授權管理系統的 API 通信
/// </summary>
public class ApiClient
{
private static readonly string DEFAULT_API_BASE = "https://your-space.hf.space/api";
private static readonly HttpClient httpClient = new HttpClient() { Timeout = TimeSpan.FromSeconds(30) };
private readonly string _apiBase;
/// <summary>
/// 初始化 API 客戶端
/// </summary>
/// <param name="apiBase">API 基礎 URL,如果為空則使用預設值</param>
public ApiClient(string apiBase = null)
{
_apiBase = string.IsNullOrEmpty(apiBase) ? DEFAULT_API_BASE : apiBase.TrimEnd('/');
// 設定 HTTP 客戶端標頭
httpClient.DefaultRequestHeaders.Clear();
httpClient.DefaultRequestHeaders.Add("User-Agent", "KSTools-Revit-Plugin/1.0");
}
/// <summary>
/// 啟用授權
/// </summary>
/// <param name="licenseCode">授權碼</param>
/// <param name="hardwareId">硬體指紋ID,如果為空則自動生成</param>
/// <returns>啟用結果</returns>
public async Task<ActivationResult> ActivateLicenseAsync(string licenseCode, string hardwareId = null)
{
try
{
if (string.IsNullOrEmpty(licenseCode))
{
return new ActivationResult
{
Success = false,
Message = "授權碼不能為空"
};
}
// 如果沒有提供硬體ID,自動生成
if (string.IsNullOrEmpty(hardwareId))
{
hardwareId = HardwareFingerprint.GetHardwareId();
}
var request = new
{
license_code = licenseCode,
hardware_id = hardwareId,
machine_name = Environment.MachineName
};
var json = JsonSerializer.Serialize(request, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync($"{_apiBase}/license/activate", content);
var resultJson = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var apiResponse = JsonSerializer.Deserialize<ApiActivationResponse>(resultJson, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
return new ActivationResult
{
Success = apiResponse.Success,
Message = apiResponse.Message,
ExpiresAt = apiResponse.ExpiresAt,
UserName = apiResponse.UserName,
HardwareId = apiResponse.HardwareId
};
}
else
{
return new ActivationResult
{
Success = false,
Message = $"HTTP 錯誤 {response.StatusCode}: {resultJson}"
};
}
}
catch (HttpRequestException ex)
{
return new ActivationResult
{
Success = false,
Message = $"網路連接錯誤: {ex.Message}"
};
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
return new ActivationResult
{
Success = false,
Message = "請求超時,請檢查網路連接"
};
}
catch (Exception ex)
{
return new ActivationResult
{
Success = false,
Message = $"未知錯誤: {ex.Message}"
};
}
}
/// <summary>
/// 驗證授權
/// </summary>
/// <param name="licenseCode">授權碼</param>
/// <param name="hardwareId">硬體指紋ID,如果為空則自動生成</param>
/// <returns>驗證結果</returns>
public async Task<ValidationResult> ValidateLicenseAsync(string licenseCode, string hardwareId = null)
{
try
{
if (string.IsNullOrEmpty(licenseCode))
{
return new ValidationResult
{
Valid = false,
Message = "授權碼不能為空"
};
}
// 如果沒有提供硬體ID,自動生成
if (string.IsNullOrEmpty(hardwareId))
{
hardwareId = HardwareFingerprint.GetHardwareId();
}
var request = new
{
license_code = licenseCode,
hardware_id = hardwareId,
machine_name = Environment.MachineName
};
var json = JsonSerializer.Serialize(request, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync($"{_apiBase}/license/validate", content);
var resultJson = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var apiResponse = JsonSerializer.Deserialize<ApiValidationResponse>(resultJson, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
return new ValidationResult
{
Valid = apiResponse.Valid,
Message = apiResponse.Message,
ExpiresAt = apiResponse.ExpiresAt,
UserName = apiResponse.UserName,
HardwareId = apiResponse.HardwareId
};
}
else
{
return new ValidationResult
{
Valid = false,
Message = $"HTTP 錯誤 {response.StatusCode}: {resultJson}"
};
}
}
catch (HttpRequestException ex)
{
return new ValidationResult
{
Valid = false,
Message = $"網路連接錯誤: {ex.Message}"
};
}
catch (TaskCanceledException ex) when (ex.InnerException is TimeoutException)
{
return new ValidationResult
{
Valid = false,
Message = "請求超時,請檢查網路連接"
};
}
catch (Exception ex)
{
return new ValidationResult
{
Valid = false,
Message = $"未知錯誤: {ex.Message}"
};
}
}
/// <summary>
/// 測試 API 連接
/// </summary>
/// <returns>是否連接成功</returns>
public async Task<bool> TestConnectionAsync()
{
try
{
var response = await httpClient.GetAsync($"{_apiBase.Replace("/api", "")}/health");
return response.IsSuccessStatusCode;
}
catch
{
return false;
}
}
}
#region API 回應模型
/// <summary>
/// API 啟用回應模型
/// </summary>
internal class ApiActivationResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public DateTime? ExpiresAt { get; set; }
public string UserName { get; set; }
public string HardwareId { get; set; }
}
/// <summary>
/// API 驗證回應模型
/// </summary>
internal class ApiValidationResponse
{
public bool Valid { get; set; }
public string Message { get; set; }
public DateTime? ExpiresAt { get; set; }
public string UserName { get; set; }
public string HardwareId { get; set; }
}
#endregion
#region 公開結果模型
/// <summary>
/// 授權啟用結果
/// </summary>
public class ActivationResult
{
/// <summary>
/// 啟用是否成功
/// </summary>
public bool Success { get; set; }
/// <summary>
/// 狀態訊息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 授權到期時間
/// </summary>
public DateTime? ExpiresAt { get; set; }
/// <summary>
/// 授權用戶名稱
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 硬體指紋ID
/// </summary>
public string HardwareId { get; set; }
}
/// <summary>
/// 授權驗證結果
/// </summary>
public class ValidationResult
{
/// <summary>
/// 授權是否有效
/// </summary>
public bool Valid { get; set; }
/// <summary>
/// 狀態訊息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 授權到期時間
/// </summary>
public DateTime? ExpiresAt { get; set; }
/// <summary>
/// 授權用戶名稱
/// </summary>
public string UserName { get; set; }
/// <summary>
/// 硬體指紋ID
/// </summary>
public string HardwareId { get; set; }
}
#endregion
}