From d5978b95f249dbacf8d37f2fc52e32335cc0b4f6 Mon Sep 17 00:00:00 2001 From: "suguo.yao" Date: Tue, 21 Nov 2023 09:35:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BA=A4=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cloud/base-cloud.go | 42 ------ cloud/oauth-cloud.go | 78 ----------- cloud/readme.md | 1 - {cloud => iot}/device-cloud.go | 32 ++--- {cloud => iot}/group-cloud.go | 12 +- iot/hikvision-iot.go | 129 ++++++++++++++++++ {cloud => iot}/hikvision.http | 11 +- iot/model/group-model.go | 6 + .../model/hikvision-model.go | 2 +- {cloud => iot}/oauth_test.go | 0 iot/readme.md | 1 + 11 files changed, 164 insertions(+), 150 deletions(-) delete mode 100644 cloud/base-cloud.go delete mode 100644 cloud/oauth-cloud.go delete mode 100644 cloud/readme.md rename {cloud => iot}/device-cloud.go (87%) rename {cloud => iot}/group-cloud.go (87%) create mode 100644 iot/hikvision-iot.go rename {cloud => iot}/hikvision.http (78%) create mode 100644 iot/model/group-model.go rename model/base-model.go => iot/model/hikvision-model.go (76%) rename {cloud => iot}/oauth_test.go (100%) create mode 100644 iot/readme.md diff --git a/cloud/base-cloud.go b/cloud/base-cloud.go deleted file mode 100644 index ee2050c..0000000 --- a/cloud/base-cloud.go +++ /dev/null @@ -1,42 +0,0 @@ -package cloud - -import ( - "encoding/json" - "fmt" - "io" - "net/http" - "strings" -) - -// 基础云眸http请求 -func BaseCloudHttpRequest(accesstoken *string, method string, url string, body interface{}) ([]byte, error) { - b, err := json.Marshal(body) - if err != nil { - return nil, err - } - reqbody := strings.NewReader(string(b)) - req, err := http.NewRequest(method, url, reqbody) - if err != nil { - return nil, err - } - - req.Header.Add("authorization", fmt.Sprintf(" bearer %s", *accesstoken)) - - if strings.ToLower(method) == "post" { - req.Header.Add("Content-Type", "application/json") - } - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - defer resp.Body.Close() - respBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - - return respBody, nil -} diff --git a/cloud/oauth-cloud.go b/cloud/oauth-cloud.go deleted file mode 100644 index 16588d4..0000000 --- a/cloud/oauth-cloud.go +++ /dev/null @@ -1,78 +0,0 @@ -package cloud - -import ( - "crypto/tls" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/url" - "strings" - "time" -) - -const ( - BASEURL = "https://api2.hik-cloud.com/oauth" -) - -type OauthRequest struct { - ClientID string `json:"client_id"` - ClientSecret string `json:"client_secret"` - GrantType string `json:"grant_type"` - Scope string `json:"scope"` -} - -type OauthResponse struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - ExpiresIn int `json:"expires_in"` - Scope string `json:"scope"` -} - -// 客户端认证获取access_token -func HikvisionOauth(body *OauthRequest) (*OauthResponse, error) { - - params := url.Values{} - params.Add("client_id", body.ClientID) - params.Add("client_secret", body.ClientSecret) - params.Add("grant_type", body.GrantType) - params.Add("scope", body.Scope) - - req, err := http.NewRequest("POST", fmt.Sprintf(`%s/token`, BASEURL), strings.NewReader(string(params.Encode()))) - if err != nil { - return nil, err - } - - req.Header.Add("Accept", "*/*") - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - - tr := &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - } - - client := &http.Client{Transport: tr, Timeout: 10 * time.Second} - resp, err := client.Do(req) - if err != nil { - return nil, err - } - - if resp.StatusCode != 200 { - errmsg := fmt.Sprintf("http status code: %d", resp.StatusCode) - return nil, errors.New(errmsg) - } - - defer resp.Body.Close() - respBody, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - var result *OauthResponse - if err := json.Unmarshal(respBody, &result); err != nil { - return nil, err - } - - return result, nil -} diff --git a/cloud/readme.md b/cloud/readme.md deleted file mode 100644 index cea7d10..0000000 --- a/cloud/readme.md +++ /dev/null @@ -1 +0,0 @@ -海康云眸平台 \ No newline at end of file diff --git a/cloud/device-cloud.go b/iot/device-cloud.go similarity index 87% rename from cloud/device-cloud.go rename to iot/device-cloud.go index bfe3d40..3cc9f94 100644 --- a/cloud/device-cloud.go +++ b/iot/device-cloud.go @@ -57,7 +57,7 @@ type DeviceData struct { // // 注册设备时首先会将设备添加到平台,然后异步同步设备通道。如果设备添加成功而同步设备通道失败,则可以先获取设备列表信息,再手动调用通道同步接口同步设备下的通道。\ func DeivceRegister(access_token *string, req *DeviceRegister) (*DeviceRegisterRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", ACCESS_REGISTER, req) + resp, err := hikvisionRequest(access_token, "POST", ACCESS_REGISTER, req) if err != nil { return nil, err } @@ -74,7 +74,7 @@ func DeivceRegister(access_token *string, req *DeviceRegister) (*DeviceRegisterR // 从某一分组内删除设备 func DeivceDelete(access_token *string, deviceSerial string) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", fmt.Sprintf("%s?deviceSerial=%s", ACCESS_DELETE, deviceSerial), nil) + resp, err := hikvisionRequest(access_token, "POST", fmt.Sprintf("%s?deviceSerial=%s", ACCESS_DELETE, deviceSerial), nil) if err != nil { return nil, err } @@ -96,7 +96,7 @@ type DeivceUpdateReq struct { // 该接口用于修改设备名称 func DeivceUpdate(access_token *string, req *DeivceUpdateReq) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", ACCESS_UPDATE, req) + resp, err := hikvisionRequest(access_token, "POST", ACCESS_UPDATE, req) if err != nil { return nil, err } @@ -113,7 +113,7 @@ func DeivceUpdate(access_token *string, req *DeivceUpdateReq) (*model.BaseOperat // 该接口用于根据设备序列号获取单个设备详细信息 func DeivceDetail(access_token *string, deviceSerial string) (*DeviceData, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", ACCESS_DETAIL, deviceSerial), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", ACCESS_DETAIL, deviceSerial), nil) if err != nil { return nil, err } @@ -150,7 +150,7 @@ type DeivceListData struct { // 该接口用于查询某组下设备列表信息 func DeivceList(access_token *string, req *DeivceListReq) (*DeivceListData, error) { url := fmt.Sprintf("%s?groupNo=%s&pageNo=%d&pageSize=%d", ACCESS_LIST, req.GroupNo, req.pageNo, req.pageSize) - resp, err := BaseCloudHttpRequest(access_token, "GET", url, nil) + resp, err := hikvisionRequest(access_token, "GET", url, nil) if err != nil { return nil, err } @@ -178,7 +178,7 @@ type DeivceNumData struct { // 该接口用于获取用户接入的设备总数 func DeivceNum(access_token *string) (*int, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", ACCESS_ACCOUNT, nil) + resp, err := hikvisionRequest(access_token, "GET", ACCESS_ACCOUNT, nil) if err != nil { return nil, err } @@ -215,7 +215,7 @@ type DeivceStatusData struct { // 该接口用于查询设备的状态信息,目前仅支持萤石设备 /*测试未通过*/ func DeivceStatus(access_token *string, deviceserial string) (*DeivceStatusData, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", ACCESS_STATUS, deviceserial), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", ACCESS_STATUS, deviceserial), nil) if err != nil { return nil, err } @@ -238,7 +238,7 @@ func DeivceReboot(access_token *string, deviceserial string) (*model.BaseOperati DeviceSerial: deviceserial, } - resp, err := BaseCloudHttpRequest(access_token, "POST", ACCESS_REBOOT, params) + resp, err := hikvisionRequest(access_token, "POST", ACCESS_REBOOT, params) if err != nil { return nil, err } @@ -266,7 +266,7 @@ func DeivceReboot(access_token *string, deviceserial string) (*model.BaseOperati // 下线确认 func DeivceOffline(access_token *string, deviceserial string) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("https://api2.hik-cloud.com/v1/carrier/wing/endpoint/confirm/right/offlineconfirm?deviceSerial=%s", deviceserial), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("https://api2.hik-cloud.com/v1/carrier/wing/endpoint/confirm/right/offlineconfirm?deviceSerial=%s", deviceserial), nil) if err != nil { return nil, err } @@ -284,7 +284,7 @@ func DeivceOffline(access_token *string, deviceserial string) (*model.BaseOperat // 上线线确认 func DeivceOnline(access_token *string, deviceserial string) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("https://api2.hik-cloud.com/v1/carrier/wing/endpoint/confirm/right/onlineconfirm?deviceSerial=%s", deviceserial), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("https://api2.hik-cloud.com/v1/carrier/wing/endpoint/confirm/right/onlineconfirm?deviceSerial=%s", deviceserial), nil) if err != nil { return nil, err } @@ -311,7 +311,7 @@ type DeviceGetTimeModeData struct { // 该接口用于获取设备当前校时配置 func DeviceGetTimeMode(access_token *string, deviceserial string) (*DeviceGetTimeModeData, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", TIME_BASE, deviceserial), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", TIME_BASE, deviceserial), nil) if err != nil { return nil, err } @@ -333,7 +333,7 @@ type DeviceSetTimeModeReq struct { // 该接口用于配置设备校时模式 func DeviceSetTimeMode(access_token *string, req *DeviceSetTimeModeReq) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", TIME_BASE, req) + resp, err := hikvisionRequest(access_token, "POST", TIME_BASE, req) if err != nil { return nil, err } @@ -350,7 +350,7 @@ func DeviceSetTimeMode(access_token *string, req *DeviceSetTimeModeReq) (*model. // 该接口用于获取设备当前NTP服务器配置 func DeviceGetNTPCfg(access_token *string, deviceserial string) (*DeviceSetNTPCfgServer, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", TIME_NTPCFG, deviceserial), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s", TIME_NTPCFG, deviceserial), nil) if err != nil { return nil, err } @@ -381,7 +381,7 @@ type DeviceSetNTPCfgServer struct { // 该接口用于配置设备NTP服务器参数 func DeviceSetNTPCfg(access_token *string, req *DeviceSetNTPCfgReq) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", TIME_NTPCFG, req) + resp, err := hikvisionRequest(access_token, "POST", TIME_NTPCFG, req) if err != nil { return nil, err } @@ -404,7 +404,7 @@ type DeviceGetNTPServerRes struct { // 该接口用于获取设备指定NTP服务器配置 func DeviceGetNTPServerCfg(access_token *string, deviceserial string, ntpserverid int) (*DeviceSetNTPCfgServer, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s&ntpServerId=%d", TIM_NTPSERVER_CFG, deviceserial, ntpserverid), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?deviceSerial=%s&ntpServerId=%d", TIM_NTPSERVER_CFG, deviceserial, ntpserverid), nil) if err != nil { return nil, err } @@ -427,7 +427,7 @@ type DeviceSetNTPServerCfgReq struct { // 该接口用于配置设备指定NTP服务器参数 func DeviceSetNTPServerCfg(access_token *string, req DeviceSetNTPServerCfgReq) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", TIM_NTPSERVER_CFG, req) + resp, err := hikvisionRequest(access_token, "POST", TIM_NTPSERVER_CFG, req) if err != nil { return nil, err } diff --git a/cloud/group-cloud.go b/iot/group-cloud.go similarity index 87% rename from cloud/group-cloud.go rename to iot/group-cloud.go index 6d32f52..5cb4525 100644 --- a/cloud/group-cloud.go +++ b/iot/group-cloud.go @@ -31,7 +31,7 @@ type GroupAddReq struct { // 该接口用于通过编号来新增组。最多支持3000个组,最多支持5层嵌套。 func GroupAdd(access_token *string, req *GroupAddReq) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", GROUP_ADD, req) + resp, err := hikvisionRequest(access_token, "POST", GROUP_ADD, req) if err != nil { return nil, err } @@ -54,7 +54,7 @@ type GroupUpdateReq struct { // 该接口用于通过组编号来删除组。组下面挂有下级节点或者设备的不可以删除,需清空后进行删除。 func GroupUpdate(access_token *string, req *GroupUpdateReq) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", GROUP_UPDATE, req) + resp, err := hikvisionRequest(access_token, "POST", GROUP_UPDATE, req) if err != nil { return nil, err } @@ -71,7 +71,7 @@ func GroupUpdate(access_token *string, req *GroupUpdateReq) (*model.BaseOperatio // 该接口用于通过组编号来删除组。组下面挂有下级节点或者设备的不可以删除,需清空后进行删除。 func GroupRemove(access_token *string, groupNo string) (*model.BaseOperationRes, error) { - resp, err := BaseCloudHttpRequest(access_token, "POST", fmt.Sprintf("%s?groupNo=%s", GROUP_REMOVE, groupNo), nil) + resp, err := hikvisionRequest(access_token, "POST", fmt.Sprintf("%s?groupNo=%s", GROUP_REMOVE, groupNo), nil) if err != nil { return nil, err } @@ -101,7 +101,7 @@ type Group struct { // 该接口用于通过组编号获取组的详细信息 func CloudGetGroup(access_token *string, groupNo string) (*Group, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?groupNo=%s", GROUP_DETAIL, groupNo), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?groupNo=%s", GROUP_DETAIL, groupNo), nil) if err != nil { return nil, err } @@ -124,7 +124,7 @@ type Groups struct { // 该接口用于获取所有组。 func GroupGetAll(access_token *string) ([]Group, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", GROUP_LISTALL, nil) + resp, err := hikvisionRequest(access_token, "GET", GROUP_LISTALL, nil) if err != nil { return nil, err } @@ -141,7 +141,7 @@ func GroupGetAll(access_token *string) ([]Group, error) { // 该接口用于通过组编号查找某组的下级节点。如果父节点为空,则查询根节点。 func GroupChildList(access_token *string, groupNo string) ([]Group, error) { - resp, err := BaseCloudHttpRequest(access_token, "GET", fmt.Sprintf("%s?parentNo=%s", GROUP_CHILD_LIST, groupNo), nil) + resp, err := hikvisionRequest(access_token, "GET", fmt.Sprintf("%s?parentNo=%s", GROUP_CHILD_LIST, groupNo), nil) if err != nil { return nil, err } diff --git a/iot/hikvision-iot.go b/iot/hikvision-iot.go new file mode 100644 index 0000000..dbab2b1 --- /dev/null +++ b/iot/hikvision-iot.go @@ -0,0 +1,129 @@ +package cloud + +import ( + "crypto/tls" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + "os" + "strings" + "time" +) + +var ( + baseURL = "https://api2.hik-cloud.com/oauth" + clientID = "" + clientSecret = "" + scope = "" +) + +func init() { + baseURL = os.Getenv("HIK_IOT_URL") + if baseURL == "" { + baseURL = "https://api2.hik-cloud.com/oauth" + } +} + +// 基础云眸http请求 +func hikvisionRequest(method string, url string, body interface{}) ([]byte, error) { + b, err := json.Marshal(body) + if err != nil { + return nil, err + } + reqbody := strings.NewReader(string(b)) + req, err := http.NewRequest(method, url, reqbody) + if err != nil { + return nil, err + } + + token, err := hikvisionOauth() + if err != nil { + return nil, err + } + req.Header.Add("authorization", fmt.Sprintf(" bearer %s", token)) + + if strings.ToLower(method) == "post" { + req.Header.Add("Content-Type", "application/json") + } + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + return respBody, nil +} + +var token string +var expired time.Time + +type OauthResponse struct { + AccessToken string `json:"access_token"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` + Scope string `json:"scope"` +} + +// 客户端认证获取access_token +func hikvisionOauth() (*string, error) { + + if expired.Before(time.Now()) { + return &token, nil + } + + params := url.Values{} + params.Add("client_id", clientID) + params.Add("client_secret", clientSecret) + params.Add("grant_type", "client_credentials") + params.Add("scope", scope) + + req, err := http.NewRequest("POST", fmt.Sprintf(`%s/token`, baseURL), strings.NewReader(string(params.Encode()))) + if err != nil { + return nil, err + } + + req.Header.Add("Accept", "*/*") + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + + client := &http.Client{Transport: tr, Timeout: 10 * time.Second} + resp, err := client.Do(req) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + errmsg := fmt.Sprintf("http status code: %d", resp.StatusCode) + return nil, errors.New(errmsg) + } + + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var result *OauthResponse + if err := json.Unmarshal(respBody, &result); err != nil { + return nil, err + } + + token = result.AccessToken + expired = time.Now().Add(time.Duration(result.ExpiresIn) * time.Second) + + return &token, nil +} diff --git a/cloud/hikvision.http b/iot/hikvision.http similarity index 78% rename from cloud/hikvision.http rename to iot/hikvision.http index 3c986ef..9737e5b 100644 --- a/cloud/hikvision.http +++ b/iot/hikvision.http @@ -1,9 +1,8 @@ -@url=https://api2.hik-cloud.com/oauth -@token=authorization: bearer a08a8044-3770-41f5-b5a5-048004a723ac -@token_type=bearer +@url=https://api2.hik-cloud.com/api/v1 +@token=bearer a08a8044-3770-41f5-b5a5-048004a723ac -### 客户端认证 -POST {{url}}/token HTTP/1.1 + +POST https://api2.hik-cloud.com/oauth/token HTTP/1.1 Content-Type: application/x-www-form-urlencoded client_id=164edfd71b744dd88c945dbd5ae30a9a&client_secret=2f580d932d7d46029a2091ece681035c&grant_type=client_credentials&scope=yy @@ -34,4 +33,4 @@ POST {{url}}/mq/consumer/messages HTTP/1.1 Content-Type: application/x-www-form-urlencoded Authorization: {{token}} -autoCommit=true&consumerId=7db9420cdb2844f5ba8bba07d1417d54 +autoCommit=true&consumerId=7db9420cdb2844f5ba8bba07d1417d54 \ No newline at end of file diff --git a/iot/model/group-model.go b/iot/model/group-model.go new file mode 100644 index 0000000..5b5f458 --- /dev/null +++ b/iot/model/group-model.go @@ -0,0 +1,6 @@ +package model + +type Groups struct { + Hikvision + Data []Group `json:"data"` +} diff --git a/model/base-model.go b/iot/model/hikvision-model.go similarity index 76% rename from model/base-model.go rename to iot/model/hikvision-model.go index 4041858..9a50534 100644 --- a/model/base-model.go +++ b/iot/model/hikvision-model.go @@ -1,7 +1,7 @@ package model // 基础操作回参 -type BaseOperationRes struct { +type Hikvision struct { Code int `json:"code"` Message string `json:"message"` } diff --git a/cloud/oauth_test.go b/iot/oauth_test.go similarity index 100% rename from cloud/oauth_test.go rename to iot/oauth_test.go diff --git a/iot/readme.md b/iot/readme.md new file mode 100644 index 0000000..606df70 --- /dev/null +++ b/iot/readme.md @@ -0,0 +1 @@ +海康云眸平台IOT \ No newline at end of file