diff --git a/cache/redis.go b/cache/redis.go new file mode 100644 index 0000000..8eb4424 --- /dev/null +++ b/cache/redis.go @@ -0,0 +1,23 @@ +package cache + +import "github.com/go-redis/redis" + +var ( + redisClient *redis.Client = nil +) + +func NewRedis() { + addr := "127.0.0.1:6379" + redis.NewClient(&redis.Options{}) + + redisClient = redis.NewClient(&redis.Options{ + Addr: addr, + }) +} + +func GetRedis() *redis.Client { + if redisClient == nil { + NewRedis() + } + return redisClient +} diff --git a/weixin/base.go b/weixin/base.go index 2b561cc..17f4092 100644 --- a/weixin/base.go +++ b/weixin/base.go @@ -2,11 +2,15 @@ package weixin import ( "fmt" - "github.com/tidwall/gjson" "io" "net/http" "sync" "time" + + cache2 "git.u8t.cn/open/gosdk/cache" + "github.com/go-redis/redis" + uuid2 "github.com/google/uuid" + "github.com/tidwall/gjson" ) const ( @@ -87,6 +91,65 @@ func (o *BaseSdk) getAccessToken() (string, error) { return o.accessToken, nil } +// redis share version +func (o *BaseSdk) getAccessToken2() (string, error) { + redix := o.getRedis() + tokenKey := fmt.Sprintf("weixin_oa_access_token_v2_%s", o.appid) + lockKey := fmt.Sprintf("get_access_token_unique_%s", o.appid) + uuid := uuid2.New().String() + + // get token + token := redix.Get(tokenKey).Val() + if token != "" { + return token, nil + } + + // setEX and expire + // if not set key. wait 200ms and get again and retry 5 times + if ok := redix.SetNX(lockKey, uuid, 10*time.Second).Val(); !ok { + for i := range 5 { + time.Sleep(time.Duration(200*(i+2)) * time.Millisecond) + if token = redix.Get(tokenKey).Val(); token != "" { + return token, nil + } + } + return "", fmt.Errorf(" wait 5 times,but still not get token") + } + + defer func() { + if redix.Get(lockKey).Val() == uuid { + redix.Del(lockKey) + } + }() + + // get new token + url := fmt.Sprintf("%s?grant_type=client_credential&appid=%s&secret=%s", accessTokenUrl, o.appid, o.secret) + res, err := http.Get(url) + if err != nil { + return "", err + } + defer res.Body.Close() + body, err := io.ReadAll(res.Body) + if err != nil { + return "", err + } + g := gjson.ParseBytes(body) + + token = g.Get("access_token").String() + if token == "" { + return "", fmt.Errorf("%d:%s", g.Get("errcode").Int(), g.Get("errmsg").String()) + } + + expire := g.Get("expires_in").Int() - 10 + redix.Set(tokenKey, token, time.Second*time.Duration(expire)) + + return token, nil +} + +func (o *BaseSdk) getRedis() *redis.Client { + return cache2.GetRedis() +} + func (o *BaseSdk) getUserInfoByCode(code string, auth bool) (*UserInfo, error) { url := fmt.Sprintf("%s?appid=%s&secret=%s&code=%s&grant_type=authorization_code", code2AccessTokenUrl, o.appid, o.secret, code) diff --git a/weixin/oa_sdk.go b/weixin/oa_sdk.go index 0adb6fe..7698358 100644 --- a/weixin/oa_sdk.go +++ b/weixin/oa_sdk.go @@ -4,11 +4,12 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/tidwall/gjson" "io" "mime/multipart" "net/http" "time" + + "github.com/tidwall/gjson" ) type OaSdk struct { @@ -35,7 +36,7 @@ func (o *OaSdk) GetQrCode(sceneStr string) (string, error) { } marshal, _ := json.Marshal(params) - accessToken, err := o.getAccessToken() + accessToken, err := o.getAccessToken2() if err != nil { return "", err } @@ -68,7 +69,7 @@ func (o *OaSdk) GetUserInfoByCodeNoAuth(code string) (*UserInfo, error) { } func (o *OaSdk) GetUserInfoByOpenid(openid string) (*UserInfo, error) { - accessToken, err := o.getAccessToken() + accessToken, err := o.getAccessToken2() if err != nil { return nil, err } @@ -115,7 +116,7 @@ func (o *OaSdk) UploadFileByByte(file []byte, ext string) (string, string, error if err != nil { return "", "", err } - token, err := o.getAccessToken() + token, err := o.getAccessToken2() if err != nil { return "", "", err } @@ -155,7 +156,7 @@ func (o *OaSdk) UploadFileByByte(file []byte, ext string) (string, string, error } func (o *OaSdk) CreateMenu(buttons []*OaMenuButton) error { - accessToken, err := o.getAccessToken() + accessToken, err := o.getAccessToken2() if err != nil { return err } @@ -182,7 +183,7 @@ func (o *OaSdk) CreateMenu(buttons []*OaMenuButton) error { } func (o *OaSdk) DeleteMenu() error { - accessToken, err := o.getAccessToken() + accessToken, err := o.getAccessToken2() if err != nil { return err }