gome.go 4.2 KB
package gome

import (
	"context"
	"errors"
	"github.com/gogf/gf/crypto/gmd5"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/text/gstr"
	"github.com/gogf/gf/util/gconv"
	"github.com/gogf/gf/util/gutil"
	"gitlab.jxhh.com/stbz/library.git/logs"
	"time"
)

type Config struct {
	ApiUrl    string
	AppKey    string
	AppSecret string
	Version   string
}

type Client struct {
	*Config
	AccessToken  string
	RefreshToken string
}

type CommonReq struct {
	AppKey      string      `json:"app_key"`
	Version     string      `json:"version"`
	Method      string      `json:"method"`
	AccessToken string      `json:"access_token"`
	Timestamp   string      `json:"timestamp"`
	Param       interface{} `json:"param"`
	Sign        string      `json:"sign,omitempty"`
}

type CommonPageReq struct {
	PageNo   int `json:"pageNo"`
	PageSize int `json:"pageSize"`
}

type CommonPageRes struct {
	PageSize   int `json:"pageSize"`
	PageNo     int `json:"pageNo"`
	TotalPage  int `json:"totalPage"`
	TotalCount int `json:"totalCount"`
}

type CommonRes struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	SubCode string `json:"sub_code"`
	SubMsg  string `json:"sub_msg"`
}

var server *Client

const pkgName = "gome"
const CacheKey = "gome:token"

func New(config *Config) {
	_ = gconv.Struct(config, &server)
	return
}

func (s *Client) sign(req g.Map) string {
	data := gjson.New(req)
	_ = data.Remove("sign")
	return gstr.ToUpper(gmd5.MustEncryptString(server.AppSecret + data.MustToJsonString() + server.AppSecret))
}

func (s *Client) post(ctx context.Context, method string, req interface{}) (str string, err error) {
	Start := gtime.TimestampMilli()

	allparams := &CommonReq{
		AppKey:      server.AppKey,
		Version:     server.Version,
		Method:      method,
		AccessToken: server.AccessToken,
		Timestamp:   gtime.Now().String(),
		Param:       req,
	}
	allparams.Sign = s.sign(gconv.Map(allparams))
	Request := g.Client()
	Request.SetHeader("Content-Type", "application/json")
	resp, err := Request.Timeout(time.Second*5).Post(server.ApiUrl, allparams)
	defer func() {
		paramStr := gjson.New(req).MustToJsonString()
		ctx = context.WithValue(ctx, "Method", "POST")
		ctx = context.WithValue(ctx, "URI", method)
		if err != nil {
			logs.Errorf(ctx, pkgName, logs.FormatErr, paramStr, err.Error(), gtime.TimestampMilli()-Start)
		} else {
			logs.Infof(ctx, pkgName, logs.FormatSuc, paramStr, str, gtime.TimestampMilli()-Start)
		}
	}()
	str = resp.ReadAllString()
	return

}

func (s *Client) requestApi(ctx context.Context, method string, req interface{}) (str string, err error) {
	err = s.getAccessToken(ctx)
	if err != nil {
		return
	}
	str, err = s.post(ctx, method, req)
	return
}

type accessToken struct {
	AppKey           string `json:"appKey"`
	AccessToken      string `json:"access_token"`
	RefreshToken     string `json:"refresh_token"`
	ExpiresInSeconds int64  `json:"expiresInSeconds"`
	CreateTime       string `json:"createTime"`
}

//getAccessToken 获取token
func (s *Client) getAccessToken(ctx context.Context) (err error) {
	var token *accessToken
	cache, _ := g.Redis().DoVar("HGETALL", CacheKey)
	if !cache.IsEmpty() {
		_ = cache.Scan(&token)
		if gtime.NewFromStr(token.CreateTime).Timestamp()+token.ExpiresInSeconds > gtime.Timestamp()-3600 {
			s.AccessToken = token.AccessToken
			return
		}
		return s.refreshToken(ctx, token)
	}
	res, err := Token.Get(ctx)
	if err != nil {
		return
	}
	if res.Code != "4000" {
		err = errors.New(res.Message)
		return
	}
	_, _ = g.Redis().Do("HMSET", append(g.Slice{CacheKey}, gutil.MapToSlice(gconv.Map(res.Data))...)...)
	s.AccessToken = res.Data.AccessToken
	return
}

//refreshToken 刷新token
func (s *Client) refreshToken(ctx context.Context, req *accessToken) (err error) {
	if gtime.NewFromStr(req.CreateTime).Timestamp()+req.ExpiresInSeconds < gtime.Timestamp() {
		_, err = g.Redis().DoVar("DEL", CacheKey)
		return s.getAccessToken(ctx)
	}
	res, err := Token.Refresh(ctx, req.RefreshToken)
	if err != nil {
		return
	}

	if res.Code != "4000" {
		err = errors.New(res.Message)
		return
	}
	_, _ = g.Redis().Do("HMSET", append(g.Slice{CacheKey}, gutil.MapToSlice(gconv.Map(res.Data))...)...)
	s.AccessToken = res.Data.AccessToken
	return
}