第一版
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
cmd/
|
||||||
|
*.pem
|
||||||
7
go.mod
Normal file
7
go.mod
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module gitee.com/LifetimeNine/singularity-rpc-client
|
||||||
|
|
||||||
|
go 1.24.3
|
||||||
|
|
||||||
|
require golang.org/x/net v0.43.0
|
||||||
|
|
||||||
|
require golang.org/x/text v0.28.0 // indirect
|
||||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||||
|
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||||
|
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||||
|
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||||
147
pkg/rpc/device.go
Normal file
147
pkg/rpc/device.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 设备详情
|
||||||
|
type DeviceDetail struct {
|
||||||
|
Type uint8 `json:"type"`
|
||||||
|
ConnectType uint8 `json:"connect_type"`
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
PId uint32 `json:"p_id"`
|
||||||
|
DataId uint32 `json:"data_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var device *Device
|
||||||
|
|
||||||
|
// 获取设备相关RPC类
|
||||||
|
func GetDevice() *Device {
|
||||||
|
if device == nil {
|
||||||
|
device = &Device{}
|
||||||
|
}
|
||||||
|
return device
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设备相关RPC
|
||||||
|
type Device struct{}
|
||||||
|
|
||||||
|
// 获取设备详情
|
||||||
|
func (d *Device) GetDetail(deviceId uint32) (*Result[DeviceDetail], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
"field_list": []string{"type", "secret", "connect_type", "p_id", "data_id"},
|
||||||
|
}
|
||||||
|
result := &Result[DeviceDetail]{}
|
||||||
|
if err := GetRequest().Send("device.get_detail", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置设备在线状态
|
||||||
|
func (d *Device) ResetOnlineStatus() (*Result[any], error) {
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.reset_online_status", map[string]any{}, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新设备在线状态
|
||||||
|
func (d *Device) UpdateOnlineStatus(deviceId uint32, online bool, updateTime time.Time) (*Result[any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
"online": online,
|
||||||
|
"time": updateTime.Format(time.DateTime),
|
||||||
|
}
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.update_online_status", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新从设备在线状态
|
||||||
|
func (d *Device) UpdateSlaveOnlineStatus(deviceId uint32, online bool, updateTime time.Time, parentId *uint32) (*Result[any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
"online": online,
|
||||||
|
"time": updateTime.Format(time.DateTime),
|
||||||
|
}
|
||||||
|
if parentId != nil {
|
||||||
|
body["parent_id"] = *parentId
|
||||||
|
}
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.update_salve_online_status", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新设备属性上报时间
|
||||||
|
func (d *Device) UpdateReportTime(deviceId uint32, reportTime *time.Time) (*Result[any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
}
|
||||||
|
if reportTime != nil {
|
||||||
|
body["time"] = reportTime.Format(time.DateTime)
|
||||||
|
}
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.update_report_time", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置设备属性
|
||||||
|
func (d *Device) SetAttribute(deviceId uint32, attributeSet map[string]any) (*Result[any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
"attribute": attributeSet,
|
||||||
|
}
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.set_attribute", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取设备属性
|
||||||
|
func (d *Device) GetAttribute(deviceId uint32) (*Result[map[string]any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
}
|
||||||
|
result := &Result[map[string]any]{}
|
||||||
|
if err := GetRequest().Send("device.get_attribute", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新设备版本信息
|
||||||
|
func (d *Device) UpdateVersion(deviceId uint32, versionNumber uint) (*Result[any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"device_id": deviceId,
|
||||||
|
"version_number": versionNumber,
|
||||||
|
}
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.update_version", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存升级结果
|
||||||
|
func (d *Device) SaveUpgradeResult(upgradeTaskId uint32, status uint8, finishTime time.Time) (*Result[any], error) {
|
||||||
|
body := map[string]any{
|
||||||
|
"upgrade_task_id": upgradeTaskId,
|
||||||
|
"status": status,
|
||||||
|
"finish_time": finishTime.Format(time.DateTime),
|
||||||
|
}
|
||||||
|
result := &Result[any]{}
|
||||||
|
if err := GetRequest().Send("device.save_upgrade_result", body, result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
102
pkg/rpc/request.go
Normal file
102
pkg/rpc/request.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/md5"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultRequest Request
|
||||||
|
|
||||||
|
// 请求类
|
||||||
|
type Request struct {
|
||||||
|
host string
|
||||||
|
port uint16
|
||||||
|
rootCertPath string
|
||||||
|
client *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
func (r *Request) Send(methodName string, body any, responseBody any) error {
|
||||||
|
if r.client == nil {
|
||||||
|
return fmt.Errorf("not initialized")
|
||||||
|
}
|
||||||
|
bodyByte, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("request body json marshal fail: %v", err)
|
||||||
|
}
|
||||||
|
request, err := http.NewRequest("POST", fmt.Sprintf("https://%s:%d/%s", r.host, r.port, methodName), bytes.NewBuffer(bodyByte))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
signByte := md5.Sum([]byte(fmt.Sprintf("%s\nsingularity\n%s", methodName, bodyByte)))
|
||||||
|
request.Header.Set("Content-Type", "application/json")
|
||||||
|
request.Header.Set("Authorization", fmt.Sprintf("Digest %s", hex.EncodeToString(signByte[:])))
|
||||||
|
|
||||||
|
response, err := r.client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
responseBodyByte, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(responseBodyByte, responseBody); err != nil {
|
||||||
|
return fmt.Errorf("response body json unmarshal fail: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化请求类
|
||||||
|
func InitiateRequest(host string, port uint16, rootCertPath string) error {
|
||||||
|
rootCert, err := os.ReadFile(rootCertPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cert file read fail")
|
||||||
|
}
|
||||||
|
defaultRequest.host = host
|
||||||
|
defaultRequest.port = port
|
||||||
|
defaultRequest.rootCertPath = rootCertPath
|
||||||
|
|
||||||
|
certPool := x509.NewCertPool()
|
||||||
|
certPool.AppendCertsFromPEM(rootCert)
|
||||||
|
|
||||||
|
transport := &http2.Transport{
|
||||||
|
AllowHTTP: true,
|
||||||
|
TLSClientConfig: &tls.Config{
|
||||||
|
RootCAs: certPool,
|
||||||
|
ServerName: host,
|
||||||
|
NextProtos: []string{"h2"},
|
||||||
|
},
|
||||||
|
StrictMaxConcurrentStreams: true,
|
||||||
|
IdleConnTimeout: time.Minute,
|
||||||
|
PingTimeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
defaultRequest.client = &http.Client{
|
||||||
|
Transport: transport,
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取请求类
|
||||||
|
func GetRequest() *Request {
|
||||||
|
return &defaultRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
defaultRequest = Request{}
|
||||||
|
}
|
||||||
43
pkg/rpc/type.go
Normal file
43
pkg/rpc/type.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
// 结果Code
|
||||||
|
type ResultCode uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
// 响应Code 正常
|
||||||
|
ResultCodeSuccess ResultCode = 0
|
||||||
|
// 响应Code 失败
|
||||||
|
ResultCodeError ResultCode = 10000
|
||||||
|
// 响应Code 参数异常
|
||||||
|
ResultCodeParamError ResultCode = 10001
|
||||||
|
// 响应Code 操作失败
|
||||||
|
ResultCodeActionFail ResultCode = 10002
|
||||||
|
// 响应Code 数据不存在
|
||||||
|
ResultCodeDataNotExist ResultCode = 10003
|
||||||
|
// 响应Code 签名错误
|
||||||
|
ResultCodeSignError ResultCode = 10105
|
||||||
|
|
||||||
|
// 服务通讯失败
|
||||||
|
ResultCodeServiceCommunicationFail ResultCode = 11000
|
||||||
|
// 数据解析失败
|
||||||
|
ResultCodeDataParseFail ResultCode = 11001
|
||||||
|
// 操作不存在
|
||||||
|
ResultCodeOperationNotExist ResultCode = 11002
|
||||||
|
// 设备不存在
|
||||||
|
ResultCodeDeviceNotExist ResultCode = 11003
|
||||||
|
// 设备信息不在线
|
||||||
|
ResultCodeDeviceOffline ResultCode = 11004
|
||||||
|
// 设备响应超时
|
||||||
|
ResultCodeDeviceResponseTimeout ResultCode = 11005
|
||||||
|
// 设备属性不可操作
|
||||||
|
ResultCodeDeviceAttributeCannotOperation ResultCode = 11006
|
||||||
|
// 设备属性不存在
|
||||||
|
ResultCodeDeviceAttributeNotExits ResultCode = 11007
|
||||||
|
)
|
||||||
|
|
||||||
|
// 响应结果
|
||||||
|
type Result[D any] struct {
|
||||||
|
Code ResultCode `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Data D `json:"data"`
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user