Files
hikvisionOpenAPIGo/sdk.go
2022-05-12 11:41:46 +08:00

227 lines
5.6 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 hikvisionOpenAPIGo
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/gofrs/uuid"
"io/ioutil"
"net/http"
"sort"
"strconv"
"strings"
"time"
)
// HKConfig 海康OpenAPI配置参数
type HKConfig struct {
Ip string //平台ip
Port int //平台端口
AppKey string //平台APPKey
Secret string //平台APPSecret
IsHttps bool //是否使用HTTPS协议
}
// 返回结果
type Result struct {
Code string `json:"code"`
Msg string `json:"msg"`
Data interface{} `json:"data"`
}
// 返回值data
type Data struct {
Total int `json:"total"`
PageSize int `json:"pageSize"`
PageNo int `json:"pageNo"`
List []map[string]interface{} `json:"list"`
}
// @title HTTP Post请求
// @url HTTP接口Url string HTTP接口Url不带协议和端口如/artemis/api/resource/v1/org/advance/orgList
// @body 请求参数 map[string]string
// @return 请求结果 参数类型
func (hk HKConfig) HttpPost(url string, body map[string]string, timeout int) (result Result, err error) {
var header = make(map[string]string)
bodyJson, err := json.Marshal(body)
if err != nil {
return result, err
}
err = hk.initRequest(header, url, string(bodyJson), true)
if err != nil {
return Result{}, err
}
var sb []string
if hk.IsHttps {
sb = append(sb, "https://")
} else {
sb = append(sb, "http://")
}
sb = append(sb, fmt.Sprintf("%s:%d", hk.Ip, hk.Port))
sb = append(sb, url)
client := &http.Client{}
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
client.Timeout = time.Duration(timeout) * time.Second
if hk.IsHttps {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client.Transport = tr
}
req, err := http.NewRequest("POST", strings.Join(sb, ""), bytes.NewReader(bodyJson))
if err != nil {
return
}
req.Header.Set("Accept", header["Accept"])
req.Header.Set("Content-Type", header["Content-Type"])
for k, v := range header {
if strings.Contains(k, "x-ca-") {
req.Header.Set(k, v)
}
}
resp, err := client.Do(req)
if err != nil {
return
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
var resBody []byte
resBody, err = ioutil.ReadAll(resp.Body)
if err != nil {
return
}
err = json.Unmarshal(resBody, &result)
} else if resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusMovedPermanently {
reqUrl := resp.Header.Get("Location")
err = fmt.Errorf("HttpPost Response StatusCode%dLocation%s", resp.StatusCode, reqUrl)
} else {
err = fmt.Errorf("HttpPost Response StatusCode%d", resp.StatusCode)
}
return
}
// initRequest 初始化请求头
func (hk HKConfig) initRequest(header map[string]string, url, body string, isPost bool) error {
header["Accept"] = "application/json"
header["Content-Type"] = "application/json"
if isPost {
var err error
header["content-md5"], err = computeContentMd5(body)
if err != nil {
return err
}
}
header["x-ca-timestamp"] = strconv.FormatInt(time.Now().UnixMilli(), 10)
uid, err := uuid.NewV4()
if err != nil {
return err
}
header["x-ca-nonce"] = uid.String()
header["x-ca-key"] = hk.AppKey
var strToSign string
if isPost {
strToSign = buildSignString(header, url, "POST")
} else {
strToSign = buildSignString(header, url, "GET")
}
signedStr, err := computeForHMACSHA256(strToSign, hk.Secret)
if err != nil {
return err
}
header["x-ca-signature"] = signedStr
return nil
}
// computeContentMd5 计算content-md5
func computeContentMd5(body string) (string, error) {
h := md5.New()
_, err := h.Write([]byte(body))
if err != nil {
return "", err
}
md5Str := hex.EncodeToString(h.Sum(nil))
return base64.StdEncoding.EncodeToString([]byte(md5Str)), nil
}
// computeForHMACSHA256 计算HMACSHA265
func computeForHMACSHA256(str, secret string) (string, error) {
mac := hmac.New(sha256.New, []byte(secret))
_, err := mac.Write([]byte(str))
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil
}
// buildSignString 计算签名字符串
func buildSignString(header map[string]string, url, method string) string {
var sb []string
sb = append(sb, strings.ToUpper(method))
sb = append(sb, "\n")
if header != nil {
if _, ok := header["Accept"]; ok {
sb = append(sb, header["Accept"])
sb = append(sb, "\n")
}
if _, ok := header["Content-MD5"]; ok {
sb = append(sb, header["Content-MD5"])
sb = append(sb, "\n")
}
if _, ok := header["Content-Type"]; ok {
sb = append(sb, header["Content-Type"])
sb = append(sb, "\n")
}
if _, ok := header["Date"]; ok {
sb = append(sb, header["Date"])
sb = append(sb, "\n")
}
}
sb = append(sb, buildSignHeader(header))
sb = append(sb, url)
return strings.Join(sb, "")
}
// buildSignHeader 计算签名头
func buildSignHeader(header map[string]string) string {
var sortedDicHeader map[string]string
sortedDicHeader = header
var sslice []string
for key, _ := range sortedDicHeader {
sslice = append(sslice, key)
}
sort.Strings(sslice)
var sbSignHeader []string
var sb []string
//在将key输出
for _, k := range sslice {
if strings.Contains(strings.ReplaceAll(k, " ", ""), "x-ca-") {
sb = append(sb, k+":")
if sortedDicHeader[k] != "" {
sb = append(sb, sortedDicHeader[k])
}
sb = append(sb, "\n")
if len(sbSignHeader) > 0 {
sbSignHeader = append(sbSignHeader, ",")
}
sbSignHeader = append(sbSignHeader, k)
}
}
header["x-ca-signature-headers"] = strings.Join(sbSignHeader, "")
return strings.Join(sb, "")
}