Skip to content

Commit

Permalink
Update stable access (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
iGoogle-ink authored Nov 29, 2024
1 parent 9db3aa2 commit d764c17
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 117 deletions.
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ module github.com/go-pay/wechat-sdk
go 1.21

require (
github.com/go-pay/bm v0.0.4
github.com/go-pay/bm v0.0.5
github.com/go-pay/crypto v0.0.1
github.com/go-pay/util v0.0.3
github.com/go-pay/xhttp v0.0.2
github.com/go-pay/smap v0.0.2
github.com/go-pay/util v0.0.4
github.com/go-pay/xhttp v0.0.3
github.com/go-pay/xlog v0.0.3
github.com/go-pay/xtime v0.0.2
)
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
github.com/go-pay/bm v0.0.4 h1:MUECRx1t0MkbQ7Yzk2qseKBOKoUi4N8WZ+alZBrZesg=
github.com/go-pay/bm v0.0.4/go.mod h1:S7ZAxWtyjm7PX54cna4N/RzJ1JAZG8EDukZ2fZaZ+qk=
github.com/go-pay/bm v0.0.5 h1:ZAg6j1Wagc8JZ88ja7VgEF/g+kKOFzLRNc43bm0ivZc=
github.com/go-pay/bm v0.0.5/go.mod h1:S7ZAxWtyjm7PX54cna4N/RzJ1JAZG8EDukZ2fZaZ+qk=
github.com/go-pay/crypto v0.0.1 h1:B6InT8CLfSLc6nGRVx9VMJRBBazFMjr293+jl0lLXUY=
github.com/go-pay/crypto v0.0.1/go.mod h1:41oEIvHMKbNcYlWUlRWtsnC6+ASgh7u29z0gJXe5bes=
github.com/go-pay/util v0.0.3 h1:0OjERb7MAVpM2gLPnBESLdMsosYyJ4i31V2/YZBiPjw=
github.com/go-pay/util v0.0.3/go.mod h1:qM8VbyF1n7YAPZBSJONSPMPsPedhUTktewUAdf1AjPg=
github.com/go-pay/xhttp v0.0.2 h1:O8rnd/d03WsboFtUthwFMg61ikHRfYHyD1m0JiUx60g=
github.com/go-pay/xhttp v0.0.2/go.mod h1:BnuvXpLKkXTFMOBc5MTb0hxdrstwunbzQPJUZOsNbt4=
github.com/go-pay/smap v0.0.2 h1:kKflYor5T5FgZltPFBMTFfjJvqYMHr5VnIFSEyhVTcA=
github.com/go-pay/smap v0.0.2/go.mod h1:HW9oAo0okuyDYsbpbj5fJFxnNj/BZorRGFw26SxrNWw=
github.com/go-pay/util v0.0.4 h1:TuwSU9o3Qd7m9v1PbzFuIA/8uO9FJnA6P7neG/NwPyk=
github.com/go-pay/util v0.0.4/go.mod h1:Tsdhs8Ib9J9b4+NKNO1PHh5hWHhlg98PthsX0ckq6PM=
github.com/go-pay/xhttp v0.0.3 h1:9Vke2QeY0xs8E9oyb3bi94v47N25ZdGgZOIG1hgCgKA=
github.com/go-pay/xhttp v0.0.3/go.mod h1:LDNKLp+C6UJRZSAcxI4z4BYtRs3ksbgxPQl1W9HQGXs=
github.com/go-pay/xlog v0.0.3 h1:avyMhCL/JgBHreoGx/am/kHxfs1udDOAeVqbmzP/Yes=
github.com/go-pay/xlog v0.0.3/go.mod h1:mH47xbobrdsSHWsmFtSF5agWbMHFP+tK0ZbVCk5OAEw=
github.com/go-pay/xtime v0.0.2 h1:7YR4/iuELsEHpJ6LUO0SVK80hQxDO9MLCfuVYIiTCRM=
Expand Down
76 changes: 19 additions & 57 deletions mini/access_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,10 @@ import (
"context"
"fmt"
"runtime"
"strconv"
"time"
)

// 获取小程序全局唯一后台接口调用凭据(access_token)
// 微信小程序文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
//func (s *SDK) getAccessToken() (err error) {
// defer func() {
// if err != nil {
// // reset default refresh internal
// s.RefreshInternal = time.Second * 20
// if s.callback != nil {
// go s.callback("", "", 0, err)
// }
// }
// }()
//
// path := "/cgi-bin/token?grant_type=client_credential&appid=" + s.Appid + "&secret=" + s.Secret
// at := &AccessToken{}
// if _, err = s.DoRequestGet(s.ctx, path, at); err != nil {
// return
// }
// if at.Errcode != Success {
// err = fmt.Errorf("errcode(%d), errmsg(%s)", at.Errcode, at.Errmsg)
// return
// }
// s.accessToken = at.AccessToken
// s.RefreshInternal = time.Second * time.Duration(at.ExpiresIn)
// if s.callback != nil {
// go s.callback(s.Appid, at.AccessToken, at.ExpiresIn, nil)
// }
// return nil
//}

//func (s *SDK) goAutoRefreshAccessToken() {
// defer func() {
// if r := recover(); r != nil {
// buf := make([]byte, 64<<10)
// buf = buf[:runtime.Stack(buf, false)]
// s.logger.Errorf("mini_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf)
// }
// }()
// for {
// // every one hour, request new access token, default 10s
// time.Sleep(s.RefreshInternal / 2)
// err := s.getAccessToken()
// if err != nil {
// s.logger.Errorf("get access token error, after 10s retry: %+v", err)
// continue
// }
// }
//}
"github.com/go-pay/bm"
)

