using System; using System.Net.Http; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Threading.Tasks; namespace DeviceSDK { public class DeviceClient : IDisposable { private readonly string _baseUrl; private readonly string _encryptKey; private readonly HttpClient _httpClient; private bool _disposed; public DeviceClient(string baseUrl, string encryptKey) { _baseUrl = baseUrl.TrimEnd('/'); _encryptKey = encryptKey; _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(30) }; } // 设备注册 public async Task RegisterDeviceAsync(DeviceRegisterRequest request) { try { var response = await PostAsync("/api/devices/register", request); return JsonSerializer.Deserialize(response); } catch (Exception ex) { throw new DeviceSDKException("设备注册失败", ex); } } // 设备验证 public async Task ValidateDeviceAsync(string uid) { try { var response = await GetAsync($"/api/devices/{uid}/validate"); var result = JsonSerializer.Deserialize(response); if (result.Code != 0) { throw new DeviceSDKException(result.Error); } var decrypted = DecryptResponse(result.Data); return JsonSerializer.Deserialize(decrypted); } catch (Exception ex) { throw new DeviceSDKException("设备验证失败", ex); } } // 更新启动次数 public async Task UpdateStartCountAsync(string uid) { try { var response = await PostAsync($"/api/devices/{uid}/start", null); return JsonSerializer.Deserialize(response); } catch (Exception ex) { throw new DeviceSDKException("更新启动次数失败", ex); } } // 绑定授权码 public async Task BindLicenseAsync(string uid, string licenseCode) { try { var request = new { license_code = licenseCode }; var response = await PostAsync($"/api/devices/{uid}/license", request); var result = JsonSerializer.Deserialize(response); if (result.Code != 0) { throw new DeviceSDKException(result.Error); } } catch (Exception ex) { throw new DeviceSDKException("绑定授权码失败", ex); } } private async Task GetAsync(string path) { var response = await _httpClient.GetAsync(_baseUrl + path); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } private async Task PostAsync(string path, object data) { var content = data == null ? null : new StringContent(JsonSerializer.Serialize(data), Encoding.UTF8, "application/json"); var response = await _httpClient.PostAsync(_baseUrl + path, content); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } private string DecryptResponse(string encrypted) { try { var cipherBytes = Convert.FromBase64String(encrypted); var keyBytes = Encoding.UTF8.GetBytes(_encryptKey); using var aes = Aes.Create(); aes.Key = keyBytes; var iv = new byte[16]; Array.Copy(cipherBytes, 0, iv, 0, 16); aes.IV = iv; using var decryptor = aes.CreateDecryptor(); var cipher = new byte[cipherBytes.Length - 16]; Array.Copy(cipherBytes, 16, cipher, 0, cipher.Length); var plainBytes = decryptor.TransformFinalBlock(cipher, 0, cipher.Length); return Encoding.UTF8.GetString(plainBytes); } catch (Exception ex) { throw new DeviceSDKException("解密响应失败", ex); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _httpClient?.Dispose(); } _disposed = true; } } } // 请求和响应模型 public class DeviceRegisterRequest { public string Uid { get; set; } public string DeviceModel { get; set; } public string LicenseCode { get; set; } } public class DeviceRegisterResponse { public int Code { get; set; } public string Message { get; set; } public DeviceRegisterData Data { get; set; } } public class DeviceRegisterData { public string Uid { get; set; } public string DeviceModel { get; set; } public string Status { get; set; } } public class DeviceValidateResponse { public string Status { get; set; } public string LicenseType { get; set; } public DateTime ExpireTime { get; set; } public int StartCount { get; set; } public int MaxUses { get; set; } public long Timestamp { get; set; } } public class StartCountResponse { public int Code { get; set; } public string Message { get; set; } public StartCountData Data { get; set; } } public class StartCountData { public int StartCount { get; set; } public string Status { get; set; } public DateTime LastActiveAt { get; set; } } internal class ApiResponse { public int Code { get; set; } public string Error { get; set; } public string Data { get; set; } } // 自定义异常 public class DeviceSDKException : Exception { public DeviceSDKException(string message) : base(message) { } public DeviceSDKException(string message, Exception innerException) : base(message, innerException) { } } }