Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1.1.6 #7

Merged
merged 5 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion common.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ const (
DebugOff = 0
DebugOn = 1

Version = "1.1.5"
HeaderRequestID = "Request-ID"

Version = "1.1.6"
)

const (
Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
module github.com/go-pay/wechat-sdk

go 1.21

require (
github.com/go-pay/bm v0.0.4
github.com/go-pay/crypto v0.0.1
github.com/go-pay/util v0.0.2
github.com/go-pay/xhttp v0.0.2
github.com/go-pay/xlog v0.0.3
github.com/go-pay/xtime v0.0.2
)
12 changes: 12 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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/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.2 h1:goJ4f6kNY5zzdtg1Cj8oWC+Cw7bfg/qq2rJangMAb9U=
github.com/go-pay/util v0.0.2/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/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=
github.com/go-pay/xtime v0.0.2/go.mod h1:W1yRbJaSt4CSBcdAtLBQ8xajiN/Pl5hquGczUcUE9xE=
14 changes: 6 additions & 8 deletions mini/access_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"runtime"
"strconv"
"time"

"github.com/go-pay/wechat-sdk/pkg/xlog"
)

// 获取小程序全局唯一后台接口调用凭据(access_token)
Expand All @@ -25,7 +23,7 @@ func (s *SDK) getAccessToken() (err error) {

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 {
if _, err = s.DoRequestGet(s.ctx, path, at); err != nil {
return
}
if at.Errcode != Success {
Expand All @@ -45,15 +43,15 @@ func (s *SDK) goAutoRefreshAccessToken() {
if r := recover(); r != nil {
buf := make([]byte, 64<<10)
buf = buf[:runtime.Stack(buf, false)]
xlog.Errorf("mini_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf)
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 {
xlog.Errorf("get access token error, after 10s retry: %+v", err)
s.logger.Errorf("get access token error, after 10s retry: %+v", err)
continue
}
}
Expand All @@ -74,7 +72,7 @@ func (s *SDK) getStableAccessToken() (err error) {

path := "/cgi-bin/stable_token?grant_type=client_credential&appid=" + s.Appid + "&secret=" + s.Secret + "&force_refresh=false"
at := &AccessToken{}
if err = s.DoRequestGet(s.ctx, path, at); err != nil {
if _, err = s.DoRequestGet(s.ctx, path, at); err != nil {
return
}
if at.Errcode != Success {
Expand All @@ -94,15 +92,15 @@ func (s *SDK) goAutoRefreshStableAccessToken() {
if r := recover(); r != nil {
buf := make([]byte, 64<<10)
buf = buf[:runtime.Stack(buf, false)]
xlog.Errorf("mini_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf)
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.getStableAccessToken()
if err != nil {
xlog.Errorf("get access token error, after 10s retry: %+v", err)
s.logger.Errorf("get access token error, after 10s retry: %+v", err)
continue
}
}
Expand Down
19 changes: 9 additions & 10 deletions mini/customer_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import (
"context"
"fmt"

"github.com/go-pay/wechat-sdk/pkg/bmap"
"github.com/go-pay/wechat-sdk/pkg/util"
"github.com/go-pay/bm"
)

// CSMessageGetTempMedia 获取客服消息内的临时素材
Expand All @@ -26,9 +25,9 @@ func (s *SDK) CSMessageGetTempMedia(c context.Context, mediaId string) (media []
// msgType:消息类型,枚举值:mini.MsgTypeText、mini.MsgTypeImage、mini.MsgTypeLink、mini.MsgTypeMiniPage
// msgValue:对应 msgType 的value值,BodyMap key-value 格式传入
// 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/kf-mgnt/kf-message/sendCustomMessage.html
func (s *SDK) CSMessageSend(c context.Context, toUser string, msgType MsgType, msgValue bmap.BodyMap) (err error) {
func (s *SDK) CSMessageSend(c context.Context, toUser string, msgType MsgType, msgValue bm.BodyMap) (err error) {
path := "/cgi-bin/message/custom/send?access_token=" + s.accessToken
body := make(bmap.BodyMap)
body := make(bm.BodyMap)
body.Set("touser", toUser)
switch msgType {
case MsgTypeText:
Expand All @@ -45,7 +44,7 @@ func (s *SDK) CSMessageSend(c context.Context, toUser string, msgType MsgType, m
Set("text", msgValue)
}
ec := &ErrorCode{}
if err = s.doRequestPost(c, path, body, ec); err != nil {
if _, err = s.doRequestPost(c, path, body, ec); err != nil {
return err
}
if ec.Errcode != Success {
Expand All @@ -61,7 +60,7 @@ func (s *SDK) CSMessageSend(c context.Context, toUser string, msgType MsgType, m
// 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/kf-mgnt/kf-message/setTyping.html
func (s *SDK) CSMessageSetTyping(c context.Context, toUser string, typingStatus TypingStatus) (err error) {
path := "/cgi-bin/message/custom/typing?access_token=" + s.accessToken
body := make(bmap.BodyMap)
body := make(bm.BodyMap)
body.Set("touser", toUser)
switch typingStatus {
case TypingTyping:
Expand All @@ -70,7 +69,7 @@ func (s *SDK) CSMessageSetTyping(c context.Context, toUser string, typingStatus
body.Set("command", "CancelTyping")
}
ec := &ErrorCode{}
if err = s.doRequestPost(c, path, body, ec); err != nil {
if _, err = s.doRequestPost(c, path, body, ec); err != nil {
return err
}
if ec.Errcode != Success {
Expand All @@ -83,13 +82,13 @@ func (s *SDK) CSMessageSetTyping(c context.Context, toUser string, typingStatus
// 注意:errcode = 0 为成功
// 注意:目前仅支持图片,用于发送客服消息或被动回复用户消息。
// 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/kf-mgnt/kf-message/uploadTempMedia.html
func (s *SDK) CSMessageUploadTempMedia(c context.Context, img *util.File) (media *UploadTempMedia, err error) {
func (s *SDK) CSMessageUploadTempMedia(c context.Context, img *bm.File) (media *UploadTempMedia, err error) {
path := "/cgi-bin/media/upload?access_token=" + s.accessToken
body := make(bmap.BodyMap)
body := make(bm.BodyMap)
body.Set("type", "image").
SetFormFile("media", img)
media = &UploadTempMedia{}
if err = s.doRequestPostFile(c, path, body, media); err != nil {
if _, err = s.doRequestPostFile(c, path, body, media); err != nil {
return nil, err
}
if media.Errcode != Success {
Expand Down
2 changes: 1 addition & 1 deletion mini/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func (s *SDK) Code2Session(c context.Context, wxCode string) (session *Code2Session, err error) {
path := "/sns/jscode2session?appid=" + s.Appid + "&secret=" + s.Secret + "&js_code=" + wxCode + "&grant_type=authorization_code"
session = &Code2Session{}
if err = s.doRequestGet(c, path, session); err != nil {
if _, err = s.doRequestGet(c, path, session); err != nil {
return nil, err
}
if session.Errcode != Success {
Expand Down
58 changes: 39 additions & 19 deletions mini/mini.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package mini

import (
"context"
"encoding/json"
"fmt"
"net/http"
"time"

"github.com/go-pay/util"
"github.com/go-pay/util/js"
"github.com/go-pay/wechat-sdk"
"github.com/go-pay/wechat-sdk/pkg/util"
"github.com/go-pay/wechat-sdk/pkg/xhttp"
"github.com/go-pay/wechat-sdk/pkg/xlog"
"github.com/go-pay/xhttp"
"github.com/go-pay/xlog"
)

type SDK struct {
Expand All @@ -20,6 +21,8 @@ type SDK struct {
Host string
accessToken string
RefreshInternal time.Duration
hc *xhttp.Client
logger xlog.XLogger

callback func(appid, accessToken string, expireIn int, err error)
}
Expand All @@ -29,12 +32,16 @@ type SDK struct {
// Secret:appSecret
// autoManageToken:是否自动获取并自动维护刷新 AccessToken,默认使用稳定版接口且force_refresh=false
func New(appid, secret string, autoManageToken bool) (m *SDK, err error) {
logger := xlog.NewLogger()
logger.SetLevel(xlog.DebugLevel)
m = &SDK{
ctx: context.Background(),
DebugSwitch: wechat.DebugOff,
Appid: appid,
Secret: secret,
Host: HostDefault,
hc: xhttp.NewClient(),
logger: logger,
}
if autoManageToken {
if err = m.getStableAccessToken(); err != nil {
Expand All @@ -45,35 +52,48 @@ func New(appid, secret string, autoManageToken bool) (m *SDK, err error) {
return
}

func (s *SDK) DoRequestGet(c context.Context, path string, ptr any) (err error) {
// SetHttpClient 设置自定义的xhttp.Client
func (s *SDK) SetHttpClient(client *xhttp.Client) {
if client != nil {
s.hc = client
}
}

func (s *SDK) SetLogger(logger xlog.XLogger) {
if logger != nil {
s.logger = logger
}
}

func (s *SDK) DoRequestGet(c context.Context, path string, ptr any) (res *http.Response, err error) {
uri := s.Host + path
httpClient := xhttp.NewClient()
if s.DebugSwitch == wechat.DebugOn {
xlog.Debugf("Wechat_SDK_URI: %s", uri)
s.logger.Debugf("Wechat_SDK_URI: %s", uri)
}
httpClient.Header.Add(xhttp.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
res, bs, err := httpClient.Get(uri).EndBytes(c)
req := s.hc.Req()
req.Header.Add(wechat.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
res, bs, err := req.Get(uri).EndBytes(c)
if err != nil {
return fmt.Errorf("http.request(GET, %s), status_code:%d, err:%w", uri, res.StatusCode, err)
return nil, fmt.Errorf("http.request(GET, %s), err:%w", uri, err)
}
if s.DebugSwitch == wechat.DebugOn {
xlog.Debugf("Wechat_SDK_Response: [%d] -> %s", res.StatusCode, string(bs))
s.logger.Debugf("Wechat_SDK_Response: [%d] -> %s", res.StatusCode, string(bs))
}
if err = json.Unmarshal(bs, ptr); err != nil {
return fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), ptr, err)
if err = js.UnmarshalBytes(bs, ptr); err != nil {
return res, fmt.Errorf("js.UnmarshalBytes(%s, %+v):%w", string(bs), ptr, err)
}
return
}

func doRequestGet(c context.Context, uri string, ptr any) (err error) {
httpClient := xhttp.NewClient()
httpClient.Header.Add(xhttp.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
res, bs, err := httpClient.Get(uri).EndBytes(c)
req := xhttp.NewClient().Req()
req.Header.Add(wechat.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix()))
_, bs, err := req.Get(uri).EndBytes(c)
if err != nil {
return fmt.Errorf("http.request(GET, %s), status_code:%d, err:%w", uri, res.StatusCode, err)
return fmt.Errorf("http.request(GET, %s), err:%w", uri, err)
}
if err = json.Unmarshal(bs, ptr); err != nil {
return fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), ptr, err)
if err = js.UnmarshalBytes(bs, ptr); err != nil {
return fmt.Errorf("js.UnmarshalBytes(%s, %+v):%w", string(bs), ptr, err)
}
return
}
11 changes: 6 additions & 5 deletions mini/mini_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"os"
"testing"

"github.com/go-pay/bm"
"github.com/go-pay/wechat-sdk"
"github.com/go-pay/wechat-sdk/pkg/bmap"
"github.com/go-pay/wechat-sdk/pkg/xlog"
"github.com/go-pay/xlog"
)

var (
Expand All @@ -20,6 +20,7 @@ var (
)

func TestMain(m *testing.M) {
xlog.SetLevel(xlog.DebugLevel)
// 初始化微信小程序 SDK
// Appid:Appid
// Secret:appSecret
Expand Down Expand Up @@ -62,10 +63,10 @@ func TestCode2Session(t *testing.T) {
}

func TestUniformMessageSend(t *testing.T) {
body := make(bmap.BodyMap)
bb := make(bmap.BodyMap)
body := make(bm.BodyMap)
bb := make(bm.BodyMap)
bb.Set("appid", "APPID").
Set("template_id", "TEMPLATE_ID").SetBodyMap("miniprogram", func(b bmap.BodyMap) {
Set("template_id", "TEMPLATE_ID").SetBodyMap("miniprogram", func(b bm.BodyMap) {
b.Set("appid", "xiaochengxuappid12345").Set("pagepath", "index?foo=bar")
})

Expand Down
2 changes: 1 addition & 1 deletion mini/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package mini

import "github.com/go-pay/wechat-sdk/pkg/xtime"
import "github.com/go-pay/xtime"

const (
Success = 0
Expand Down
25 changes: 8 additions & 17 deletions mini/open_data.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
package mini

import (
"crypto/aes"
"crypto/cipher"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"reflect"

xaes "github.com/go-pay/wechat-sdk/pkg/aes"
"github.com/go-pay/wechat-sdk/pkg/util"
"github.com/go-pay/crypto/aes"
"github.com/go-pay/util"
"github.com/go-pay/util/js"
)

// VerifyDecryptOpenData 数据签名校验
Expand All @@ -39,8 +37,6 @@ func (s *SDK) DecryptOpenData(encryptedData, iv, sessionKey string, ptr any) (er
}
var (
cipherText, aesKey, ivKey, plainText []byte
block cipher.Block
blockMode cipher.BlockMode
)
beanValue := reflect.ValueOf(ptr)
if beanValue.Kind() != reflect.Ptr {
Expand All @@ -55,17 +51,12 @@ func (s *SDK) DecryptOpenData(encryptedData, iv, sessionKey string, ptr any) (er
if len(cipherText)%len(aesKey) != 0 {
return errors.New("encryptedData error")
}
if block, err = aes.NewCipher(aesKey); err != nil {
return fmt.Errorf("aes.NewCipher(),error(%w)", err)
plainText, err = aes.CBCDecrypt(cipherText, aesKey, ivKey)
if err != nil {
return fmt.Errorf("aes.CBCDecrypt(),err(%w)", err)
}
blockMode = cipher.NewCBCDecrypter(block, ivKey)
plainText = make([]byte, len(cipherText))
blockMode.CryptBlocks(plainText, cipherText)
if len(plainText) > 0 {
plainText = xaes.PKCS7UnPadding(plainText)
}
if err = json.Unmarshal(plainText, ptr); err != nil {
return fmt.Errorf("json.Unmarshal(%s, %+v),error(%w)", string(plainText), ptr, err)
if err = js.UnmarshalBytes(plainText, ptr); err != nil {
return fmt.Errorf("js.UnmarshalBytes(%s, %+v),error(%w)", string(plainText), ptr, err)
}
return
}
Loading