up
This commit is contained in:
146
sdk/cpp/README.md
Normal file
146
sdk/cpp/README.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Device SDK for C++
|
||||
|
||||
## 依赖
|
||||
- libcurl
|
||||
- nlohmann/json
|
||||
- OpenSSL
|
||||
|
||||
### Windows
|
||||
1. vcpkg 安装依赖:
|
||||
```bash
|
||||
vcpkg install curl:x64-windows
|
||||
vcpkg install openssl:x64-windows
|
||||
vcpkg install nlohmann-json:x64-windows
|
||||
```
|
||||
### Linux
|
||||
1. Ubuntu/Debian:
|
||||
```bash
|
||||
sudo apt-get install libcurl4-openssl-dev libssl-dev nlohmann-json-dev
|
||||
```
|
||||
2. CentOS/RHEL:
|
||||
```bash
|
||||
sudo yum install libcurl-devel openssl-devel nlohmann-json-devel
|
||||
```
|
||||
|
||||
## 编译
|
||||
### Windows (Visual Studio)
|
||||
1. 添加包含目录:
|
||||
- $(vcpkg_root)/installed/x64-windows/include
|
||||
2. 添加库目录:
|
||||
- $(vcpkg_root)/installed/x64-windows/lib
|
||||
3. 添加依赖库:
|
||||
- libcurl
|
||||
- libssl
|
||||
- libcrypto
|
||||
|
||||
### Linux
|
||||
|
||||
```bash
|
||||
g++ -o example example.cpp device_sdk.cpp -lcurl -lssl -lcrypto -I/usr/include/nlohmann
|
||||
```
|
||||
|
||||
## 基本用法
|
||||
### 初始化
|
||||
|
||||
```cpp
|
||||
#include "device_sdk.h"
|
||||
DeviceClient client("http://localhost:8080", "your-32-byte-encrypt-key-here123456");
|
||||
```
|
||||
### 设备注册
|
||||
```cpp
|
||||
// 不带授权码注册
|
||||
DeviceInfo device;
|
||||
device.uid = "device-001";
|
||||
device.device_model = "test-model";
|
||||
std::string error;
|
||||
if (!client.registerDevice(device, error)) {
|
||||
std::cerr << "注册失败: " << error << std::endl;
|
||||
return;
|
||||
}
|
||||
// 带授权码注册
|
||||
DeviceInfo deviceWithLicense;
|
||||
deviceWithLicense.uid = "device-002";
|
||||
deviceWithLicense.device_model = "test-model";
|
||||
deviceWithLicense.license_code = "your-license-code";
|
||||
if (!client.registerDevice(deviceWithLicense, error)) {
|
||||
std::cerr << "注册失败: " << error << std::endl;
|
||||
return;
|
||||
}
|
||||
```
|
||||
### 设备验证
|
||||
```cpp
|
||||
ValidateResponse response;
|
||||
std::string error;
|
||||
if (!client.validateDevice("device-001", response, error)) {
|
||||
std::cerr << "验证失败: " << error << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << "设备状态: " << response.status << std::endl;
|
||||
std::cout << "授权类型: " << response.license_type << std::endl;
|
||||
std::cout << "过期时间: " << response.expire_time << std::endl;
|
||||
```
|
||||
|
||||
### 更新启动次数
|
||||
|
||||
```cpp
|
||||
int count;
|
||||
std::string error;
|
||||
if (!client.updateStartCount("device-001", count, error)) {
|
||||
std::cerr << "更新失败: " << error << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cout << "当前启动次数: " << count << std::endl;
|
||||
```
|
||||
### 绑定授权码
|
||||
```cpp
|
||||
std::string error;
|
||||
if (!client.bindLicense("device-001", "license-code-123", error)) {
|
||||
std::cerr << "绑定失败: " << error << std::endl;
|
||||
return;
|
||||
}
|
||||
```
|
||||
## 完整示例
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include "device_sdk.h"
|
||||
int main() {
|
||||
try {
|
||||
DeviceClient client("http://localhost:8080", "your-32-byte-encrypt-key-here123456");
|
||||
std::string error;
|
||||
// 注册设备
|
||||
DeviceInfo device;
|
||||
device.uid = "device-001";
|
||||
device.device_model = "test-model";
|
||||
if (!client.registerDevice(device, error)) {
|
||||
std::cerr << "注册失败: " << error << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "设备注册成功" << std::endl;
|
||||
// 绑定授权码
|
||||
if (!client.bindLicense("device-001", "license-code-123", error)) {
|
||||
std::cerr << "绑定失败: " << error << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "授权码绑定成功" << std::endl;
|
||||
// 验证设备
|
||||
ValidateResponse response;
|
||||
if (!client.validateDevice("device-001", response, error)) {
|
||||
std::cerr << "验证失败: " << error << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "设备状态: " << response.status << std::endl;
|
||||
std::cout << "授权类型: " << response.license_type << std::endl;
|
||||
// 更新启动次数
|
||||
int count;
|
||||
if (!client.updateStartCount("device-001", count, error)) {
|
||||
std::cerr << "更新失败: " << error << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "当前启动次数: " << count << std::endl;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "发生错误: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
100
sdk/cpp/device_sdk.cpp
Normal file
100
sdk/cpp/device_sdk.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "device_sdk.h"
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
|
||||
DeviceClient::DeviceClient(const std::string& base_url, const std::string& encrypt_key)
|
||||
: base_url_(base_url), encrypt_key_(encrypt_key) {
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl_ = curl_easy_init();
|
||||
}
|
||||
|
||||
DeviceClient::~DeviceClient() {
|
||||
if (curl_) {
|
||||
curl_easy_cleanup(curl_);
|
||||
}
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
bool DeviceClient::registerDevice(const DeviceInfo& device_info, std::string& error) {
|
||||
json request;
|
||||
request["uid"] = device_info.uid;
|
||||
request["device_model"] = device_info.device_model;
|
||||
if (!device_info.license_code.empty()) {
|
||||
request["license_code"] = device_info.license_code;
|
||||
}
|
||||
|
||||
std::string response;
|
||||
if (!post(base_url_ + "/api/devices/register", request.dump(), response, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto resp_json = json::parse(response);
|
||||
if (resp_json["code"] != 0) {
|
||||
error = resp_json["error"];
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceClient::validateDevice(const std::string& uid, ValidateResponse& response, std::string& error) {
|
||||
std::string encrypted_response;
|
||||
if (!get(base_url_ + "/api/devices/" + uid + "/validate", encrypted_response, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto resp_json = json::parse(encrypted_response);
|
||||
if (resp_json["code"] != 0) {
|
||||
error = resp_json["error"];
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string decrypted = decryptResponse(resp_json["data"]);
|
||||
auto data = json::parse(decrypted);
|
||||
|
||||
response.status = data["status"];
|
||||
response.license_type = data["license_type"];
|
||||
response.expire_time = data["expire_time"];
|
||||
response.start_count = data["start_count"];
|
||||
response.max_uses = data["max_uses"];
|
||||
response.timestamp = data["timestamp"];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceClient::updateStartCount(const std::string& uid, int& count, std::string& error) {
|
||||
std::string response;
|
||||
if (!post(base_url_ + "/api/devices/" + uid + "/start", "", response, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto resp_json = json::parse(response);
|
||||
if (resp_json["code"] != 0) {
|
||||
error = resp_json["error"];
|
||||
return false;
|
||||
}
|
||||
|
||||
count = resp_json["data"]["start_count"];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceClient::bindLicense(const std::string& uid, const std::string& license_code, std::string& error) {
|
||||
json request;
|
||||
request["license_code"] = license_code;
|
||||
|
||||
std::string response;
|
||||
if (!post(base_url_ + "/api/devices/" + uid + "/license", request.dump(), response, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto resp_json = json::parse(response);
|
||||
if (resp_json["code"] != 0) {
|
||||
error = resp_json["error"];
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ... HTTP 请求和加密相关的辅助函数实现 ...
|
61
sdk/cpp/device_sdk.h
Normal file
61
sdk/cpp/device_sdk.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef DEVICE_SDK_H
|
||||
#define DEVICE_SDK_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <winhttp.h>
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <ctime>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
struct DeviceInfo {
|
||||
std::string uid;
|
||||
std::string device_model;
|
||||
std::string license_code; // 可选
|
||||
};
|
||||
|
||||
struct ValidateResponse {
|
||||
std::string status;
|
||||
std::string license_type;
|
||||
std::string expire_time;
|
||||
int start_count;
|
||||
int max_uses;
|
||||
int64_t timestamp;
|
||||
};
|
||||
|
||||
class DeviceClient {
|
||||
public:
|
||||
DeviceClient(const std::string& base_url, const std::string& encrypt_key);
|
||||
~DeviceClient();
|
||||
|
||||
// 设备注册
|
||||
bool registerDevice(const DeviceInfo& device_info, std::string& error);
|
||||
|
||||
// 设备验证
|
||||
bool validateDevice(const std::string& uid, ValidateResponse& response, std::string& error);
|
||||
|
||||
// 更新启动次数
|
||||
bool updateStartCount(const std::string& uid, int& count, std::string& error);
|
||||
|
||||
// 绑定授权码
|
||||
bool bindLicense(const std::string& uid, const std::string& license_code, std::string& error);
|
||||
|
||||
private:
|
||||
std::string base_url_;
|
||||
std::string encrypt_key_;
|
||||
CURL* curl_;
|
||||
|
||||
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* userp);
|
||||
bool post(const std::string& url, const std::string& data, std::string& response, std::string& error);
|
||||
bool get(const std::string& url, std::string& response, std::string& error);
|
||||
std::string decryptResponse(const std::string& encrypted);
|
||||
};
|
||||
|
||||
#endif // DEVICE_SDK_H
|
220
sdk/csharp/DeviceSDK.cs
Normal file
220
sdk/csharp/DeviceSDK.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
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<DeviceRegisterResponse> RegisterDeviceAsync(DeviceRegisterRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await PostAsync("/api/devices/register", request);
|
||||
return JsonSerializer.Deserialize<DeviceRegisterResponse>(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DeviceSDKException("设备注册失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// 设备验证
|
||||
public async Task<DeviceValidateResponse> ValidateDeviceAsync(string uid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await GetAsync($"/api/devices/{uid}/validate");
|
||||
var result = JsonSerializer.Deserialize<ApiResponse>(response);
|
||||
|
||||
if (result.Code != 0)
|
||||
{
|
||||
throw new DeviceSDKException(result.Error);
|
||||
}
|
||||
|
||||
var decrypted = DecryptResponse(result.Data);
|
||||
return JsonSerializer.Deserialize<DeviceValidateResponse>(decrypted);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DeviceSDKException("设备验证失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新启动次数
|
||||
public async Task<StartCountResponse> UpdateStartCountAsync(string uid)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await PostAsync($"/api/devices/{uid}/start", null);
|
||||
return JsonSerializer.Deserialize<StartCountResponse>(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<ApiResponse>(response);
|
||||
|
||||
if (result.Code != 0)
|
||||
{
|
||||
throw new DeviceSDKException(result.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new DeviceSDKException("绑定授权码失败", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<string> GetAsync(string path)
|
||||
{
|
||||
var response = await _httpClient.GetAsync(_baseUrl + path);
|
||||
response.EnsureSuccessStatusCode();
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
|
||||
private async Task<string> 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) { }
|
||||
}
|
||||
}
|
90
sdk/csharp/README.md
Normal file
90
sdk/csharp/README.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Device SDK for C#
|
||||
|
||||
## 安装
|
||||
将 `DeviceSDK.cs` 添加到你的项目中。
|
||||
|
||||
## 初始化
|
||||
|
||||
```csharp
|
||||
var client = new DeviceClient(
|
||||
baseUrl: "http://your-server:8080", // 服务器地址
|
||||
encryptKey: "your-32-byte-encrypt-key-here123456" // 32字节加密密钥
|
||||
);
|
||||
```
|
||||
|
||||
## API 使用说明
|
||||
|
||||
### 1. 设备注册
|
||||
|
||||
```csharp
|
||||
// 基本注册(无授权码)
|
||||
var response = await client.RegisterDeviceAsync(new DeviceRegisterRequest {
|
||||
Uid = "device-001",
|
||||
DeviceModel = "test-model"
|
||||
});```
|
||||
|
||||
|
||||
|
||||
```csharp
|
||||
// 带授权码的注册
|
||||
var response = await client.RegisterDeviceAsync(new DeviceRegisterRequest {
|
||||
Uid = "device-001",
|
||||
DeviceModel = "test-model",
|
||||
License = "your-license-code-here"
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 设备验证
|
||||
|
||||
```csharp
|
||||
var validateResponse = await client.ValidateDeviceAsync("device-001");
|
||||
Console.WriteLine($"设备状态: {validateResponse.Status}");
|
||||
Console.WriteLine($"授权类型: {validateResponse.LicenseType}");
|
||||
Console.WriteLine($"过期时间: {validateResponse.ExpireTime}");
|
||||
```
|
||||
|
||||
### 3. 更新启动次数
|
||||
|
||||
```csharp
|
||||
var startCountResponse = await client.UpdateStartCountAsync("device-001");
|
||||
Console.WriteLine($"当前启动次数: {startCountResponse.Data.StartCount}");
|
||||
```
|
||||
|
||||
### 4. 绑定授权码
|
||||
|
||||
```csharp
|
||||
var bindLicenseResponse = await client.BindLicenseAsync("device-001", "your-license-code-here");
|
||||
Console.WriteLine($"绑定结果: {bindLicenseResponse.Data.Success}");
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
SDK 使用 `DeviceSDKException` 统一处理错误:
|
||||
|
||||
```csharp
|
||||
try {
|
||||
// 调用 API 的代码
|
||||
} catch (DeviceSDKException e) {
|
||||
Console.WriteLine($"错误码: {e.ErrorCode}, 错误信息: {e.Message}");
|
||||
}
|
||||
```
|
||||
|
||||
## 响应数据结构
|
||||
|
||||
```csharp
|
||||
// 设备验证响应
|
||||
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 class StartCountResponse
|
||||
{
|
||||
public int Code { get; set; }
|
||||
public string Message { get; set; }
|
||||
public StartCountData Data { get; set; }
|
||||
}
|
||||
```
|
1
sdk/csharp/docs/README.md
Normal file
1
sdk/csharp/docs/README.md
Normal file
@@ -0,0 +1 @@
|
||||
|
104
sdk/go/README.md
Normal file
104
sdk/go/README.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Device SDK for Go
|
||||
|
||||
## 安装
|
||||
`go import "license-server/sdk/go/devicesdk"`
|
||||
|
||||
## 基本用法
|
||||
|
||||
### 初始化客户端
|
||||
```go
|
||||
client := devicesdk.NewDeviceClient(
|
||||
"http://localhost:8080",
|
||||
"your-32-byte-encrypt-key-here123456",
|
||||
)
|
||||
```
|
||||
### 设备注册
|
||||
```go
|
||||
// 不带授权码注册
|
||||
err := client.RegisterDevice(&devicesdk.DeviceInfo{
|
||||
UID: "device-001",
|
||||
DeviceModel: "test-model",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("设备注册失败: %v", err)
|
||||
}
|
||||
// 带授权码注册
|
||||
err = client.RegisterDevice(&devicesdk.DeviceInfo{
|
||||
UID: "device-002",
|
||||
DeviceModel: "test-model",
|
||||
LicenseCode: "your-license-code", // 可选
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("设备注册失败: %v", err)
|
||||
}
|
||||
```
|
||||
### 设备验证
|
||||
```go
|
||||
validateResp, err := client.ValidateDevice("device-001")
|
||||
if err != nil {
|
||||
log.Fatalf("设备验证失败: %v", err)
|
||||
}
|
||||
fmt.Printf("设备状态: %s\n", validateResp.Status)
|
||||
fmt.Printf("授权类型: %s\n", validateResp.LicenseType)
|
||||
fmt.Printf("过期时间: %s\n", validateResp.ExpireTime)
|
||||
```
|
||||
### 更新启动次数
|
||||
```go
|
||||
count, err := client.UpdateStartCount("device-001")
|
||||
if err != nil {
|
||||
log.Fatalf("更新启动次数失败: %v", err)
|
||||
}
|
||||
fmt.Printf("当前启动次数: %d\n", count)
|
||||
```
|
||||
|
||||
### 绑定授权码
|
||||
```go
|
||||
err := client.BindLicense("device-001", "your-license-code")
|
||||
if err != nil {
|
||||
log.Fatalf("绑定授权码失败: %v", err)
|
||||
}
|
||||
```
|
||||
## 完整示例
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"license-server/sdk/go/devicesdk"
|
||||
)
|
||||
func main() {
|
||||
client := devicesdk.NewDeviceClient(
|
||||
"http://localhost:8080",
|
||||
"your-32-byte-encrypt-key-here123456",
|
||||
)
|
||||
// 注册设备
|
||||
err := client.RegisterDevice(&devicesdk.DeviceInfo{
|
||||
UID: "device-001",
|
||||
DeviceModel: "test-model",
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("设备注册失败: %v", err)
|
||||
}
|
||||
fmt.Println("设备注册成功")
|
||||
// 绑定授权码
|
||||
err = client.BindLicense("device-001", "license-code-123")
|
||||
if err != nil {
|
||||
log.Fatalf("绑定授权码失败: %v", err)
|
||||
}
|
||||
fmt.Println("授权码绑定成功")
|
||||
// 验证设备
|
||||
validateResp, err := client.ValidateDevice("device-001")
|
||||
if err != nil {
|
||||
log.Fatalf("设备验证失败: %v", err)
|
||||
}
|
||||
fmt.Printf("设备状态: %s\n", validateResp.Status)
|
||||
fmt.Printf("授权类型: %s\n", validateResp.LicenseType)
|
||||
fmt.Printf("过期时间: %s\n", validateResp.ExpireTime)
|
||||
// 更新启动次数
|
||||
count, err := client.UpdateStartCount("device-001")
|
||||
if err != nil {
|
||||
log.Fatalf("更新启动次数失败: %v", err)
|
||||
}
|
||||
fmt.Printf("当前启动次数: %d\n", count)
|
||||
}
|
||||
```
|
191
sdk/go/device_sdk.go
Normal file
191
sdk/go/device_sdk.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package devicesdk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DeviceClient struct {
|
||||
baseURL string
|
||||
encryptKey string
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
type DeviceInfo struct {
|
||||
UID string `json:"uid"`
|
||||
DeviceModel string `json:"device_model"`
|
||||
LicenseCode string `json:"license_code,omitempty"`
|
||||
}
|
||||
|
||||
type ValidateResponse struct {
|
||||
Status string `json:"status"`
|
||||
LicenseType string `json:"license_type"`
|
||||
ExpireTime time.Time `json:"expire_time"`
|
||||
StartCount int `json:"start_count"`
|
||||
MaxUses int `json:"max_uses"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
type ApiResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Error string `json:"error"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func NewDeviceClient(baseURL, encryptKey string) *DeviceClient {
|
||||
return &DeviceClient{
|
||||
baseURL: baseURL,
|
||||
encryptKey: encryptKey,
|
||||
client: &http.Client{Timeout: time.Second * 30},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DeviceClient) RegisterDevice(info *DeviceInfo) error {
|
||||
data, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return fmt.Errorf("序列化请求数据失败: %v", err)
|
||||
}
|
||||
|
||||
resp, err := c.post("/api/devices/register", data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Code != 0 {
|
||||
return fmt.Errorf(resp.Error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *DeviceClient) ValidateDevice(uid string) (*ValidateResponse, error) {
|
||||
resp, err := c.get(fmt.Sprintf("/api/devices/%s/validate", uid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.Code != 0 {
|
||||
return nil, fmt.Errorf(resp.Error)
|
||||
}
|
||||
|
||||
decrypted, err := c.decryptResponse(resp.Data.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var validateResp ValidateResponse
|
||||
if err := json.Unmarshal([]byte(decrypted), &validateResp); err != nil {
|
||||
return nil, fmt.Errorf("解析响应数据失败: %v", err)
|
||||
}
|
||||
|
||||
return &validateResp, nil
|
||||
}
|
||||
|
||||
func (c *DeviceClient) UpdateStartCount(uid string) (int, error) {
|
||||
resp, err := c.post(fmt.Sprintf("/api/devices/%s/start", uid), nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if resp.Code != 0 {
|
||||
return 0, fmt.Errorf(resp.Error)
|
||||
}
|
||||
|
||||
data := resp.Data.(map[string]interface{})
|
||||
return int(data["start_count"].(float64)), nil
|
||||
}
|
||||
|
||||
func (c *DeviceClient) BindLicense(uid, licenseCode string) error {
|
||||
data, err := json.Marshal(map[string]string{
|
||||
"license_code": licenseCode,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("序列化请求数据失败: %v", err)
|
||||
}
|
||||
|
||||
resp, err := c.post(fmt.Sprintf("/api/devices/%s/license", uid), data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Code != 0 {
|
||||
return fmt.Errorf(resp.Error)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HTTP 请求辅助方法
|
||||
func (c *DeviceClient) get(path string) (*ApiResponse, error) {
|
||||
resp, err := c.client.Get(c.baseURL + path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("HTTP请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return c.parseResponse(resp)
|
||||
}
|
||||
|
||||
func (c *DeviceClient) post(path string, data []byte) (*ApiResponse, error) {
|
||||
var resp *http.Response
|
||||
var err error
|
||||
|
||||
if data == nil {
|
||||
resp, err = c.client.Post(c.baseURL+path, "application/json", nil)
|
||||
} else {
|
||||
resp, err = c.client.Post(c.baseURL+path, "application/json", bytes.NewBuffer(data))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("HTTP请求失败: %v", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return c.parseResponse(resp)
|
||||
}
|
||||
|
||||
func (c *DeviceClient) parseResponse(resp *http.Response) (*ApiResponse, error) {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应数据失败: %v", err)
|
||||
}
|
||||
|
||||
var apiResp ApiResponse
|
||||
if err := json.Unmarshal(body, &apiResp); err != nil {
|
||||
return nil, fmt.Errorf("解析响应数据失败: %v", err)
|
||||
}
|
||||
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
func (c *DeviceClient) decryptResponse(encrypted string) (string, error) {
|
||||
ciphertext, err := base64.StdEncoding.DecodeString(encrypted)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("base64解码失败: %v", err)
|
||||
}
|
||||
|
||||
block, err := aes.NewCipher([]byte(c.encryptKey))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("创建AES cipher失败: %v", err)
|
||||
}
|
||||
|
||||
if len(ciphertext) < aes.BlockSize {
|
||||
return "", fmt.Errorf("密文长度不足")
|
||||
}
|
||||
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
ciphertext = ciphertext[aes.BlockSize:]
|
||||
|
||||
stream := cipher.NewCFBDecrypter(block, iv)
|
||||
stream.XORKeyStream(ciphertext, ciphertext)
|
||||
|
||||
return string(ciphertext), nil
|
||||
}
|
Reference in New Issue
Block a user