itao.go 5.2 KB
package itao

import (
	"context"
	"crypto/hmac"
	"crypto/sha1"
	"encoding/hex"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/errors/gerror"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gctx"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/os/gtimer"
	"github.com/gogf/gf/util/gconv"
	"net/url"
	"sort"
	"strings"
	"time"
)

type Config struct {
	ApiUrl    string
	AppKey    string
	AppSecret string
}

var server *Config

const PkgName = "itao"
const CacheKey = "itao:token"
const Host = "https://open.huoju6.com/openapi/param2/1/com.huoju6.open/"

func New(req *Config) {
	server = req
	gtimer.Add(time.Hour, func() {
		var ctx = gctx.New()
		_, _ = server.accessToken(ctx)
	})
	return
}

type CommonRes struct {
	Success bool   `json:"success"`
	ErrCode string `json:"errCode"`
	ErrMsg  string `json:"errMsg"`
}

func generate(req string) (res string) {
	//拼接参数
	mac := hmac.New(sha1.New, []byte(server.AppSecret))
	mac.Write([]byte(req))
	mdStr := hex.EncodeToString(mac.Sum(nil))
	res = strings.ToUpper(mdStr)
	return
}

func sign(method string, req g.Map) (err error) {
	var keys []string
	req["_aop_timestamp"] = gtime.Now().TimestampMilliStr()

	for k := range req {
		keys = append(keys, k)
	}

	sort.Strings(keys)

	var signStr string
	for _, v := range keys {
		if v != "_aop_signature" {
			signStr += v
			signStr += gconv.String(req[v])
		}
	}
	//拼接参数
	signStr = "param2/1/com.huoju6.open/" + method + "/" + server.AppKey + signStr
	req["_aop_signature"] = generate(signStr)
	return
}

func (s *Config) Post(ctx context.Context, method string, params g.Map) (str string, err error) {
	params["access_token"], err = s.GetAccessToken(ctx)
	if err != nil {
		return
	}
	str, err = Post(ctx, method, params)
	return

}

func Post(ctx context.Context, method string, params g.Map) (str string, err error) {
	Start := gtime.TimestampMilli()
	err = sign(method, params)
	if err != nil {
		return
	}
	Url := Host + method + "/" + server.AppKey
	Request := g.Client()
	Request.SetHeader("Content-Type", "application/x-www-form-urlencoded")
	resp, err := Request.Timeout(time.Second*5).Get(Url, params)

	defer func() {
		_ = resp.Close()
		paramStr := gjson.New(params).MustToJsonString()
		ctx = context.WithValue(ctx, "Method", "POST")
		ctx = context.WithValue(ctx, "URI", Url)
		if err != nil {
			g.Log().Cat(PkgName).Ctx(ctx).Infof("参数【%v】错误【%v】响应时间【%vms】", paramStr, err.Error(), gtime.TimestampMilli()-Start)
		} else {
			g.Log().Cat(PkgName).Ctx(ctx).Infof("参数【%v】响应【%v】响应时间【%vms】", paramStr, str, gtime.TimestampMilli()-Start)
		}

	}()
	str = resp.ReadAllString()
	return

}

func (s *Config) Get(ctx context.Context, method string, params g.Map) (str string, err error) {
	params["access_token"], err = s.GetAccessToken(ctx)
	if err != nil {
		return
	}
	str, err = Get(ctx, method, params)
	return

}

func Get(ctx context.Context, method string, params g.Map) (str string, err error) {
	Start := gtime.TimestampMilli()
	err = sign(method, params)
	if err != nil {
		return
	}
	Url := Host + method + "/" + server.AppKey
	Request := g.Client()
	Values := url.Values{}
	for k, v := range params {
		Values.Add(k, gconv.String(v))
	}
	Request.SetHeader("Content-Type", "application/x-www-form-urlencoded")
	resp, err := Request.Timeout(time.Second * 5).Get(Url + "?" + Values.Encode())

	defer func() {
		_ = resp.Close()
		paramStr := gjson.New(params).MustToJsonString()
		ctx = context.WithValue(ctx, "Method", "GET")
		ctx = context.WithValue(ctx, "URI", Url)
		if err != nil {
			g.Log().Cat(PkgName).Ctx(ctx).Infof("参数【%v】错误【%v】响应时间【%vms】", paramStr, err.Error(), gtime.TimestampMilli()-Start)
		} else {
			g.Log().Cat(PkgName).Ctx(ctx).Infof("参数【%v】响应【%v】响应时间【%vms】", paramStr, str, gtime.TimestampMilli()-Start)
		}

	}()
	str = resp.ReadAllString()
	return

}

func (s *Config) GetAccessToken(ctx context.Context) (res string, err error) {
	var conn = g.Redis().Conn()
	defer func() {
		_ = conn.Close()
	}()
	_, _ = conn.DoVar("SELECT", 10)
	cache, _ := conn.DoVar("HGETALL", CacheKey)
	if cache.IsEmpty() {
		err = gerror.New("获取token 失败")
		return
	}
	var result *AuthTokenRes
	_ = gjson.New(cache).Scan(&result)
	if result == nil || result.AccessToken == "" {
		err = gerror.New("获取token 失败")
		return
	}
	if result.AccessTokenExpireTime < gtime.TimestampMilli() {
		result, err = s.accessToken(ctx)
		if err != nil {
			return
		}
	}
	res = result.AccessToken
	return
}

//accessToken 刷新
func (s *Config) accessToken(ctx context.Context) (res *AuthTokenRes, err error) {
	var conn = g.Redis().Conn()
	defer func() {
		_ = conn.Close()
	}()
	_, _ = conn.DoVar("SELECT", 10)
	cache, _ := conn.DoVar("HGETALL", CacheKey)
	if cache.IsEmpty() {
		err = gerror.New("获取token 失败")
		return
	}
	_ = gjson.New(cache).Scan(&res)
	if res.AccessTokenExpireTime > gtime.Now().Add(time.Hour).TimestampMilli() {
		return
	}
	res, err = Auth.Token(ctx, res.RefreshToken, 2)
	if err != nil {
		return
	}
	if res.Code != "success" {
		err = gerror.New("获取token 失败")
		return
	}
	_, _ = conn.Do("HMSET", CacheKey, "accessToken", res.AccessToken, "accessTokenExpireTime", res.AccessTokenExpireTime)
	return
}