up
This commit is contained in:
@@ -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)
|
||||
}
|
||||
```
|
||||
@@ -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