// 获取稳定版接口调用凭据
// 微信小程序文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getStableAccessToken.html
Expand All @@ -70,9 +22,14 @@ func (s *SDK) getStableAccessToken() (err error) {
}
}()

path := "/cgi-bin/stable_token?grant_type=client_credential&appid=" + s.Appid + "&secret=" + s.Secret + "&force_refresh=false"
path := "/cgi-bin/stable_token"
body := make(bm.BodyMap)
body.Set("grant_type", "client_credential").
Set("appid", s.Appid).
Set("secret", s.Secret).
Set("force_refresh", false)
at := &AccessToken{}
if _, err = s.DoRequestGet(s.ctx, path, at); err != nil {
if _, err = s.doRequestPost(s.ctx, path, body, at); err != nil {
return
}
if at.Errcode != Success {
Expand Down Expand Up @@ -106,7 +63,7 @@ func (s *SDK) goAutoRefreshStableAccessToken() {
time.Sleep(s.RefreshInternal / 2)
err := s.getStableAccessToken()
if err != nil {
s.logger.Errorf("get access token error, after 10s retry: %+v", err)
s.logger.Errorf("get stable access token error, after 10s retry: %+v", err)
continue
}
}
Expand All @@ -129,7 +86,7 @@ func (s *SDK) SetMiniAccessToken(accessToken string) {

// =====================================================================================================================

// 获取接口调用凭据
// 获取 Access Token
// 微信小程序文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
func GetAccessToken(c context.Context, appid, secret string) (at *AccessToken, err error) {
uri := HostDefault + "/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret
Expand All @@ -143,12 +100,17 @@ func GetAccessToken(c context.Context, appid, secret string) (at *AccessToken, e
return at, nil
}

// 获取稳定版接口调用凭据
// 获取 Stable Access Token
// 微信小程序文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getStableAccessToken.html
func GetStableAccessToken(c context.Context, appid, secret string, forceRefresh bool) (at *AccessToken, err error) {
uri := HostDefault + "/cgi-bin/stable_token?grant_type=client_credential&appid=" + appid + "&secret=" + secret + "&force_refresh=" + strconv.FormatBool(forceRefresh)
url := HostDefault + "/cgi-bin/stable_token"
body := make(bm.BodyMap)
body.Set("grant_type", "client_credential").
Set("appid", appid).
Set("secret", secret).
Set("force_refresh", forceRefresh)
at = &AccessToken{}
if err = doRequestGet(c, uri, at); err != nil {
if err = doRequestPost(c, url, body, at); err != nil {
return nil, err
}
if at.Errcode != Success {
Expand Down
14 changes: 14 additions & 0 deletions mini/mini.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net/http"
"time"

"github.com/go-pay/bm"
"github.com/go-pay/util"
"github.com/go-pay/util/js"
"github.com/go-pay/wechat-sdk"
Expand Down Expand Up @@ -97,3 +98,16 @@ func doRequestGet(c context.Context, uri string, ptr any) (err error) {
}
return
}

func doRequestPost(c context.Context, url string, body bm.BodyMap, ptr any) (err error) {
req := xhttp.NewClient().Req()
req.Header.Add(wechat.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
_, bs, err := req.Post(url).SendBodyMap(body).EndBytes(c)
if err != nil {
return fmt.Errorf("http.request(POST, %s), err:%w", url, err)
}
if err = js.UnmarshalBytes(bs, ptr); err != nil {
return fmt.Errorf("js.UnmarshalBytes(%s, %+v):%w", string(bs), ptr, err)
}
return
}
52 changes: 20 additions & 32 deletions open/access_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ func (s *SDK) refreshAccessToken(openid, refreshToken string) {
}
return
}
s.mu.Lock()
s.openidAccessTokenMap[at.Openid] = at
s.mu.Unlock()

s.openidAccessTokenMap.Store(at.Openid, at)
if s.callback != nil {
go s.callback(&AT{
AccessToken: at.AccessToken,
Expand All @@ -53,12 +52,13 @@ func (s *SDK) goAutoRefreshAccessTokenJob() {
for {
// request new access token, default internal 10min
time.Sleep(s.autoRefreshTokenInternal)
for k, v := range s.openidAccessTokenMap {
s.openidAccessTokenMap.Range(func(k string, v *AccessToken) bool {
// 有效期小于1.5倍轮询时间时,自动刷新)
if time.Duration(v.ExpiresIn)*time.Second < (s.autoRefreshTokenInternal*3)/2 {
s.refreshAccessToken(k, v.RefreshToken)
}
}
return true
})
}
}

Expand All @@ -74,30 +74,24 @@ func (s *SDK) SetAccessTokenRefreshInternal(internal time.Duration) {

// GetAccessTokenMap 获取 access_token map,key 为 openid
func (s *SDK) GetAccessTokenMap() (openidATMap map[string]*AT) {
openidATMap = make(map[string]*AT, len(s.openidAccessTokenMap))
if s.openidAccessTokenMap != nil && len(s.openidAccessTokenMap) > 0 {
s.mu.RLock()
defer s.mu.RUnlock()
for k, v := range s.openidAccessTokenMap {
openidATMap[k] = &AT{
AccessToken: v.AccessToken,
ExpiresIn: v.ExpiresIn,
RefreshToken: v.RefreshToken,
Openid: v.Openid,
Scope: v.Scope,
Unionid: v.Unionid,
}
openidATMap = make(map[string]*AT)
s.openidAccessTokenMap.Range(func(k string, v *AccessToken) bool {
openidATMap[k] = &AT{
AccessToken: v.AccessToken,
ExpiresIn: v.ExpiresIn,
RefreshToken: v.RefreshToken,
Openid: v.Openid,
Scope: v.Scope,
Unionid: v.Unionid,
}
return
}
return true
})
return
}

// DelAccessToken 根据 openid 删除 map 中维护的 access_token
func (s *SDK) DelAccessToken(openid string) {
if s.openidAccessTokenMap != nil {
delete(s.openidAccessTokenMap, openid)
}
s.openidAccessTokenMap.Delete(openid)
}

// Code2AccessToken 通过 code 获取用户 access_token
Expand All @@ -123,9 +117,7 @@ func (s *SDK) Code2AccessToken(c context.Context, code string) (at *AccessToken,
}, nil)
}
if s.autoManageToken {
s.mu.Lock()
s.openidAccessTokenMap[at.Openid] = at
s.mu.Unlock()
s.openidAccessTokenMap.Store(at.Openid, at)
}
return at, nil
}
Expand Down Expand Up @@ -153,9 +145,7 @@ func (s *SDK) RefreshAccessToken(c context.Context, refreshToken string) (at *Ac
}, nil)
}
if s.autoManageToken {
s.mu.Lock()
s.openidAccessTokenMap[at.Openid] = at
s.mu.Unlock()
s.openidAccessTokenMap.Store(at.Openid, at)
}
return at, nil
}
Expand All @@ -171,9 +161,7 @@ func (s *SDK) CheckAccessToken(c context.Context, accessToken, openid string) (e
}
if ec.Errcode != Success {
if s.autoManageToken {
s.mu.Lock()
delete(s.openidAccessTokenMap, openid)
s.mu.Unlock()
s.DelAccessToken(openid)
}
err = fmt.Errorf("errcode(%d), errmsg(%s)", ec.Errcode, ec.Errmsg)
return err
Expand Down
10 changes: 4 additions & 6 deletions open/open.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"context"
"fmt"
"net/http"
"sync"
"time"

"github.com/go-pay/smap"
"github.com/go-pay/util"
"github.com/go-pay/util/js"
"github.com/go-pay/wechat-sdk"
Expand All @@ -17,13 +17,12 @@ import (
type SDK struct {
ctx context.Context
DebugSwitch wechat.DebugSwitch
mu sync.RWMutex
Appid string
Secret string
Host string
autoManageToken bool // 是否自动维护刷新 AccessToken
autoRefreshTokenInternal time.Duration // 自动刷新 token 的间隔时间
openidAccessTokenMap map[string]*AccessToken // key: openid
autoManageToken bool // 是否自动维护刷新 AccessToken
autoRefreshTokenInternal time.Duration // 自动刷新 token 的间隔时间
openidAccessTokenMap smap.Map[string, *AccessToken] // key: openid
hc *xhttp.Client
logger xlog.XLogger

Expand All @@ -49,7 +48,6 @@ func New(appid, secret string, autoManageToken bool) (o *SDK) {
}
if autoManageToken {
o.autoRefreshTokenInternal = time.Minute * 10
o.openidAccessTokenMap = make(map[string]*AccessToken)
go o.goAutoRefreshAccessTokenJob()
}
return
Expand Down
Loading

0 comments on commit d764c17

Please sign in to comment.