hikvision/iot/hikvision-iot.go

259 lines
6.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package iot
import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"time"
)
var (
baseURL = "https://api2.hik-cloud.com"
clientID = ""
clientSecret = ""
scope = ""
)
func init() {
baseURL = os.Getenv("IOT_URL")
if baseURL == "" {
baseURL = "https://api2.hik-cloud.com"
}
clientID = os.Getenv("IOT_CLIENTID")
if clientID == "" {
clientID = "164edfd71b744dd88c945dbd5ae30a9a"
}
clientSecret = os.Getenv("IOT_CLIENTSECRET")
if clientSecret == "" {
clientSecret = "2f580d932d7d46029a2091ece681035c"
}
scope = os.Getenv("IOT_SCOPE")
if scope == "" {
scope = "yy"
}
}
// 基础云眸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, baseURL+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))
switch strings.ToLower(method) {
case "post":
req.Header.Add("Content-Type", "application/json")
case "delete":
if body != nil {
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
// 客户端认证获取access_token公共方法
func hikvisionOauth() (*string, error) {
if expired.After(time.Now()) {
return &token, nil
}
params := struct {
client_id string
client_secret string
grant_type string
scope string
}{
client_id: clientID,
client_secret: clientSecret,
grant_type: "client_credentials",
scope: scope,
}
resp, err := hikvisionIOTRequestUrlencoded("POST", `/oauth/token`, params, false)
if err != nil {
return nil, err
}
result := &struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
Scope string `json:"scope"`
}{}
if err := json.Unmarshal(resp, &result); err != nil {
return nil, err
}
token = result.AccessToken
expired = time.Now().Add(time.Duration(result.ExpiresIn) * time.Second)
return &token, nil
}
// iot 使用form请求 application/x-www-form-urlencoded公共方法
//
// 传入的结构体内的字段名称必须与文档一致
func hikvisionIOTRequestUrlencoded(method string, url string, body interface{}, auth bool) ([]byte, error) {
reader, err := hikvisioninspectStruct(body)
if err != nil {
return nil, err
}
req, err := http.NewRequest(method, baseURL+url, strings.NewReader(reader.Encode()))
if err != nil {
return nil, err
}
req.Header.Add("Accept", "*/*")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
if auth {
token, err := hikvisionOauth()
if err != nil {
return nil, err
}
req.Header.Add("authorization", fmt.Sprintf(" bearer %s", *token))
}
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
}
return respBody, nil
}
func hikvisionRequestUrlencoded(method string, url string, body interface{}, auth bool) ([]byte, error) {
reader, err := hikvisioninspectStruct(body)
if err != nil {
return nil, err
}
req, err := http.NewRequest(method, url, strings.NewReader(reader.Encode()))
if err != nil {
return nil, err
}
req.Header.Add("Accept", "*/*")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
if auth {
token, err := hikvisionOauth()
if err != nil {
return nil, err
}
req.Header.Add("authorization", fmt.Sprintf(" bearer %s", *token))
}
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
}
return respBody, nil
}
// 解析结构体数据写入到url.values中
func hikvisioninspectStruct(u interface{}) (url.Values, error) {
values := url.Values{}
typev := reflect.TypeOf(u)
if typev.Kind() != reflect.Struct {
return nil, errors.New("typev.Kind() is not a reflect.Struct")
}
for i := 0; i < typev.NumField(); i++ {
v := reflect.ValueOf(u)
field := v.FieldByName(typev.Field(i).Name)
// typev := reflect.TypeOf(u).FieldByName()
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
values.Add(typev.Field(i).Name, fmt.Sprintf("%d", field.Int()))
// fmt.Printf("field:%s type:%s value:%d\n", typev.Field(i).Name, field.Type().Name(), field.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
values.Add(typev.Field(i).Name, fmt.Sprintf("%d", field.Uint()))
// fmt.Printf("field:%s type:%s value:%d\n", typev.Field(i).Name, field.Type().Name(), field.Uint())
case reflect.Bool:
values.Add(typev.Field(i).Name, fmt.Sprintf("%v", field.Bool()))
// fmt.Printf("field:%s type:%s value:%t\n", typev.Field(i).Name, field.Type().Name(), field.Bool())
case reflect.String:
values.Add(typev.Field(i).Name, field.String())
// fmt.Printf("field:%s type:%s value:%q\n", typev.Field(i).Name, field.Type().Name(), field.String())
// default:
// fmt.Printf("field:%s unhandled kind:%s\n", typev.Field(i).Name, field.Kind())
}
}
return values, nil
}