| | using System; |
| | using System.Net.Http; |
| | using System.Text; |
| | using System.Text.Json; |
| | using System.Threading.Tasks; |
| |
|
| | namespace KSTools.Licensing |
| | { |
| | |
| | |
| | |
| | |
| | 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; |
| | |
| | |
| | |
| | |
| | |
| | public ApiClient(string apiBase = null) |
| | { |
| | _apiBase = string.IsNullOrEmpty(apiBase) ? DEFAULT_API_BASE : apiBase.TrimEnd('/'); |
| | |
| | |
| | httpClient.DefaultRequestHeaders.Clear(); |
| | httpClient.DefaultRequestHeaders.Add("User-Agent", "KSTools-Revit-Plugin/1.0"); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public async Task<ActivationResult> ActivateLicenseAsync(string licenseCode, string hardwareId = null) |
| | { |
| | try |
| | { |
| | if (string.IsNullOrEmpty(licenseCode)) |
| | { |
| | return new ActivationResult |
| | { |
| | Success = false, |
| | Message = "授權碼不能為空" |
| | }; |
| | } |
| | |
| | |
| | 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}" |
| | }; |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public async Task<ValidationResult> ValidateLicenseAsync(string licenseCode, string hardwareId = null) |
| | { |
| | try |
| | { |
| | if (string.IsNullOrEmpty(licenseCode)) |
| | { |
| | return new ValidationResult |
| | { |
| | Valid = false, |
| | Message = "授權碼不能為空" |
| | }; |
| | } |
| | |
| | |
| | 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}" |
| | }; |
| | } |
| | } |
| | |
| | |
| | |
| | |
| | |
| | public async Task<bool> TestConnectionAsync() |
| | { |
| | try |
| | { |
| | var response = await httpClient.GetAsync($"{_apiBase.Replace("/api", "")}/health"); |
| | return response.IsSuccessStatusCode; |
| | } |
| | catch |
| | { |
| | return false; |
| | } |
| | } |
| | } |
| | |
| | #region API 回應模型 |
| | |
| | |
| | |
| | |
| | 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; } |
| | } |
| | |
| | |
| | |
| | |
| | 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 公開結果模型 |
| | |
| | |
| | |
| | |
| | public class ActivationResult |
| | { |
| | |
| | |
| | |
| | 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; } |
| | } |
| | |
| | |
| | |
| | |
| | public class ValidationResult |
| | { |
| | |
| | |
| | |
| | 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 |
| | } |