From ddb96890e47f9932763c1f2800d1d31477ef03f3 Mon Sep 17 00:00:00 2001 From: Jerry <85411418@qq.com> Date: Sat, 3 Aug 2024 00:22:09 +0800 Subject: [PATCH] V1.1.6 (#7) * v1.1.6 --- common.go | 4 +- go.mod | 9 + go.sum | 12 ++ mini/access_token.go | 14 +- mini/customer_service.go | 19 +- mini/login.go | 2 +- mini/mini.go | 58 ++++-- mini/mini_test.go | 11 +- mini/model.go | 2 +- mini/open_data.go | 25 +-- mini/request.go | 79 ++++---- mini/uniform_message.go | 8 +- mini/user_info.go | 22 +-- open/access_token.go | 12 +- open/open.go | 46 +++-- open/open_test.go | 3 +- open/user_info.go | 2 +- pkg/aes/aes_cbc_decrypt.go | 47 ----- pkg/aes/aes_cbc_encrypt.go | 43 ----- pkg/aes/aes_gcm_decrypt.go | 27 --- pkg/aes/aes_gcm_encrypt.go | 29 --- pkg/aes/aes_test.go | 72 -------- pkg/aes/pkcs_padding.go | 42 ----- pkg/bmap/body_map.go | 242 ------------------------- pkg/bmap/body_map_test.go | 146 --------------- pkg/util/common.go | 10 -- pkg/util/convert.go | 95 ---------- pkg/util/convert_test.go | 15 -- pkg/util/random.go | 42 ----- pkg/util/string.go | 18 -- pkg/util/util_test.go | 16 -- pkg/xhttp/client.go | 359 ------------------------------------- pkg/xhttp/client_test.go | 69 ------- pkg/xhttp/model.go | 28 --- pkg/xlog/color.go | 112 ------------ pkg/xlog/debug_logger.go | 41 ----- pkg/xlog/error_logger.go | 41 ----- pkg/xlog/info_logger.go | 41 ----- pkg/xlog/log.go | 71 -------- pkg/xlog/log_test.go | 20 --- pkg/xlog/warn_logger.go | 41 ----- pkg/xtime/constants.go | 8 - pkg/xtime/data_time.go | 99 ---------- pkg/xtime/parse_format.go | 107 ----------- pkg/xtime/xtime.go | 78 -------- pkg/xtime/xtime_test.go | 38 ---- public/access_token.go | 8 +- public/account_manage.go | 14 +- public/model.go | 2 +- public/public.go | 48 +++-- public/public_test.go | 17 +- public/request.go | 93 +++------- public/sign.go | 9 +- public/sign_test.go | 2 +- public/ticket.go | 4 +- public/user_manage.go | 38 ++-- release_note.txt | 4 + 57 files changed, 300 insertions(+), 2264 deletions(-) delete mode 100644 pkg/aes/aes_cbc_decrypt.go delete mode 100644 pkg/aes/aes_cbc_encrypt.go delete mode 100644 pkg/aes/aes_gcm_decrypt.go delete mode 100644 pkg/aes/aes_gcm_encrypt.go delete mode 100644 pkg/aes/aes_test.go delete mode 100644 pkg/aes/pkcs_padding.go delete mode 100644 pkg/bmap/body_map.go delete mode 100644 pkg/bmap/body_map_test.go delete mode 100644 pkg/util/common.go delete mode 100644 pkg/util/convert.go delete mode 100644 pkg/util/convert_test.go delete mode 100644 pkg/util/random.go delete mode 100644 pkg/util/string.go delete mode 100644 pkg/util/util_test.go delete mode 100644 pkg/xhttp/client.go delete mode 100644 pkg/xhttp/client_test.go delete mode 100644 pkg/xhttp/model.go delete mode 100644 pkg/xlog/color.go delete mode 100644 pkg/xlog/debug_logger.go delete mode 100644 pkg/xlog/error_logger.go delete mode 100644 pkg/xlog/info_logger.go delete mode 100644 pkg/xlog/log.go delete mode 100644 pkg/xlog/log_test.go delete mode 100644 pkg/xlog/warn_logger.go delete mode 100644 pkg/xtime/constants.go delete mode 100644 pkg/xtime/data_time.go delete mode 100644 pkg/xtime/parse_format.go delete mode 100644 pkg/xtime/xtime.go delete mode 100644 pkg/xtime/xtime_test.go diff --git a/common.go b/common.go index 7e389c3..c2d199a 100644 --- a/common.go +++ b/common.go @@ -10,7 +10,9 @@ const ( DebugOff = 0 DebugOn = 1 - Version = "1.1.5" + HeaderRequestID = "Request-ID" + + Version = "1.1.6" ) const ( diff --git a/go.mod b/go.mod index 77cf17b..eaa0fce 100644 --- a/go.mod +++ b/go.mod @@ -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 +) diff --git a/go.sum b/go.sum index e69de29..ae3aecd 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/mini/access_token.go b/mini/access_token.go index 52ddf30..8b7c87e 100644 --- a/mini/access_token.go +++ b/mini/access_token.go @@ -6,8 +6,6 @@ import ( "runtime" "strconv" "time" - - "github.com/go-pay/wechat-sdk/pkg/xlog" ) // 获取小程序全局唯一后台接口调用凭据(access_token) @@ -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 { @@ -45,7 +43,7 @@ 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 { @@ -53,7 +51,7 @@ func (s *SDK) goAutoRefreshAccessToken() { 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 } } @@ -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 { @@ -94,7 +92,7 @@ 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 { @@ -102,7 +100,7 @@ func (s *SDK) goAutoRefreshStableAccessToken() { 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 } } diff --git a/mini/customer_service.go b/mini/customer_service.go index a130ef7..5b013e7 100644 --- a/mini/customer_service.go +++ b/mini/customer_service.go @@ -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 获取客服消息内的临时素材 @@ -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: @@ -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 { @@ -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: @@ -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 { @@ -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 { diff --git a/mini/login.go b/mini/login.go index d133e48..4352e4a 100644 --- a/mini/login.go +++ b/mini/login.go @@ -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 { diff --git a/mini/mini.go b/mini/mini.go index 957df31..e0297e7 100644 --- a/mini/mini.go +++ b/mini/mini.go @@ -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 { @@ -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) } @@ -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 { @@ -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 } diff --git a/mini/mini_test.go b/mini/mini_test.go index 3a09284..7f9fa8f 100644 --- a/mini/mini_test.go +++ b/mini/mini_test.go @@ -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 ( @@ -20,6 +20,7 @@ var ( ) func TestMain(m *testing.M) { + xlog.SetLevel(xlog.DebugLevel) // 初始化微信小程序 SDK // Appid:Appid // Secret:appSecret @@ -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") }) diff --git a/mini/model.go b/mini/model.go index 60624d5..d330dce 100644 --- a/mini/model.go +++ b/mini/model.go @@ -1,6 +1,6 @@ package mini -import "github.com/go-pay/wechat-sdk/pkg/xtime" +import "github.com/go-pay/xtime" const ( Success = 0 diff --git a/mini/open_data.go b/mini/open_data.go index e26f8d3..9cac0d0 100644 --- a/mini/open_data.go +++ b/mini/open_data.go @@ -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 数据签名校验 @@ -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 { @@ -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 } diff --git a/mini/request.go b/mini/request.go index 9198e5d..cac6840 100644 --- a/mini/request.go +++ b/mini/request.go @@ -4,48 +4,49 @@ import ( "context" "encoding/json" "fmt" + "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" - "github.com/go-pay/wechat-sdk/pkg/bmap" - "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" ) -func (s *SDK) doRequestGet(c context.Context, path string, ptr any) (err error) { +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_Mini_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Mini_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_Mini_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Mini_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 + return res, nil } func (s *SDK) doRequestGetByte(c context.Context, path string) (bs []byte, err error) { uri := s.Host + path - httpClient := xhttp.NewClient() if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Mini_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Mini_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 nil, 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_Mini_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Mini_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) } ec := &ErrorCode{} // 如果解析成功,说明获取buffer文件失败 @@ -55,43 +56,43 @@ func (s *SDK) doRequestGetByte(c context.Context, path string) (bs []byte, err e return } -func (s *SDK) doRequestPost(c context.Context, path string, body bmap.BodyMap, ptr any) (err error) { +func (s *SDK) doRequestPost(c context.Context, path string, body bm.BodyMap, ptr any) (res *http.Response, err error) { uri := s.Host + path - httpClient := xhttp.NewClient() if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Mini_SDK_URI: %s", uri) - xlog.Debugf("Wechat_Mini_SDK_RequestBody: %s", body.JsonBody()) + s.logger.Debugf("Wechat_Mini_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Mini_SDK_RequestBody: %s", body.JsonBody()) } - httpClient.Header.Add(xhttp.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix())) - res, bs, err := httpClient.Post(uri).SendBodyMap(body).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.Post(uri).SendBodyMap(body).EndBytes(c) if err != nil { - return fmt.Errorf("http.request(POST, %s), status_code:%d, err:%w", uri, res.StatusCode, err) + return nil, fmt.Errorf("http.request(POST, %s), err:%w", uri, err) } if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Mini_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Mini_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 (s *SDK) doRequestPostFile(ctx context.Context, path string, body bmap.BodyMap, ptr any) (err error) { +func (s *SDK) doRequestPostFile(ctx context.Context, path string, body bm.BodyMap, ptr any) (res *http.Response, err error) { uri := s.Host + path - httpClient := xhttp.NewClient() if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Mini_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Mini_SDK_URI: %s", uri) } - httpClient.Header.Add(xhttp.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix())) - res, bs, err := httpClient.Type(xhttp.TypeMultipartFormData).Post(uri).SendMultipartBodyMap(body).EndBytes(ctx) + req := s.hc.Req(xhttp.TypeMultipartFormData) + req.Header.Add(wechat.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix())) + res, bs, err := req.Post(uri).SendMultipartBodyMap(body).EndBytes(ctx) if err != nil { - return fmt.Errorf("http.request(POST, %s), status_code:%d, err:%w", uri, res.StatusCode, err) + return nil, fmt.Errorf("http.request(POST, %s), err:%w", uri, err) } if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Mini_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Mini_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 } diff --git a/mini/uniform_message.go b/mini/uniform_message.go index f7b7fe8..b76e11b 100644 --- a/mini/uniform_message.go +++ b/mini/uniform_message.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/go-pay/wechat-sdk/pkg/bmap" + "github.com/go-pay/bm" ) // UniformMessageSend 发送统一服务消息 @@ -12,13 +12,13 @@ import ( // toUser:用户openid,可以是小程序的openid,也可以是mp_template_msg.appid对应的公众号的openid // mpMsg:对应 mp_template_msg 的value值,BodyMap key-value 格式传入 // 文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/uniform-message/uniformMessage.send.html -func (s *SDK) UniformMessageSend(c context.Context, toUser string, mpMsg bmap.BodyMap) (err error) { +func (s *SDK) UniformMessageSend(c context.Context, toUser string, mpMsg bm.BodyMap) (err error) { path := "/cgi-bin/message/wxopen/template/uniform_send?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("touser", toUser) body.Set("mp_template_msg", mpMsg) 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 { diff --git a/mini/user_info.go b/mini/user_info.go index 6f3c51b..79f21b2 100644 --- a/mini/user_info.go +++ b/mini/user_info.go @@ -6,7 +6,7 @@ import ( "encoding/hex" "fmt" - "github.com/go-pay/wechat-sdk/pkg/bmap" + "github.com/go-pay/bm" ) // GetPluginOpenPid 获取插件用户openpid @@ -16,9 +16,9 @@ import ( func (s *SDK) GetPluginOpenPid(c context.Context, code string) (openpid *PluginOpenPid, err error) { path := "/wxa/getpluginopenpid?access_token=" + s.accessToken openpid = &PluginOpenPid{} - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("code", code) - if err = s.doRequestPost(c, path, body, openpid); err != nil { + if _, err = s.doRequestPost(c, path, body, openpid); err != nil { return nil, err } if openpid.Errcode != Success { @@ -35,7 +35,7 @@ func (s *SDK) GetPluginOpenPid(c context.Context, code string) (openpid *PluginO func (s *SDK) GetPaidUnionid(c context.Context, openid, transactionId string) (unionid *PaidUnionId, err error) { path := "/wxa/getpaidunionid?access_token=" + s.accessToken + "&openid=" + openid + "&transaction_id=" + transactionId unionid = &PaidUnionId{} - if err = s.doRequestGet(c, path, unionid); err != nil { + if _, err = s.doRequestGet(c, path, unionid); err != nil { return nil, err } if unionid.Errcode != Success { @@ -53,7 +53,7 @@ func (s *SDK) GetPaidUnionid(c context.Context, openid, transactionId string) (u func (s *SDK) GetPaidUnionidByTradeNo(c context.Context, openid, mchid, tradeNo string) (unionid *PaidUnionId, err error) { path := "/wxa/getpaidunionid?access_token=" + s.accessToken + "&openid=" + openid + "&mch_id=" + mchid + "&out_trade_no=" + tradeNo unionid = &PaidUnionId{} - if err = s.doRequestGet(c, path, unionid); err != nil { + if _, err = s.doRequestGet(c, path, unionid); err != nil { return nil, err } if unionid.Errcode != Success { @@ -71,10 +71,10 @@ func (s *SDK) CheckEncryptedData(c context.Context, encryptedData string) (resul path := "/wxa/business/checkencryptedmsg?access_token=" + s.accessToken h := sha256.New() h.Write([]byte(encryptedData)) - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("encrypted_msg_hash", hex.EncodeToString(h.Sum(nil))) result = &CheckEncryptedResult{} - if err = s.doRequestPost(c, path, body, result); err != nil { + if _, err = s.doRequestPost(c, path, body, result); err != nil { return nil, err } if result.Errcode != Success { @@ -90,12 +90,12 @@ func (s *SDK) CheckEncryptedData(c context.Context, encryptedData string) (resul // 文档:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/internet/getUserEncryptKey.html func (s *SDK) GetUserEncryptKey(c context.Context, openid, signature, sigMethod string) (uek *UserEncryptKey, err error) { path := "/wxa/business/getuserencryptkey?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("openid", openid). Set("signature", signature). Set("sig_method", sigMethod) uek = &UserEncryptKey{} - if err = s.doRequestPost(c, path, body, uek); err != nil { + if _, err = s.doRequestPost(c, path, body, uek); err != nil { return nil, err } if uek.Errcode != Success { @@ -111,9 +111,9 @@ func (s *SDK) GetUserEncryptKey(c context.Context, openid, signature, sigMethod func (s *SDK) GetPhoneNumber(c context.Context, code string) (pn *PhoneNumberRsp, err error) { path := "/wxa/business/getuserphonenumber?access_token=" + s.accessToken pn = &PhoneNumberRsp{} - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("code", code) - if err = s.doRequestPost(c, path, body, pn); err != nil { + if _, err = s.doRequestPost(c, path, body, pn); err != nil { return nil, err } if pn.Errcode != Success { diff --git a/open/access_token.go b/open/access_token.go index 5cbeabf..2bcaa02 100644 --- a/open/access_token.go +++ b/open/access_token.go @@ -5,8 +5,6 @@ import ( "fmt" "runtime" "time" - - "github.com/go-pay/wechat-sdk/pkg/xlog" ) func (s *SDK) refreshAccessToken(openid, refreshToken string) { @@ -15,7 +13,7 @@ func (s *SDK) refreshAccessToken(openid, refreshToken string) { at = &AccessToken{} err error ) - if err = s.DoRequestGet(s.ctx, path, at); err != nil { + if _, err = s.DoRequestGet(s.ctx, path, at); err != nil { if s.callback != nil { go s.callback(nil, fmt.Errorf("openid[%s],refresh_token[%s] refresh access token failed: %w", openid, refreshToken, err)) } @@ -47,7 +45,7 @@ func (s *SDK) goAutoRefreshAccessTokenJob() { if r := recover(); r != nil { buf := make([]byte, 64<<10) buf = buf[:runtime.Stack(buf, false)] - xlog.Errorf("open_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf) + s.logger.Errorf("open_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf) } }() for { @@ -105,7 +103,7 @@ func (s *SDK) DelAccessToken(openid string) { func (s *SDK) Code2AccessToken(c context.Context, code string) (at *AccessToken, err error) { path := "/sns/oauth2/access_token?grant_type=authorization_code&appid=" + s.Appid + "&secret=" + s.Secret + "&code=" + code at = &AccessToken{} - if err = s.DoRequestGet(c, path, at); err != nil { + if _, err = s.DoRequestGet(c, path, at); err != nil { return nil, err } if at.Errcode != Success { @@ -135,7 +133,7 @@ func (s *SDK) Code2AccessToken(c context.Context, code string) (at *AccessToken, func (s *SDK) RefreshAccessToken(c context.Context, refreshToken string) (at *AccessToken, err error) { path := "/sns/oauth2/refresh_token?grant_type=refresh_token&appid=" + s.Appid + "&refresh_token=" + refreshToken at = &AccessToken{} - if err = s.DoRequestGet(s.ctx, path, at); err != nil { + if _, err = s.DoRequestGet(s.ctx, path, at); err != nil { return nil, err } if at.Errcode != Success { @@ -166,7 +164,7 @@ func (s *SDK) RefreshAccessToken(c context.Context, refreshToken string) (at *Ac func (s *SDK) CheckAccessToken(c context.Context, accessToken, openid string) (err error) { path := "/sns/auth?access_token=" + accessToken + "&openid=" + openid ec := &ErrorCode{} - if err = s.DoRequestGet(c, path, ec); err != nil { + if _, err = s.DoRequestGet(c, path, ec); err != nil { return err } if ec.Errcode != Success { diff --git a/open/open.go b/open/open.go index ade52ae..253572f 100644 --- a/open/open.go +++ b/open/open.go @@ -2,15 +2,16 @@ package open import ( "context" - "encoding/json" "fmt" + "net/http" "sync" "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 { @@ -23,6 +24,8 @@ type SDK struct { autoManageToken bool // 是否自动维护刷新 AccessToken autoRefreshTokenInternal time.Duration // 自动刷新 token 的间隔时间 openidAccessTokenMap map[string]*AccessToken // key: openid + hc *xhttp.Client + logger xlog.XLogger callback func(at *AT, err error) } @@ -32,6 +35,8 @@ type SDK struct { // Secret:appSecret // autoManageToken:是否自动维护刷新 AccessToken(用户量较少时推荐使用,默认10分钟轮询检测一次,发现有效期小于1.5倍轮询时间时,自动刷新) func New(appid, secret string, autoManageToken bool) (o *SDK) { + logger := xlog.NewLogger() + logger.SetLevel(xlog.DebugLevel) o = &SDK{ ctx: context.Background(), DebugSwitch: wechat.DebugOff, @@ -39,6 +44,8 @@ func New(appid, secret string, autoManageToken bool) (o *SDK) { Appid: appid, Secret: secret, autoManageToken: autoManageToken, + hc: xhttp.NewClient(), + logger: logger, } if autoManageToken { o.autoRefreshTokenInternal = time.Minute * 10 @@ -48,22 +55,35 @@ func New(appid, secret string, autoManageToken bool) (o *SDK) { 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_Open_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Open_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_Open_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Open_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 } diff --git a/open/open_test.go b/open/open_test.go index fbe5731..42deeb0 100644 --- a/open/open_test.go +++ b/open/open_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/go-pay/wechat-sdk" - "github.com/go-pay/wechat-sdk/pkg/xlog" + "github.com/go-pay/xlog" ) var ( @@ -18,6 +18,7 @@ var ( ) func TestMain(m *testing.M) { + xlog.SetLevel(xlog.DebugLevel) // New 初始化微信开放平台 SDK // Appid:Appid // Secret:appSecret diff --git a/open/user_info.go b/open/user_info.go index dd0f6d7..074f93e 100644 --- a/open/user_info.go +++ b/open/user_info.go @@ -16,7 +16,7 @@ func (s *SDK) UserInfo(c context.Context, accessToken, openid, lan string) (ui * } path := "/sns/userinfo?access_token=" + accessToken + "&openid=" + openid + "&lang=" + lan ui = &UserInfo{} - if err = s.DoRequestGet(c, path, ui); err != nil { + if _, err = s.DoRequestGet(c, path, ui); err != nil { return } if ui.Errcode != Success { diff --git a/pkg/aes/aes_cbc_decrypt.go b/pkg/aes/aes_cbc_decrypt.go deleted file mode 100644 index a250201..0000000 --- a/pkg/aes/aes_cbc_decrypt.go +++ /dev/null @@ -1,47 +0,0 @@ -package aes - -import ( - "crypto/aes" - "crypto/cipher" - "errors" -) - -// 解密数据的Bytes数组 -func CBCDecryptData(secretData, key []byte) ([]byte, error) { - return decrypt(secretData, key) -} - -// 解密数据的Bytes数组 -func CBCDecryptIvData(secretData, key, iv []byte) ([]byte, error) { - return decryptIv(secretData, key, iv) -} - -func decrypt(secretData, key []byte) (originByte []byte, err error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - blockSize := block.BlockSize() - blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) - originByte = make([]byte, len(secretData)) - blockMode.CryptBlocks(originByte, secretData) - if len(originByte) == 0 { - return nil, errors.New("blockMode.CryptBlocks error") - } - return PKCS7UnPadding(originByte), nil -} - -func decryptIv(secretData, key, iv []byte) (originByte []byte, err error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - blockMode := cipher.NewCBCDecrypter(block, iv[:block.BlockSize()]) - - originByte = make([]byte, len(secretData)) - blockMode.CryptBlocks(originByte, secretData) - if len(originByte) == 0 { - return nil, errors.New("blockMode.CryptBlocks error") - } - return PKCS7UnPadding(originByte), nil -} diff --git a/pkg/aes/aes_cbc_encrypt.go b/pkg/aes/aes_cbc_encrypt.go deleted file mode 100644 index ce83618..0000000 --- a/pkg/aes/aes_cbc_encrypt.go +++ /dev/null @@ -1,43 +0,0 @@ -package aes - -import ( - "crypto/aes" - "crypto/cipher" -) - -// 加密后的Bytes数组 -func CBCEncryptData(originData, key []byte) ([]byte, error) { - return encrypt(originData, key) -} - -// 加密后的Bytes数组 -func CBCEncryptIvData(originData, key, iv []byte) ([]byte, error) { - return encryptIv(originData, key, iv) -} - -func encrypt(originData, key []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - blockSize := block.BlockSize() - blockMode := cipher.NewCBCEncrypter(block, key[:blockSize]) - - originData = PKCS7Padding(originData, blockSize) - secretData := make([]byte, len(originData)) - blockMode.CryptBlocks(secretData, originData) - return secretData, nil -} - -func encryptIv(originData, key, iv []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - blockMode := cipher.NewCBCEncrypter(block, iv[:block.BlockSize()]) - - originData = PKCS7Padding(originData, block.BlockSize()) - secretData := make([]byte, len(originData)) - blockMode.CryptBlocks(secretData, originData) - return secretData, nil -} diff --git a/pkg/aes/aes_gcm_decrypt.go b/pkg/aes/aes_gcm_decrypt.go deleted file mode 100644 index aa5c569..0000000 --- a/pkg/aes/aes_gcm_decrypt.go +++ /dev/null @@ -1,27 +0,0 @@ -package aes - -import ( - "crypto/aes" - "crypto/cipher" - "fmt" -) - -func GCMDecrypt(cipherText, nonce, additional, key []byte) ([]byte, error) { - return gcmDecrypt(cipherText, nonce, additional, key) -} - -func gcmDecrypt(secretData, nonce, additional, key []byte) ([]byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, err - } - gcm, err := cipher.NewGCM(block) - if err != nil { - return nil, fmt.Errorf("cipher.NewGCM(),error:%w", err) - } - originByte, err := gcm.Open(nil, nonce, secretData, additional) - if err != nil { - return nil, err - } - return originByte, nil -} diff --git a/pkg/aes/aes_gcm_encrypt.go b/pkg/aes/aes_gcm_encrypt.go deleted file mode 100644 index b18a590..0000000 --- a/pkg/aes/aes_gcm_encrypt.go +++ /dev/null @@ -1,29 +0,0 @@ -package aes - -import ( - "crypto/aes" - "crypto/cipher" - "fmt" - - "github.com/go-pay/wechat-sdk/pkg/util" -) - -func GCMEncrypt(originText, additional, key []byte) (nonce []byte, cipherText []byte, err error) { - return gcmEncrypt(originText, additional, key) -} - -func gcmEncrypt(originText, additional, key []byte) ([]byte, []byte, error) { - block, err := aes.NewCipher(key) - if err != nil { - return nil, nil, err - } - nonce := []byte(util.RandomString(12)) - gcm, err := cipher.NewGCM(block) - if err != nil { - return nil, nil, fmt.Errorf("cipher.NewGCM(),error:%w", err) - } - - cipherBytes := gcm.Seal(nil, nonce, originText, additional) - - return nonce, cipherBytes, nil -} diff --git a/pkg/aes/aes_test.go b/pkg/aes/aes_test.go deleted file mode 100644 index 607b178..0000000 --- a/pkg/aes/aes_test.go +++ /dev/null @@ -1,72 +0,0 @@ -package aes - -import ( - "encoding/base64" - "testing" - - "github.com/go-pay/wechat-sdk/pkg/xlog" -) - -var ( - secretKey = "GYBh3Rmey7nNzR/NpV0vAw==" - iv = "JR3unO2glQuMhUx3" -) - -func TestAesCBCEncryptDecrypt(t *testing.T) { - originData := "www.gopay.ink" - xlog.Debug("originData:", originData) - encryptData, err := CBCEncryptData([]byte(originData), []byte(secretKey)) - if err != nil { - xlog.Error("AesCBCEncryptToString:", err) - return - } - xlog.Debug("encryptData:", string(encryptData)) - origin, err := CBCDecryptData(encryptData, []byte(secretKey)) - if err != nil { - xlog.Error("AesDecryptToBytes:", err) - return - } - xlog.Debug("origin:", string(origin)) -} - -func TestAesCBCEncryptDecryptIv(t *testing.T) { - originData := "www.gopay.ink" - xlog.Debug("originData:", originData) - encryptData, err := CBCEncryptIvData([]byte(originData), []byte(secretKey), []byte(iv)) - if err != nil { - xlog.Error("CBCEncryptIvData:", err) - return - } - xlog.Debug("encryptData:", string(encryptData)) - origin, err := CBCDecryptIvData(encryptData, []byte(secretKey), []byte(iv)) - if err != nil { - xlog.Error("CBCDecryptIvData:", err) - return - } - xlog.Debug("origin:", string(origin)) -} - -func TestEncryptGCM(t *testing.T) { - data := `我是要加密的数据` - additional := "transaction" - apiV3key := "Cj5xC9RXf0GFCKWeD9PyY1ZWLgionbvx" - xlog.Debug("原始数据:", data) - // 加密 - nonce, ciphertext, err := GCMEncrypt([]byte(data), []byte(additional), []byte(apiV3key)) - if err != nil { - xlog.Error(err) - return - } - encryptText := base64.StdEncoding.EncodeToString(ciphertext) - xlog.Debug("加密后:", encryptText) - xlog.Debug("nonce:", string(nonce)) - - // 解密 - cipherBytes, _ := base64.StdEncoding.DecodeString(encryptText) - decryptBytes, err := GCMDecrypt(cipherBytes, nonce, []byte(additional), []byte(apiV3key)) - if err != nil { - xlog.Error(err) - return - } - xlog.Debug("解密后:", string(decryptBytes)) -} diff --git a/pkg/aes/pkcs_padding.go b/pkg/aes/pkcs_padding.go deleted file mode 100644 index 7bcc8f6..0000000 --- a/pkg/aes/pkcs_padding.go +++ /dev/null @@ -1,42 +0,0 @@ -package aes - -import "bytes" - -// 加密填充模式(添加补全码) PKCS5Padding -// 加密时,如果加密bytes的length不是blockSize的整数倍,需要在最后面添加填充byte -func PKCS5Padding(ciphertext []byte, blockSize int) []byte { - paddingCount := blockSize - len(ciphertext)%blockSize //需要padding的数目 - paddingBytes := []byte{byte(paddingCount)} - padtext := bytes.Repeat(paddingBytes, paddingCount) //生成填充的文本 - return append(ciphertext, padtext...) -} - -// 解密填充模式(去除补全码) PKCS5UnPadding -// 解密时,需要在最后面去掉加密时添加的填充byte -func PKCS5UnPadding(origData []byte) []byte { - length := len(origData) - unpadding := int(origData[length-1]) //找到Byte数组最后的填充byte - return origData[:(length - unpadding)] //只截取返回有效数字内的byte数组 -} - -// 加密填充模式(添加补全码) PKCS5Padding -// 加密时,如果加密bytes的length不是blockSize的整数倍,需要在最后面添加填充byte -func PKCS7Padding(ciphertext []byte, blockSize int) []byte { - paddingCount := blockSize - len(ciphertext)%blockSize //需要padding的数目 - paddingBytes := []byte{byte(paddingCount)} - padtext := bytes.Repeat(paddingBytes, paddingCount) //生成填充的文本 - return append(ciphertext, padtext...) -} - -// 解密填充模式(去除补全码) PKCS7UnPadding -// 解密时,需要在最后面去掉加密时添加的填充byte -func PKCS7UnPadding(origData []byte) (bs []byte) { - length := len(origData) - unPaddingNumber := int(origData[length-1]) // 找到Byte数组最后的填充byte 数字 - if unPaddingNumber <= 16 { - bs = origData[:(length - unPaddingNumber)] // 只截取返回有效数字内的byte数组 - } else { - bs = origData - } - return -} diff --git a/pkg/bmap/body_map.go b/pkg/bmap/body_map.go deleted file mode 100644 index 1ed49f7..0000000 --- a/pkg/bmap/body_map.go +++ /dev/null @@ -1,242 +0,0 @@ -package bmap - -import ( - "encoding/json" - "encoding/xml" - "errors" - "io" - "net/url" - "sort" - "strings" - - "github.com/go-pay/wechat-sdk/pkg/util" -) - -type BodyMap map[string]any - -type xmlMapMarshal struct { - XMLName xml.Name - Value any `xml:",cdata"` -} - -type xmlMapUnmarshal struct { - XMLName xml.Name - Value string `xml:",cdata"` -} - -// 设置参数 -func (bm BodyMap) Set(key string, value any) BodyMap { - bm[key] = value - return bm -} - -func (bm BodyMap) SetBodyMap(key string, value func(b BodyMap)) BodyMap { - _bm := make(BodyMap) - value(_bm) - bm[key] = _bm - return bm -} - -// 设置 FormFile -func (bm BodyMap) SetFormFile(key string, file *util.File) BodyMap { - bm[key] = file - return bm -} - -// 获取参数,同 GetString() -func (bm BodyMap) Get(key string) string { - return bm.GetString(key) -} - -// 获取参数转换string -func (bm BodyMap) GetString(key string) string { - if bm == nil { - return "" - } - value, ok := bm[key] - if !ok { - return "" - } - v, ok := value.(string) - if !ok { - return convertToString(value) - } - return v -} - -// 获取原始参数 -func (bm BodyMap) GetInterface(key string) any { - if bm == nil { - return nil - } - return bm[key] -} - -// 删除参数 -func (bm BodyMap) Remove(key string) { - delete(bm, key) -} - -// 置空BodyMap -func (bm BodyMap) Reset() { - for k := range bm { - delete(bm, k) - } -} - -func (bm BodyMap) JsonBody() (jb string) { - bs, err := json.Marshal(bm) - if err != nil { - return "" - } - jb = string(bs) - return jb -} - -// Unmarshal to struct or slice point -func (bm BodyMap) Unmarshal(ptr any) (err error) { - bs, err := json.Marshal(bm) - if err != nil { - return err - } - return json.Unmarshal(bs, ptr) -} - -func (bm BodyMap) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) { - if len(bm) == 0 { - return nil - } - start.Name = xml.Name{Space: "", Local: "xml"} - if err = e.EncodeToken(start); err != nil { - return - } - for k := range bm { - if v := bm.GetString(k); v != "" { - _ = e.Encode(xmlMapMarshal{XMLName: xml.Name{Local: k}, Value: v}) - } - } - return e.EncodeToken(start.End()) -} - -func (bm *BodyMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) { - for { - var e xmlMapUnmarshal - err = d.Decode(&e) - if err != nil { - if err == io.EOF { - return nil - } - return err - } - bm.Set(e.XMLName.Local, e.Value) - } -} - -// ("bar=baz&foo=quux") sorted by key. -func (bm BodyMap) EncodeWeChatSignParams(apiKey string) string { - if bm == nil { - return "" - } - var ( - buf strings.Builder - keyList []string - ) - for k := range bm { - keyList = append(keyList, k) - } - sort.Strings(keyList) - for _, k := range keyList { - if v := bm.GetString(k); v != "" { - buf.WriteString(k) - buf.WriteByte('=') - buf.WriteString(v) - buf.WriteByte('&') - } - } - buf.WriteString("key") - buf.WriteByte('=') - buf.WriteString(apiKey) - return buf.String() -} - -// ("bar=baz&foo=quux") sorted by key. -func (bm BodyMap) EncodeSortedSignParams() string { - if bm == nil { - return "" - } - var ( - buf strings.Builder - keyList []string - ) - for k := range bm { - keyList = append(keyList, k) - } - sort.Strings(keyList) - for _, k := range keyList { - if v := bm.GetString(k); v != "" { - buf.WriteString(k) - buf.WriteByte('=') - buf.WriteString(v) - buf.WriteByte('&') - } - } - if buf.Len() <= 0 { - return "" - } - return buf.String()[:buf.Len()-1] -} - -// ("bar=baz&foo=quux") sorted by key. -func (bm BodyMap) EncodeURLParams() string { - if bm == nil { - return "" - } - var ( - buf strings.Builder - keys []string - ) - for k := range bm { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - if v := bm.GetString(k); v != "" { - buf.WriteString(url.QueryEscape(k)) - buf.WriteByte('=') - buf.WriteString(url.QueryEscape(v)) - buf.WriteByte('&') - } - } - if buf.Len() <= 0 { - return "" - } - return buf.String()[:buf.Len()-1] -} - -func (bm BodyMap) CheckEmptyError(keys ...string) error { - var emptyKeys []string - for _, k := range keys { - if v := bm.GetString(k); v == "" { - emptyKeys = append(emptyKeys, k) - } - } - if len(emptyKeys) > 0 { - return errors.New(strings.Join(emptyKeys, ", ") + " : cannot be empty") - } - return nil -} - -func convertToString(v any) (str string) { - if v == nil { - return "" - } - var ( - bs []byte - err error - ) - if bs, err = json.Marshal(v); err != nil { - return "" - } - str = string(bs) - return -} diff --git a/pkg/bmap/body_map_test.go b/pkg/bmap/body_map_test.go deleted file mode 100644 index 93bf634..0000000 --- a/pkg/bmap/body_map_test.go +++ /dev/null @@ -1,146 +0,0 @@ -package bmap - -import ( - "encoding/json" - "encoding/xml" - "testing" - - "github.com/go-pay/wechat-sdk/pkg/util" - "github.com/go-pay/wechat-sdk/pkg/xlog" -) - -func TestBodyMapSetBodyMap(t *testing.T) { - bm := make(BodyMap) - // 1、配合map使用 - sceneInfo := make(map[string]map[string]string) - h5Info := make(map[string]string) - h5Info["type"] = "Wap" - h5Info["wap_url"] = "https://www.fmm.ink" - h5Info["wap_name"] = "H5测试支付" - sceneInfo["h5_info"] = h5Info - bm.Set("scene_info", sceneInfo) - xlog.Debug("配合map使用:", bm) // map[scene_info:map[h5_info:map[type:Wap wap_name:H5测试支付 wap_url:https://www.fmm.ink]]] - - bm.Reset() - xlog.Debug(bm) // [] - - // 2、基础用法 - bm.Set("1key", "1value") - bm.Set("2key", "2value") - bm.Set("3key", "3value") - xlog.Debug("基础用法:", bm) - - bm.Reset() - xlog.Debug(bm) // [] - - // 3、链式用法 - bm.Set("4key", "4value"). - Set("5key", "5value"). - Set("6key", "6value") - xlog.Debug("链式用法:", bm) - - bm.Reset() - xlog.Debug(bm) // [] - - // 4、高级用法 - bm.SetBodyMap("scene_info", func(bm BodyMap) { - bm.SetBodyMap("h5_info", func(bm BodyMap) { - bm.Set("type", "Wap"). - Set("wap_url", "https://www.fmm.ink"). - Set("wap_name", "H5测试支付") - }) - }).Set("7key", "7value"). - Set("8key", "8value") - xlog.Debug("高级用法:", bm) // map[scene_info:map[h5_info:map[type:Wap wap_name:H5测试支付 wap_url:https://www.fmm.ink]]] - xlog.Debug("高级用法 JsonBody:", bm.JsonBody()) -} - -func TestBodyMapMarshal(t *testing.T) { - bm := make(BodyMap) - bm.Set("4key", "4value"). - Set("6key", "6value"). - Set("5key", "5value") - jb := bm.JsonBody() - xlog.Debug("jb:", jb) - - bm.Reset() - - bm.SetBodyMap("scene_info", func(bm BodyMap) { - bm.SetBodyMap("h5_info", func(bm BodyMap) { - bm.Set("type", "Wap"). - Set("wap_url", "https://www.fmm.ink"). - Set("wap_name", "H5测试支付") - }) - }).Set("7key", "7value"). - Set("8key", "8value") - jb2 := bm.JsonBody() - xlog.Debug("jb2:", jb2) - - bm.Reset() - - bm.SetBodyMap("partner", func(bm BodyMap) { - bm.Set("type", "APPID"). - Set("appid", "wx123456"). - Set("merchant_id", "88888") - }).SetBodyMap("authorized_data", func(bm BodyMap) { - bm.Set("business_type", "BUSIFAVOR_STOCK"). - Set("stock_id", "66666") - }).Set("limit", 5). - Set("offset", 10) - - urlParams := bm.EncodeURLParams() - xlog.Debug("urlParams:", urlParams) -} - -func TestBodyMapMarshalSlice(t *testing.T) { - type Receiver struct { - Type string `json:"type"` - Account string `json:"account"` - Amount int `json:"amount"` - Description string `json:"description"` - } - var rs []*Receiver - item := &Receiver{ - Type: "MERCHANT_ID", - Account: "190001001", - Amount: 100, - Description: "分到商户", - } - rs = append(rs, item) - item2 := &Receiver{ - Type: "PERSONAL_OPENID", - Account: "86693952", - Amount: 888, - Description: "分到个人", - } - rs = append(rs, item2) - bs, _ := json.Marshal(rs) - - bm := make(BodyMap) - bm.Set("nonce_str", util.RandomString(32)). - Set("transaction_id", "4208450740201411110007820472"). - Set("out_order_no", "P20150806125346") - - bm.Set("receivers", string(bs)) - - xlog.Debug("JsonBody:", bm.JsonBody()) - //receiver := make(BodyMap) - //receiver.Set("receiver", string(bs)) - // - //body := receiver.JsonBody() - bss, _ := xml.Marshal(bm) - xlog.Debug("body:", string(bss)) -} - -func TestSliceTest(t *testing.T) { - var rs []string - rs = append(rs, "SOFTWARE") - rs = append(rs, "SECURITY") - rs = append(rs, "LOVE_MARRIAGE") - - bm := make(BodyMap) - bm.Set("sub_mchid", "2021060717"). - Set("advertising_industry_filters", rs) - - xlog.Debugf("%s", bm.JsonBody()) -} diff --git a/pkg/util/common.go b/pkg/util/common.go deleted file mode 100644 index 9a56fa9..0000000 --- a/pkg/util/common.go +++ /dev/null @@ -1,10 +0,0 @@ -package util - -const ( - NULL = "" -) - -type File struct { - Name string `json:"name"` - Content []byte `json:"content"` -} diff --git a/pkg/util/convert.go b/pkg/util/convert.go deleted file mode 100644 index 1e708d9..0000000 --- a/pkg/util/convert.go +++ /dev/null @@ -1,95 +0,0 @@ -package util - -import ( - "math" - "strconv" - "strings" - "unsafe" -) - -// 字符串转Int -// intStr:数字的字符串 -func String2Int(intStr string) (intNum int) { - intNum, _ = strconv.Atoi(intStr) - return -} - -// 字符串转Int64 -// intStr:数字的字符串 -func String2Int64(intStr string) (int64Num int64) { - intNum, _ := strconv.Atoi(intStr) - int64Num = int64(intNum) - return -} - -// 字符串转Float64 -// floatStr:小数点数字的字符串 -func String2Float64(floatStr string) (floatNum float64) { - floatNum, _ = strconv.ParseFloat(floatStr, 64) - return -} - -// 字符串转Float32 -// floatStr:小数点数字的字符串 -func String2Float32(floatStr string) (floatNum float32) { - floatNum64, _ := strconv.ParseFloat(floatStr, 32) - floatNum = float32(floatNum64) - return -} - -// Int转字符串 -// intNum:数字字符串 -func Int2String(intNum int) (intStr string) { - intStr = strconv.Itoa(intNum) - return -} - -// Int64转字符串 -// intNum:数字字符串 -func Int642String(intNum int64) (int64Str string) { - //10, 代表10进制 - int64Str = strconv.FormatInt(intNum, 10) - return -} - -// Float64转字符串 -// floatNum:float64数字 -// prec:精度位数(不传则默认float数字精度) -func Float64ToString(floatNum float64, prec ...int) (floatStr string) { - if len(prec) > 0 { - floatStr = strconv.FormatFloat(floatNum, 'f', prec[0], 64) - return - } - floatStr = strconv.FormatFloat(floatNum, 'f', -1, 64) - return -} - -// Float32转字符串 -// floatNum:float32数字 -// prec:精度位数(不传则默认float数字精度) -func Float32ToString(floatNum float32, prec ...int) (floatStr string) { - if len(prec) > 0 { - floatStr = strconv.FormatFloat(float64(floatNum), 'f', prec[0], 32) - return - } - floatStr = strconv.FormatFloat(float64(floatNum), 'f', -1, 32) - return -} - -// 二进制转10进制 -func BinaryToDecimal(bit string) (num int) { - fields := strings.Split(bit, "") - lens := len(fields) - var tempF float64 = 0 - for i := 0; i < lens; i++ { - floatNum := String2Float64(fields[i]) - tempF += floatNum * math.Pow(2, float64(lens-i-1)) - } - num = int(tempF) - return -} - -// BytesToString 0 拷贝转换 slice byte 为 string -func BytesToString(b []byte) (s string) { - return *(*string)(unsafe.Pointer(&b)) -} diff --git a/pkg/util/convert_test.go b/pkg/util/convert_test.go deleted file mode 100644 index 09dee3b..0000000 --- a/pkg/util/convert_test.go +++ /dev/null @@ -1,15 +0,0 @@ -package util - -import "testing" - -func TestBytesToString(t *testing.T) { - var b = []byte("abc") - s := BytesToString(b) - if s != string(b) { - t.Fatal("BytesToString error") - } - b[1] = 'c' - if s != "acc" { - t.Fatal("BytesToString error") - } -} diff --git a/pkg/util/random.go b/pkg/util/random.go deleted file mode 100644 index d7bb3bf..0000000 --- a/pkg/util/random.go +++ /dev/null @@ -1,42 +0,0 @@ -package util - -import ( - "math/rand" - "time" -) - -// 随机生成字符串 -func RandomString(l int) string { - str := "0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" - bytes := []byte(str) - var result = make([]byte, 0, l) - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < l; i++ { - result = append(result, bytes[r.Intn(len(bytes))]) - } - return BytesToString(result) -} - -// 随机生成纯字符串 -func RandomPureString(l int) string { - str := "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz" - bytes := []byte(str) - var result = make([]byte, 0, l) - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < l; i++ { - result = append(result, bytes[r.Intn(len(bytes))]) - } - return BytesToString(result) -} - -// 随机生成数字字符串 -func RandomNumber(l int) string { - str := "0123456789" - bytes := []byte(str) - var result []byte - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < l; i++ { - result = append(result, bytes[r.Intn(len(bytes))]) - } - return BytesToString(result) -} diff --git a/pkg/util/string.go b/pkg/util/string.go deleted file mode 100644 index 3fb764d..0000000 --- a/pkg/util/string.go +++ /dev/null @@ -1,18 +0,0 @@ -package util - -import "encoding/json" - -func ConvertToString(v any) (str string) { - if v == nil { - return NULL - } - var ( - bs []byte - err error - ) - if bs, err = json.Marshal(v); err != nil { - return NULL - } - str = string(bs) - return -} diff --git a/pkg/util/util_test.go b/pkg/util/util_test.go deleted file mode 100644 index 068ae51..0000000 --- a/pkg/util/util_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package util - -import ( - "crypto/sha256" - "encoding/hex" - "testing" - - "github.com/go-pay/wechat-sdk/pkg/xlog" -) - -func TestHexToString(t *testing.T) { - h := sha256.New() - h.Write([]byte("hsSuSUsePBqSQw2rYMtf9Nvha603xX8f2BMQBcYRoJiMNwOqt/UEhrqekebG5ar0LFNAm5MD4Uz6zorRwiXJwbySJ/FEJHav4NsobBIU1PwdjbJWVQLFy7+YFkHB32OnQXWMh6ugW7Dyk2KS5BXp1f5lniKPp1KNLyNLlFlNZ2mgJCJmWvHj5AI7BLpWwoRvqRyZvVXo+9FsWqvBdxmAPA==")) - toString := hex.EncodeToString(h.Sum(nil)) - xlog.Debugf("hex: %s", toString) -} diff --git a/pkg/xhttp/client.go b/pkg/xhttp/client.go deleted file mode 100644 index d25bc6f..0000000 --- a/pkg/xhttp/client.go +++ /dev/null @@ -1,359 +0,0 @@ -package xhttp - -import ( - "bytes" - "context" - "crypto/tls" - "encoding/json" - "encoding/xml" - "errors" - "fmt" - "io" - "mime/multipart" - "net/http" - "net/url" - "sort" - "strings" - "time" - - "github.com/go-pay/wechat-sdk/pkg/util" -) - -type Client struct { - HttpClient *http.Client - Transport *http.Transport - Header http.Header - Timeout time.Duration - url string - Host string - method string - requestType RequestType - FormString string - ContentType string - unmarshalType string - multipartBodyMap map[string]any - jsonByte []byte - err error -} - -// NewClient , default tls.Config{InsecureSkipVerify: true} -func NewClient() (client *Client) { - client = &Client{ - HttpClient: &http.Client{ - Timeout: 60 * time.Second, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, - DisableKeepAlives: true, - Proxy: http.ProxyFromEnvironment, - }, - }, - Transport: nil, - Header: make(http.Header), - requestType: TypeJSON, - unmarshalType: string(TypeJSON), - } - return client -} - -func (c *Client) SetTransport(transport *http.Transport) (client *Client) { - c.Transport = transport - return c -} - -func (c *Client) SetTLSConfig(tlsCfg *tls.Config) (client *Client) { - c.Transport = &http.Transport{TLSClientConfig: tlsCfg, DisableKeepAlives: true, Proxy: http.ProxyFromEnvironment} - return c -} - -func (c *Client) SetTimeout(timeout time.Duration) (client *Client) { - c.Timeout = timeout - return c -} - -func (c *Client) SetHost(host string) (client *Client) { - c.Host = host - return c -} - -func (c *Client) Type(typeStr RequestType) (client *Client) { - if _, ok := types[typeStr]; ok { - c.requestType = typeStr - } - return c -} - -func (c *Client) Get(url string) (client *Client) { - c.method = GET - c.url = url - return c -} - -func (c *Client) Post(url string) (client *Client) { - c.method = POST - c.url = url - return c -} - -func (c *Client) Put(url string) (client *Client) { - c.method = PUT - c.url = url - return c -} - -func (c *Client) Delete(url string) (client *Client) { - c.method = DELETE - c.url = url - return c -} - -func (c *Client) Patch(url string) (client *Client) { - c.method = PATCH - c.url = url - return c -} - -func (c *Client) SendStruct(v any) (client *Client) { - if v == nil { - return c - } - bs, err := json.Marshal(v) - if err != nil { - c.err = fmt.Errorf("json.Marshal(%+v):%w", v, err) - return c - } - switch c.requestType { - case TypeJSON: - c.jsonByte = bs - case TypeXML, TypeUrlencoded, TypeForm, TypeFormData: - body := make(map[string]any) - if err = json.Unmarshal(bs, &body); err != nil { - c.err = fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), body, err) - return c - } - c.FormString = FormatURLParam(body) - } - return c -} - -func (c *Client) SendBodyMap(bm map[string]any) (client *Client) { - if bm == nil { - return c - } - switch c.requestType { - case TypeJSON: - bs, err := json.Marshal(bm) - if err != nil { - c.err = fmt.Errorf("json.Marshal(%+v):%w", bm, err) - return c - } - c.jsonByte = bs - case TypeXML, TypeUrlencoded, TypeForm, TypeFormData: - c.FormString = FormatURLParam(bm) - } - return c -} - -func (c *Client) SendMultipartBodyMap(bm map[string]any) (client *Client) { - if bm == nil { - return c - } - switch c.requestType { - case TypeJSON: - bs, err := json.Marshal(bm) - if err != nil { - c.err = fmt.Errorf("json.Marshal(%+v):%w", bm, err) - return c - } - c.jsonByte = bs - case TypeXML, TypeUrlencoded, TypeForm, TypeFormData: - c.FormString = FormatURLParam(bm) - case TypeMultipartFormData: - c.multipartBodyMap = bm - } - return c -} - -// encodeStr: url.Values.Encode() or jsonBody -func (c *Client) SendString(encodeStr string) (client *Client) { - switch c.requestType { - case TypeJSON: - c.jsonByte = []byte(encodeStr) - case TypeXML, TypeUrlencoded, TypeForm, TypeFormData: - c.FormString = encodeStr - } - return c -} - -func (c *Client) EndStruct(ctx context.Context, v any) (res *http.Response, err error) { - res, bs, err := c.EndBytes(ctx) - if err != nil { - return nil, err - } - if res.StatusCode != http.StatusOK { - return res, fmt.Errorf("StatusCode(%d) != 200", res.StatusCode) - } - - switch c.unmarshalType { - case string(TypeJSON): - err = json.Unmarshal(bs, &v) - if err != nil { - return nil, fmt.Errorf("json.Unmarshal(%s, %+v):%w", string(bs), v, err) - } - return res, nil - case string(TypeXML): - err = xml.Unmarshal(bs, &v) - if err != nil { - return nil, fmt.Errorf("xml.Unmarshal(%s, %+v):%w", string(bs), v, err) - } - return res, nil - default: - return nil, errors.New("unmarshalType Type Wrong") - } -} - -func (c *Client) EndBytes(ctx context.Context) (res *http.Response, bs []byte, err error) { - if c.err != nil { - return nil, nil, c.err - } - var ( - body io.Reader - bw *multipart.Writer - ) - // multipart-form-data - if c.requestType == TypeMultipartFormData { - body = &bytes.Buffer{} - bw = multipart.NewWriter(body.(io.Writer)) - } - - reqFunc := func() (err error) { - switch c.method { - case GET: - switch c.requestType { - case TypeJSON: - c.ContentType = types[TypeJSON] - case TypeForm, TypeFormData, TypeUrlencoded: - c.ContentType = types[TypeForm] - case TypeMultipartFormData: - c.ContentType = bw.FormDataContentType() - case TypeXML: - c.ContentType = types[TypeXML] - c.unmarshalType = string(TypeXML) - default: - return errors.New("Request type Error ") - } - case POST, PUT, DELETE, PATCH: - switch c.requestType { - case TypeJSON: - if c.jsonByte != nil { - body = strings.NewReader(string(c.jsonByte)) - } - c.ContentType = types[TypeJSON] - case TypeForm, TypeFormData, TypeUrlencoded: - body = strings.NewReader(c.FormString) - c.ContentType = types[TypeForm] - case TypeMultipartFormData: - for k, v := range c.multipartBodyMap { - // file 参数 - if file, ok := v.(*util.File); ok { - fw, err := bw.CreateFormFile(k, file.Name) - if err != nil { - return err - } - _, _ = fw.Write(file.Content) - continue - } - // text 参数 - vs, ok2 := v.(string) - if ok2 { - _ = bw.WriteField(k, vs) - } else if ss := util.ConvertToString(v); ss != "" { - _ = bw.WriteField(k, ss) - } - } - _ = bw.Close() - c.ContentType = bw.FormDataContentType() - case TypeXML: - body = strings.NewReader(c.FormString) - c.ContentType = types[TypeXML] - c.unmarshalType = string(TypeXML) - default: - return errors.New("Request type Error ") - } - default: - return errors.New("Only support GET and POST and PUT and DELETE ") - } - - req, err := http.NewRequestWithContext(ctx, c.method, c.url, body) - if err != nil { - return err - } - req.Header = c.Header - req.Header.Set("Content-Type", c.ContentType) - if c.Transport != nil { - c.HttpClient.Transport = c.Transport - } - if c.Host != "" { - req.Host = c.Host - } - if c.Timeout > 0 { - c.HttpClient.Timeout = c.Timeout - } - res, err = c.HttpClient.Do(req) - if err != nil { - return err - } - defer res.Body.Close() - bs, err = io.ReadAll(io.LimitReader(res.Body, int64(5<<20))) // default 5MB change the size you want - if err != nil { - return err - } - return nil - } - - if err = reqFunc(); err != nil { - return nil, nil, err - } - return res, bs, nil -} - -func FormatURLParam(body map[string]any) (urlParam string) { - var ( - buf strings.Builder - keys []string - ) - for k := range body { - keys = append(keys, k) - } - sort.Strings(keys) - for _, k := range keys { - v, ok := body[k].(string) - if !ok { - v = convertToString(body[k]) - } - if v != "" { - buf.WriteString(url.QueryEscape(k)) - buf.WriteByte('=') - buf.WriteString(url.QueryEscape(v)) - buf.WriteByte('&') - } - } - if buf.Len() <= 0 { - return "" - } - return buf.String()[:buf.Len()-1] -} - -func convertToString(v any) (str string) { - if v == nil { - return "" - } - var ( - bs []byte - err error - ) - if bs, err = json.Marshal(v); err != nil { - return "" - } - str = string(bs) - return -} diff --git a/pkg/xhttp/client_test.go b/pkg/xhttp/client_test.go deleted file mode 100644 index 15a77c5..0000000 --- a/pkg/xhttp/client_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package xhttp - -import ( - "context" - "os" - "testing" - "time" - - "github.com/go-pay/wechat-sdk/pkg/bmap" - "github.com/go-pay/wechat-sdk/pkg/util" - "github.com/go-pay/wechat-sdk/pkg/xlog" -) - -type HttpGet struct { - Code int `json:"code"` - Message string `json:"message"` - Data any `json:"data,omitempty"` -} - -var ctx = context.Background() - -func TestHttpGet(t *testing.T) { - client := NewClient() - client.Timeout = 10 * time.Second - // test - _, bs, err := client.Get("http://www.baidu.com").EndBytes(ctx) - if err != nil { - xlog.Error(err) - return - } - xlog.Debug(string(bs)) - - //rsp := new(HttpGet) - //_, err := client.Type(TypeJSON).Get("http://api.igoogle.ink/app/v1/ping").EndStruct(ctx,rsp) - //if err != nil { - // xlog.Error(err) - // return - //} - //xlog.Debug(rsp) -} - -func TestHttpUploadFile(t *testing.T) { - fileContent, err := os.ReadFile("../../logo.png") - if err != nil { - xlog.Error(err) - return - } - //xlog.Debug("fileByte:", string(fileContent)) - - bm := make(bmap.BodyMap) - bm.SetBodyMap("meta", func(bm bmap.BodyMap) { - bm.Set("filename", "123.jpg"). - Set("sha256", "ad4465asd4fgw5q") - }).SetFormFile("image", &util.File{Name: "logo.png", Content: fileContent}) - - client := NewClient() - client.Timeout = 10 * time.Second - - rsp := new(HttpGet) - _, err = client.Type(TypeMultipartFormData). - Post("http://localhost:2233/admin/v1/oss/uploadImage"). - SendMultipartBodyMap(bm). - EndStruct(ctx, rsp) - if err != nil { - xlog.Error(err) - return - } - xlog.Debugf("%+v", rsp) -} diff --git a/pkg/xhttp/model.go b/pkg/xhttp/model.go deleted file mode 100644 index 30ae41b..0000000 --- a/pkg/xhttp/model.go +++ /dev/null @@ -1,28 +0,0 @@ -package xhttp - -type RequestType string - -const ( - GET = "GET" - POST = "POST" - PUT = "PUT" - DELETE = "DELETE" - PATCH = "PATCH" - TypeJSON RequestType = "json" - TypeXML RequestType = "xml" - TypeUrlencoded RequestType = "urlencoded" - TypeForm RequestType = "form" - TypeFormData RequestType = "form-data" - TypeMultipartFormData RequestType = "multipart-form-data" - - HeaderRequestID = "Request-ID" -) - -var types = map[RequestType]string{ - TypeJSON: "application/json", - TypeXML: "application/xml", - TypeUrlencoded: "application/x-www-form-urlencoded", - TypeForm: "application/x-www-form-urlencoded", - TypeFormData: "application/x-www-form-urlencoded", - TypeMultipartFormData: "multipart/form-data", -} diff --git a/pkg/xlog/color.go b/pkg/xlog/color.go deleted file mode 100644 index facdf67..0000000 --- a/pkg/xlog/color.go +++ /dev/null @@ -1,112 +0,0 @@ -package xlog - -type ColorType string - -var ( - Reset = ColorType([]byte{27, 91, 48, 109}) - // 标准 - White = ColorType([]byte{27, 91, 51, 48, 109}) // 白色 - Red = ColorType([]byte{27, 91, 51, 49, 109}) // 红色 - Green = ColorType([]byte{27, 91, 51, 50, 109}) // 绿色 - Yellow = ColorType([]byte{27, 91, 51, 51, 109}) // 黄色 - Blue = ColorType([]byte{27, 91, 51, 52, 109}) // 蓝色 - Magenta = ColorType([]byte{27, 91, 51, 53, 109}) // 紫色 - Cyan = ColorType([]byte{27, 91, 51, 54, 109}) // 青色 - // 高亮 - WhiteBright = ColorType([]byte{27, 91, 49, 59, 51, 48, 109}) - RedBright = ColorType([]byte{27, 91, 49, 59, 51, 49, 109}) - GreenBright = ColorType([]byte{27, 91, 49, 59, 51, 50, 109}) - YellowBright = ColorType([]byte{27, 91, 49, 59, 51, 51, 109}) - BlueBright = ColorType([]byte{27, 91, 49, 59, 51, 52, 109}) - MagentaBright = ColorType([]byte{27, 91, 49, 59, 51, 53, 109}) - CyanBright = ColorType([]byte{27, 91, 49, 59, 51, 54, 109}) - // 斜体 - WhiteBevel = ColorType([]byte{27, 91, 51, 59, 51, 48, 109}) - RedBevel = ColorType([]byte{27, 91, 51, 59, 51, 49, 109}) - GreenBevel = ColorType([]byte{27, 91, 51, 59, 51, 50, 109}) - YellowBevel = ColorType([]byte{27, 91, 51, 59, 51, 51, 109}) - BlueBevel = ColorType([]byte{27, 91, 51, 59, 51, 52, 109}) - MagentaBevel = ColorType([]byte{27, 91, 51, 59, 51, 53, 109}) - CyanBevel = ColorType([]byte{27, 91, 51, 59, 51, 54, 109}) - // 下划线 - WhiteUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 48, 109}) - RedUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 49, 109}) - GreenUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 50, 109}) - YellowUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 51, 109}) - BlueUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 52, 109}) - MagentaUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 53, 109}) - CyanUnderLine = ColorType([]byte{27, 91, 52, 59, 51, 54, 109}) - // 背景色 - WhiteBg = ColorType([]byte{27, 91, 55, 59, 51, 48, 109}) - RedBg = ColorType([]byte{27, 91, 55, 59, 51, 49, 109}) - GreenBg = ColorType([]byte{27, 91, 55, 59, 51, 50, 109}) - YellowBg = ColorType([]byte{27, 91, 55, 59, 51, 51, 109}) - BlueBg = ColorType([]byte{27, 91, 55, 59, 51, 52, 109}) - MagentaBg = ColorType([]byte{27, 91, 55, 59, 51, 53, 109}) - CyanBg = ColorType([]byte{27, 91, 55, 59, 51, 54, 109}) - // 删除线 - WhiteDelLine = ColorType([]byte{27, 91, 57, 59, 51, 48, 109}) - RedDelLine = ColorType([]byte{27, 91, 57, 59, 51, 49, 109}) - GreenDelLine = ColorType([]byte{27, 91, 57, 59, 51, 50, 109}) - YellowDelLine = ColorType([]byte{27, 91, 57, 59, 51, 51, 109}) - BlueDelLine = ColorType([]byte{27, 91, 57, 59, 51, 52, 109}) - MagentaDelLine = ColorType([]byte{27, 91, 57, 59, 51, 53, 109}) - CyanDelLine = ColorType([]byte{27, 91, 57, 59, 51, 54, 109}) -) - -var cl *ColorLogger - -type ColorLogger struct { - Color ColorType - i *InfoLogger - d *DebugLogger - w *WarnLogger - e *ErrorLogger -} - -func Color(color ColorType) *ColorLogger { - if cl == nil { - cl = &ColorLogger{ - Color: color, - i: &InfoLogger{}, - d: &DebugLogger{}, - w: &WarnLogger{}, - e: &ErrorLogger{}, - } - return cl - } - cl.Color = color - return cl -} - -func (l *ColorLogger) Info(args ...any) { - l.i.LogOut(&l.Color, nil, args...) -} - -func (l *ColorLogger) Infof(format string, args ...any) { - l.i.LogOut(&l.Color, &format, args...) -} - -func (l *ColorLogger) Debug(args ...any) { - l.d.LogOut(&l.Color, nil, args...) -} - -func (l *ColorLogger) Debugf(format string, args ...any) { - l.d.LogOut(&l.Color, &format, args...) -} - -func (l *ColorLogger) Warn(args ...any) { - l.w.LogOut(&l.Color, nil, args...) -} - -func (l *ColorLogger) Warnf(format string, args ...any) { - l.w.LogOut(&l.Color, &format, args...) -} - -func (l *ColorLogger) Error(args ...any) { - l.e.LogOut(&l.Color, nil, args...) -} - -func (l *ColorLogger) Errorf(format string, args ...any) { - l.e.LogOut(&l.Color, &format, args...) -} diff --git a/pkg/xlog/debug_logger.go b/pkg/xlog/debug_logger.go deleted file mode 100644 index 8f26fd3..0000000 --- a/pkg/xlog/debug_logger.go +++ /dev/null @@ -1,41 +0,0 @@ -package xlog - -import ( - "fmt" - "log" - "os" - "sync" -) - -type DebugLogger struct { - logger *log.Logger - once sync.Once -} - -func (d *DebugLogger) LogOut(col *ColorType, format *string, v ...any) { - d.once.Do(func() { - d.init() - }) - if Level >= DebugLevel { - if col != nil { - if format != nil { - _ = d.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset)) - return - } - _ = d.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset)) - return - } - if format != nil { - _ = d.logger.Output(3, fmt.Sprintf(*format, v...)) - return - } - _ = d.logger.Output(3, fmt.Sprintln(v...)) - } -} - -func (d *DebugLogger) init() { - if Level == 0 { - Level = DebugLevel - } - d.logger = log.New(os.Stdout, "[DEBUG] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds) -} diff --git a/pkg/xlog/error_logger.go b/pkg/xlog/error_logger.go deleted file mode 100644 index bd65a6a..0000000 --- a/pkg/xlog/error_logger.go +++ /dev/null @@ -1,41 +0,0 @@ -package xlog - -import ( - "fmt" - "log" - "os" - "sync" -) - -type ErrorLogger struct { - logger *log.Logger - once sync.Once -} - -func (e *ErrorLogger) LogOut(col *ColorType, format *string, v ...any) { - e.once.Do(func() { - e.init() - }) - if Level >= ErrorLevel { - if col != nil { - if format != nil { - _ = e.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset)) - return - } - _ = e.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset)) - return - } - if format != nil { - _ = e.logger.Output(3, fmt.Sprintf(*format, v...)) - return - } - _ = e.logger.Output(3, fmt.Sprintln(v...)) - } -} - -func (e *ErrorLogger) init() { - if Level == 0 { - Level = DebugLevel - } - e.logger = log.New(os.Stdout, "[ERROR] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds) -} diff --git a/pkg/xlog/info_logger.go b/pkg/xlog/info_logger.go deleted file mode 100644 index bfe347c..0000000 --- a/pkg/xlog/info_logger.go +++ /dev/null @@ -1,41 +0,0 @@ -package xlog - -import ( - "fmt" - "log" - "os" - "sync" -) - -type InfoLogger struct { - logger *log.Logger - once sync.Once -} - -func (i *InfoLogger) LogOut(col *ColorType, format *string, v ...any) { - i.once.Do(func() { - i.init() - }) - if Level >= InfoLevel { - if col != nil { - if format != nil { - _ = i.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset)) - return - } - _ = i.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset)) - return - } - if format != nil { - _ = i.logger.Output(3, fmt.Sprintf(*format, v...)) - return - } - _ = i.logger.Output(3, fmt.Sprintln(v...)) - } -} - -func (i *InfoLogger) init() { - if Level == 0 { - Level = DebugLevel - } - i.logger = log.New(os.Stdout, "[INFO] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds) -} diff --git a/pkg/xlog/log.go b/pkg/xlog/log.go deleted file mode 100644 index 223dc8f..0000000 --- a/pkg/xlog/log.go +++ /dev/null @@ -1,71 +0,0 @@ -package xlog - -const ( - ErrorLevel LogLevel = iota + 1 - WarnLevel - InfoLevel - DebugLevel -) - -type LogLevel int - -var ( - debugLog XLogger = &DebugLogger{} - infoLog XLogger = &InfoLogger{} - warnLog XLogger = &WarnLogger{} - errLog XLogger = &ErrorLogger{} - - Level LogLevel -) - -type XLogger interface { - LogOut(col *ColorType, format *string, args ...any) -} - -func Info(args ...any) { - infoLog.LogOut(nil, nil, args...) -} - -func Infof(format string, args ...any) { - infoLog.LogOut(nil, &format, args...) -} - -func Debug(args ...any) { - debugLog.LogOut(nil, nil, args...) -} - -func Debugf(format string, args ...any) { - debugLog.LogOut(nil, &format, args...) -} - -func Warn(args ...any) { - warnLog.LogOut(nil, nil, args...) -} - -func Warnf(format string, args ...any) { - warnLog.LogOut(nil, &format, args...) -} - -func Error(args ...any) { - errLog.LogOut(nil, nil, args...) -} - -func Errorf(format string, args ...any) { - errLog.LogOut(nil, &format, args...) -} - -func SetDebugLog(logger XLogger) { - debugLog = logger -} - -func SetInfoLog(logger XLogger) { - infoLog = logger -} - -func SetWarnLog(logger XLogger) { - warnLog = logger -} - -func SetErrLog(logger XLogger) { - errLog = logger -} diff --git a/pkg/xlog/log_test.go b/pkg/xlog/log_test.go deleted file mode 100644 index bb117af..0000000 --- a/pkg/xlog/log_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package xlog - -import ( - "testing" -) - -func TestLog(t *testing.T) { - - // default log - Info(White, "白色 info", Reset, WhiteBright, "高亮 info", Reset, "恢复默认颜色", WhiteDelLine, "删除线", Reset, WhiteUnderLine, "下划线", Reset, WhiteBevel, "斜体 info", Reset, WhiteBg, "背景", Reset) - Debug(Cyan, "青色 debug", Reset, CyanBright, "高亮 debug", Reset, "恢复默认颜色", CyanDelLine, "删除线", Reset, CyanUnderLine, "下划线", Reset, CyanBevel, "斜体 debug", Reset, CyanBg, "背景", Reset) - Warn(Yellow, "黄色 warning", Reset, YellowBright, "高亮 warning", Reset, "恢复默认颜色", YellowDelLine, "删除线", Reset, YellowUnderLine, "下划线", Reset, YellowBevel, "斜体 warning", Reset, YellowBg, "背景", Reset) - Error(Red, "红色 error", Reset, RedBright, "高亮 error", Reset, "恢复默认颜色", RedDelLine, "删除线", Reset, RedUnderLine, "下划线", Reset, RedBevel, "斜体 error", Reset, RedBg, "背景", Reset) - - // color log - Color(White).Info("color log info") - Color(Cyan).Debug("color log debug") - Color(Yellow).Warn("color log warn") - Color(Red).Error("color log error") -} diff --git a/pkg/xlog/warn_logger.go b/pkg/xlog/warn_logger.go deleted file mode 100644 index 4b06565..0000000 --- a/pkg/xlog/warn_logger.go +++ /dev/null @@ -1,41 +0,0 @@ -package xlog - -import ( - "fmt" - "log" - "os" - "sync" -) - -type WarnLogger struct { - logger *log.Logger - once sync.Once -} - -func (w *WarnLogger) LogOut(col *ColorType, format *string, v ...any) { - w.once.Do(func() { - w.init() - }) - if Level >= WarnLevel { - if col != nil { - if format != nil { - _ = w.logger.Output(3, string(*col)+fmt.Sprintf(*format, v...)+string(Reset)) - return - } - _ = w.logger.Output(3, string(*col)+fmt.Sprintln(v...)+string(Reset)) - return - } - if format != nil { - _ = w.logger.Output(3, fmt.Sprintf(*format, v...)) - return - } - _ = w.logger.Output(3, fmt.Sprintln(v...)) - } -} - -func (w *WarnLogger) init() { - if Level == 0 { - Level = DebugLevel - } - w.logger = log.New(os.Stdout, "[WARN] >> ", log.Lmsgprefix|log.Lshortfile|log.Ldate|log.Lmicroseconds) -} diff --git a/pkg/xtime/constants.go b/pkg/xtime/constants.go deleted file mode 100644 index 9930f53..0000000 --- a/pkg/xtime/constants.go +++ /dev/null @@ -1,8 +0,0 @@ -package xtime - -const ( - TimeLayout = "2006-01-02 15:04:05" - TimeLayout_1 = "2006-01-02 15:04:05.000" - TimeLayout_2 = "20060102150405" - DateLayout = "2006-01-02" -) diff --git a/pkg/xtime/data_time.go b/pkg/xtime/data_time.go deleted file mode 100644 index 9c9e862..0000000 --- a/pkg/xtime/data_time.go +++ /dev/null @@ -1,99 +0,0 @@ -package xtime - -import ( - "time" -) - -var daysBefore = [...]int32{ - 0, - 31, - 31 + 28, - 31 + 28 + 31, - 31 + 28 + 31 + 30, - 31 + 28 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30, - 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31, -} - -func MonthDays(m time.Month, year int) int { - if m == time.February && isLeap(year) { - return 29 - } - return int(daysBefore[m] - daysBefore[m-1]) -} - -func isLeap(year int) bool { - return year%4 == 0 && (year%100 != 0 || year%400 == 0) -} - -// 获取最近 7天 日期 -func GetRecentSevenDay() (sevenDays []string) { - now := time.Now() - nowDay := time.Date(now.Year(), now.Month(), now.Day()-7, 0, 0, 0, 0, time.Local) - for i := 0; i < 7; i++ { - date := nowDay.AddDate(0, 0, i) - sevenDays = append(sevenDays, date.Format(DateLayout)) - } - return sevenDays -} - -// 获取最近 30天 日期 -func GetRecentThirtyDay() (thirtyDays []string) { - now := time.Now() - nowDay := time.Date(now.Year(), now.Month(), now.Day()-30, 0, 0, 0, 0, time.Local) - for i := 0; i < 30; i++ { - date := nowDay.AddDate(0, 0, i) - thirtyDays = append(thirtyDays, date.Format(DateLayout)) - } - return thirtyDays -} - -// 获取本周 7天 日期 -func GetCurWeekDays() (curWeekDays []string) { - now := time.Now() - offset := int(time.Monday - now.Weekday()) - if offset > 0 { - offset = -6 - } - weekStartDate := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local).AddDate(0, 0, offset) - for i := 0; i < 7; i++ { - date := weekStartDate.AddDate(0, 0, i) - curWeekDays = append(curWeekDays, date.Format(DateLayout)) - } - return -} - -// 获取本月 日期 -func GetCurMonthDays() (curMonthDays []string) { - now := time.Now() - year := now.Year() - month := now.Month() - days := MonthDays(month, year) - - monthFirstDay := time.Date(year, month, 01, 0, 0, 0, 0, time.Local) - for i := 0; i < days; i++ { - date := monthFirstDay.AddDate(0, 0, i) - curMonthDays = append(curMonthDays, date.Format(DateLayout)) - } - return curMonthDays -} - -// 获取上一个月 日期 -func GetLastMonthDays() (monthDays []string) { - now := time.Now() - year := now.Year() - month := now.Month() - days := MonthDays(month-1, year) - - monthFirstDay := time.Date(year, month-1, 01, 0, 0, 0, 0, time.Local) - for i := 0; i < days; i++ { - date := monthFirstDay.AddDate(0, 0, i) - monthDays = append(monthDays, date.Format(DateLayout)) - } - return monthDays -} diff --git a/pkg/xtime/parse_format.go b/pkg/xtime/parse_format.go deleted file mode 100644 index e54df36..0000000 --- a/pkg/xtime/parse_format.go +++ /dev/null @@ -1,107 +0,0 @@ -package xtime - -import ( - "strings" - "time" - - "github.com/go-pay/wechat-sdk/pkg/util" -) - -// 解析时间 -// 时间字符串格式:2006-01-02 15:04:05 -func ParseDateTime(timeStr string) (datetime time.Time) { - datetime, _ = time.ParseInLocation(TimeLayout, timeStr, time.Local) - return -} - -// 解析日期 -// 日期字符串格式:2006-01-02 -func ParseDate(timeStr string) (date time.Time) { - date, _ = time.ParseInLocation(DateLayout, timeStr, time.Local) - return -} - -// 格式化Datetime字符串 -// 格式化前输入样式:2019-01-04T15:40:00Z 或 2019-01-04T15:40:00+08:00 -// 格式化后返回样式:2019-01-04 15:40:00 -func FormatDateTime(timeStr string) (formatTime string) { - if timeStr == util.NULL { - return util.NULL - } - replace := strings.Replace(timeStr, "T", " ", 1) - formatTime = replace[:19] - return -} - -// 格式化Date成字符串 -// 格式化前输入样式:2019-01-04T15:40:00Z 或 2019-01-04T15:40:00+08:00 -// 格式化后返回样式:2019-01-04 -func FormatDate(dateStr string) (formatDate string) { - if dateStr == util.NULL { - return util.NULL - } - split := strings.Split(dateStr, "T") - formatDate = split[0] - return -} - -func DurationToUnit(duration time.Duration) string { - var ( - t string - intNs = int(duration) - ) - if intNs >= 0 && intNs < int(time.Second) { - t = util.Int2String(intNs/int(time.Millisecond)) + "ms" - } - - // 大于等于 1秒,小于 1分钟 - if intNs >= int(time.Second) && intNs < int(time.Minute) { - s := intNs / int(time.Second) - ms := (intNs - s*int(time.Second)) / int(time.Millisecond) - t = util.Int2String(s) + "s" - if ms > 0 { - t += util.Int2String(ms) + "ms" - } - } - // 大于等于 1分钟,小于 1小时 - if intNs >= int(time.Minute) && intNs < int(time.Hour) { - m := intNs / int(time.Minute) - s := (intNs - m*int(time.Minute)) / int(time.Second) - t = util.Int2String(m) + "m" - if s > 0 { - t += util.Int2String(s) + "s" - } - } - // 大于等于 1小时,小于 1天 - if intNs >= int(time.Hour) && intNs < 24*int(time.Hour) { - h := intNs / int(time.Hour) - m := (intNs - h*int(time.Hour)) / int(time.Minute) - s := (intNs - h*int(time.Hour) - m*int(time.Minute)) / int(time.Second) - t = util.Int2String(h) + "h" - if m > 0 { - t += util.Int2String(m) + "m" - } - if s > 0 { - t += util.Int2String(s) + "s" - } - } - // 大于等于 1天 - if intNs >= 24*int(time.Hour) { - d := intNs / (24 * int(time.Hour)) - h := (intNs - d*24*int(time.Hour)) / int(time.Hour) - m := (intNs - d*24*int(time.Hour) - h*int(time.Hour)) / int(time.Minute) - s := ((intNs - m*int(time.Minute)) % int(time.Minute)) / int(time.Second) - - t = util.Int2String(d) + "d" - if h > 0 { - t += util.Int2String(h) + "h" - } - if m > 0 { - t += util.Int2String(m) + "m" - } - if s > 0 { - t += util.Int2String(s) + "s" - } - } - return t -} diff --git a/pkg/xtime/xtime.go b/pkg/xtime/xtime.go deleted file mode 100644 index f23c5dc..0000000 --- a/pkg/xtime/xtime.go +++ /dev/null @@ -1,78 +0,0 @@ -package xtime - -import ( - "context" - "database/sql/driver" - "strconv" - "time" -) - -// Time be used to MySql timestamp converting. -type Time int64 - -// Scan scan time. -func (t *Time) Scan(src any) (err error) { - switch sc := src.(type) { - case time.Time: - *t = Time(sc.Unix()) - case string: - var i int64 - i, err = strconv.ParseInt(sc, 10, 64) - *t = Time(i) - } - return -} - -// Value get time value. -func (t Time) Value() (driver.Value, error) { - return time.Unix(int64(t), 0), nil -} - -// Time get time. -func (t Time) Time() time.Time { - return time.Unix(int64(t), 0) -} - -func (t *Time) FromDB(bs []byte) error { - timeStr := string(bs) - ti, err := time.ParseInLocation("2006-01-02T15:04:05", timeStr[:19], time.Local) - if err != nil { - return err - } - *t = Time(ti.Unix()) - return nil -} - -func (t Time) ToDB() ([]byte, error) { - unix := time.Unix(int64(t), 0) - return []byte(unix.String()), nil -} - -// Duration be used json unmarshal string time, like 1s, 500ms. -type Duration time.Duration - -// UnmarshalText unmarshal text to duration. -func (d *Duration) UnmarshalText(text []byte) error { - tmp, err := time.ParseDuration(string(text)) - if err == nil { - *d = Duration(tmp) - } - return err -} - -// UnitTime duration parse to unit, such as "300ms", "1h30m" or "2h10s". -func (d *Duration) UnitTime() string { - return DurationToUnit(time.Duration(*d)) -} - -// Shrink will decrease the duration by comparing with context's timeout duration and return new timeout\context\CancelFunc. -func (d Duration) Shrink(c context.Context) (Duration, context.Context, context.CancelFunc) { - if deadline, ok := c.Deadline(); ok { - if ctimeout := time.Until(deadline); ctimeout < time.Duration(d) { - // deliver small timeout - return Duration(ctimeout), c, func() {} - } - } - ctx, cancel := context.WithTimeout(c, time.Duration(d)) - return d, ctx, cancel -} diff --git a/pkg/xtime/xtime_test.go b/pkg/xtime/xtime_test.go deleted file mode 100644 index fb23cd3..0000000 --- a/pkg/xtime/xtime_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package xtime - -import ( - "encoding/json" - "testing" - - "github.com/go-pay/wechat-sdk/pkg/xlog" -) - -type TimeParser struct { - T1 Duration `json:"t1"` - T2 Duration `json:"t2"` - T3 Duration `json:"t3"` - T4 Duration `json:"t4"` -} - -func TestParseTime(t *testing.T) { - parseText := ` -{ - "t1":"10s", - "t2":"1m20s", - "t3":"5m", - "t4":"1h10m10s" -}` - tp := new(TimeParser) - err := json.Unmarshal([]byte(parseText), tp) - if err != nil { - xlog.Error(err) - return - } - - xlog.Infof("%+v", tp) - - xlog.Debugf("t1: %s", tp.T1.UnitTime()) - xlog.Debugf("t2: %s", tp.T2.UnitTime()) - xlog.Debugf("t3: %s", tp.T3.UnitTime()) - xlog.Debugf("t4: %s", tp.T4.UnitTime()) -} diff --git a/public/access_token.go b/public/access_token.go index 6f4df61..df1b99b 100644 --- a/public/access_token.go +++ b/public/access_token.go @@ -4,8 +4,6 @@ import ( "fmt" "runtime" "time" - - "github.com/go-pay/wechat-sdk/pkg/xlog" ) // 获取公众号全局唯一后台接口调用凭据(access_token) @@ -23,7 +21,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 { @@ -43,7 +41,7 @@ func (s *SDK) goAutoRefreshAccessToken() { if r := recover(); r != nil { buf := make([]byte, 64<<10) buf = buf[:runtime.Stack(buf, false)] - xlog.Errorf("public_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf) + s.logger.Errorf("public_goAutoRefreshAccessToken: panic recovered: %s\n%s", r, buf) } }() for { @@ -51,7 +49,7 @@ func (s *SDK) goAutoRefreshAccessToken() { 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 } } diff --git a/public/account_manage.go b/public/account_manage.go index 26d8e10..57f2c5b 100644 --- a/public/account_manage.go +++ b/public/account_manage.go @@ -4,17 +4,17 @@ import ( "context" "fmt" - "github.com/go-pay/wechat-sdk/pkg/bmap" + "github.com/go-pay/bm" ) // QRCodeCreate 生成带参数的二维码 // 注意:errcode = 0 为成功 // 注意:expire_seconds 字段不传,代表永久二维码。 // 文档:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/Generating_a_Parametric_QR_Code.html -func (s *SDK) QRCodeCreate(c context.Context, body bmap.BodyMap) (qr *QRCodeRsp, err error) { +func (s *SDK) QRCodeCreate(c context.Context, body bm.BodyMap) (qr *QRCodeRsp, err error) { path := "/cgi-bin/qrcode/create?access_token=" + s.accessToken qr = &QRCodeRsp{} - if err = s.doRequestPost(c, path, body, qr); err != nil { + if _, err = s.doRequestPost(c, path, body, qr); err != nil { return nil, err } if qr.Errcode != Success { @@ -26,10 +26,10 @@ func (s *SDK) QRCodeCreate(c context.Context, body bmap.BodyMap) (qr *QRCodeRsp, // ShortKeyGen 生成短key托管 // 注意:errcode = 0 为成功 // 文档:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/KEY_Shortener.html -func (s *SDK) ShortKeyGen(c context.Context, body bmap.BodyMap) (skg *ShortKeyGenRsp, err error) { +func (s *SDK) ShortKeyGen(c context.Context, body bm.BodyMap) (skg *ShortKeyGenRsp, err error) { path := "/cgi-bin/shorten/gen?access_token=" + s.accessToken skg = &ShortKeyGenRsp{} - if err = s.doRequestPost(c, path, body, skg); err != nil { + if _, err = s.doRequestPost(c, path, body, skg); err != nil { return nil, err } if skg.Errcode != Success { @@ -44,10 +44,10 @@ func (s *SDK) ShortKeyGen(c context.Context, body bmap.BodyMap) (skg *ShortKeyGe // 文档:https://developers.weixin.qq.com/doc/offiaccount/Account_Management/KEY_Shortener.html func (s *SDK) ShortKeyFetch(c context.Context, shortKey string) (skf *ShortKeyFetchRsp, err error) { path := "/cgi-bin/shorten/fetch?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("short_key", shortKey) skf = &ShortKeyFetchRsp{} - if err = s.doRequestPost(c, path, body, skf); err != nil { + if _, err = s.doRequestPost(c, path, body, skf); err != nil { return nil, err } if skf.Errcode != Success { diff --git a/public/model.go b/public/model.go index b944fa2..614a3d7 100644 --- a/public/model.go +++ b/public/model.go @@ -1,6 +1,6 @@ package public -import "github.com/go-pay/wechat-sdk/pkg/xtime" +import "github.com/go-pay/xtime" const ( Success = 0 diff --git a/public/public.go b/public/public.go index 95ca0ec..7f9d8ab 100644 --- a/public/public.go +++ b/public/public.go @@ -2,14 +2,15 @@ package public 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 { @@ -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) } @@ -29,12 +32,16 @@ type SDK struct { // Secret:appSecret // autoManageToken:是否自动获取并自动维护刷新 AccessToken func New(appid, secret string, autoManageToken bool) (p *SDK, err error) { + logger := xlog.NewLogger() + logger.SetLevel(xlog.DebugLevel) p = &SDK{ ctx: context.Background(), DebugSwitch: wechat.DebugOff, Appid: appid, Secret: secret, Host: HostDefault, + hc: xhttp.NewClient(), + logger: logger, } if autoManageToken { if err = p.getAccessToken(); err != nil { @@ -45,22 +52,35 @@ func New(appid, secret string, autoManageToken bool) (p *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 + return res, nil } diff --git a/public/public_test.go b/public/public_test.go index 056851c..7786c39 100644 --- a/public/public_test.go +++ b/public/public_test.go @@ -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 ( @@ -20,6 +20,7 @@ var ( ) func TestMain(m *testing.M) { + xlog.SetLevel(xlog.DebugLevel) // 初始化微信公众号 SDK // Appid:Appid // Secret:appSecret @@ -53,12 +54,12 @@ func TestMain(m *testing.M) { } func TestQRCodeCreate(t *testing.T) { - body := make(bmap.BodyMap) + body := make(bm.BodyMap) // 临时二维码 body.Set("expire_seconds", 604800). Set("action_name", "QR_SCENE"). - SetBodyMap("action_info", func(b bmap.BodyMap) { - b.SetBodyMap("scene", func(b bmap.BodyMap) { + SetBodyMap("action_info", func(b bm.BodyMap) { + b.SetBodyMap("scene", func(b bm.BodyMap) { b.Set("scene_id", 123) }) }) @@ -74,8 +75,8 @@ func TestQRCodeCreate(t *testing.T) { // 永久二维码 body.Set("action_name", "QR_LIMIT_SCENE"). - SetBodyMap("action_info", func(b bmap.BodyMap) { - b.SetBodyMap("scene", func(b bmap.BodyMap) { + SetBodyMap("action_info", func(b bm.BodyMap) { + b.SetBodyMap("scene", func(b bm.BodyMap) { b.Set("scene_id", 456) }) }) @@ -88,7 +89,7 @@ func TestQRCodeCreate(t *testing.T) { } func TestShortKeyGen(t *testing.T) { - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("long_data", "loooooong data"). Set("expire_seconds", 86400) diff --git a/public/request.go b/public/request.go index 4907f3a..d920db9 100644 --- a/public/request.go +++ b/public/request.go @@ -2,96 +2,53 @@ package public import ( "context" - "encoding/json" "fmt" + "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" - "github.com/go-pay/wechat-sdk/pkg/bmap" - "github.com/go-pay/wechat-sdk/pkg/util" - "github.com/go-pay/wechat-sdk/pkg/xhttp" - "github.com/go-pay/wechat-sdk/pkg/xlog" ) -func (s *SDK) doRequestGet(c context.Context, path string, ptr any) (err error) { +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_Public_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Public_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_Public_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Public_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 + return res, nil } -//func (s *SDK) doRequestGetByte(c context.Context, path string) (bs []byte, err error) { -// uri := s.Host + path -// httpClient := xhttp.NewClient() -// if s.DebugSwitch == wechat.DebugOn { -// xlog.Debugf("Wechat_Public_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) -// if err != nil { -// return nil, fmt.Errorf("http.request(GET, %s), status_code:%d, err:%w", uri, res.StatusCode, err) -// } -// if s.DebugSwitch == wechat.DebugOn { -// xlog.Debugf("Wechat_Public_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) -// } -// ec := &ErrorCode{} -// // 如果解析成功,说明获取buffer文件失败 -// if err = json.Unmarshal(bs, ec); err == nil { -// return nil, fmt.Errorf("errcode(%d),errmsg(%s)", ec.Errcode, ec.Errmsg) -// } -// return -//} - -func (s *SDK) doRequestPost(c context.Context, path string, body bmap.BodyMap, ptr any) (err error) { +func (s *SDK) doRequestPost(c context.Context, path string, body bm.BodyMap, ptr any) (res *http.Response, err error) { uri := s.Host + path - httpClient := xhttp.NewClient() if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Public_SDK_URI: %s", uri) - xlog.Debugf("Wechat_Public_SDK_RequestBody: %s", body.JsonBody()) + s.logger.Debugf("Wechat_Public_SDK_URI: %s", uri) + s.logger.Debugf("Wechat_Public_SDK_RequestBody: %s", body.JsonBody()) } - httpClient.Header.Add(xhttp.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix())) - res, bs, err := httpClient.Post(uri).SendBodyMap(body).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.Post(uri).SendBodyMap(body).EndBytes(c) if err != nil { - return fmt.Errorf("http.request(POST, %s), status_code:%d, err:%w", uri, res.StatusCode, err) + return nil, fmt.Errorf("http.request(POST, %s), err:%w", uri, err) } if s.DebugSwitch == wechat.DebugOn { - xlog.Debugf("Wechat_Public_SDK_Response: [%d] -> %s", res.StatusCode, string(bs)) + s.logger.Debugf("Wechat_Public_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 + return res, nil } - -//func (s *SDK) doRequestPostFile(ctx context.Context, path string, body bmap.BodyMap, ptr any) (err error) { -// uri := s.Host + path -// httpClient := xhttp.NewClient() -// if s.DebugSwitch == wechat.DebugOn { -// xlog.Debugf("Wechat_Public_SDK_URI: %s", uri) -// } -// httpClient.Header.Add(xhttp.HeaderRequestID, fmt.Sprintf("%s-%d", util.RandomString(21), time.Now().Unix())) -// res, bs, err := httpClient.Type(xhttp.TypeMultipartFormData).Post(uri).SendMultipartBodyMap(body).EndBytes(ctx) -// if err != nil { -// return fmt.Errorf("http.request(POST, %s), status_code:%d, err:%w", uri, res.StatusCode, err) -// } -// if s.DebugSwitch == wechat.DebugOn { -// xlog.Debugf("Wechat_Public_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) -// } -// return -//} diff --git a/public/sign.go b/public/sign.go index 7b1bce2..ce7c21d 100644 --- a/public/sign.go +++ b/public/sign.go @@ -4,17 +4,18 @@ import ( "crypto/sha1" "encoding/hex" - "github.com/go-pay/wechat-sdk/pkg/bmap" + "github.com/go-pay/bm" ) // JsSDKUsePermissionSign 获取JS-SDK使用权限签名 // 文档介绍:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#62 func JsSDKUsePermissionSign(jsapiTicket, nonceStr, url string, timestamp int) (sign string) { - bm := make(bmap.BodyMap) - params := bm.Set("jsapi_ticket", jsapiTicket). + body := make(bm.BodyMap) + params := body.Set("jsapi_ticket", jsapiTicket). Set("noncestr", nonceStr). Set("timestamp", timestamp). - Set("url", url).EncodeSortedSignParams() + Set("url", url). + EncodeURLParams() hash := sha1.New() hash.Write([]byte(params)) sign = hex.EncodeToString(hash.Sum(nil)) diff --git a/public/sign_test.go b/public/sign_test.go index 06f8f19..d7c0153 100644 --- a/public/sign_test.go +++ b/public/sign_test.go @@ -3,7 +3,7 @@ package public import ( "testing" - "github.com/go-pay/wechat-sdk/pkg/xlog" + "github.com/go-pay/xlog" ) func TestJsSDKUsePermissionSign(t *testing.T) { diff --git a/public/ticket.go b/public/ticket.go index 03536c9..7b76914 100644 --- a/public/ticket.go +++ b/public/ticket.go @@ -11,7 +11,7 @@ import ( func (s *SDK) GetJsApiTicket(c context.Context) (jt *TicketRsp, err error) { path := "/cgi-bin/ticket/getticket?access_token=" + s.accessToken + "&type=jsapi" jt = &TicketRsp{} - if err = s.doRequestGet(c, path, jt); err != nil { + if _, err = s.doRequestGet(c, path, jt); err != nil { return nil, err } if jt.Errcode != Success { @@ -27,7 +27,7 @@ func (s *SDK) GetApiTicket(c context.Context) (at *TicketRsp, err error) { // /cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card path := "/cgi-bin/ticket/getticket?access_token=" + s.accessToken + "&type=wx_card" at = &TicketRsp{} - if err = s.doRequestGet(c, path, at); err != nil { + if _, err = s.doRequestGet(c, path, at); err != nil { return nil, err } if at.Errcode != Success { diff --git a/public/user_manage.go b/public/user_manage.go index a0f1e91..adcc9c3 100644 --- a/public/user_manage.go +++ b/public/user_manage.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/go-pay/wechat-sdk/pkg/bmap" + "github.com/go-pay/bm" ) // UserTagCreate 用户标签创建 @@ -13,12 +13,12 @@ import ( // 文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/User_Tag_Management.html func (s *SDK) UserTagCreate(c context.Context, tagName string) (ut *UserTagRsp, err error) { path := "/cgi-bin/tags/create?access_token=" + s.accessToken - body := make(bmap.BodyMap) - body.SetBodyMap("tag", func(b bmap.BodyMap) { + body := make(bm.BodyMap) + body.SetBodyMap("tag", func(b bm.BodyMap) { b.Set("name", tagName) }) ut = &UserTagRsp{} - if err = s.doRequestPost(c, path, body, ut); err != nil { + if _, err = s.doRequestPost(c, path, body, ut); err != nil { return nil, err } if ut.Errcode != Success { @@ -33,7 +33,7 @@ func (s *SDK) UserTagCreate(c context.Context, tagName string) (ut *UserTagRsp, func (s *SDK) UserTagList(c context.Context) (utl *UserTagListRsp, err error) { path := "/cgi-bin/tags/get?access_token=" + s.accessToken utl = &UserTagListRsp{} - if err = s.doRequestGet(c, path, utl); err != nil { + if _, err = s.doRequestGet(c, path, utl); err != nil { return nil, err } if utl.Errcode != Success { @@ -47,13 +47,13 @@ func (s *SDK) UserTagList(c context.Context) (utl *UserTagListRsp, err error) { // 文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/User_Tag_Management.html func (s *SDK) UserTagUpdate(c context.Context, tagId int, tagName string) (err error) { path := "/cgi-bin/tags/update?access_token=" + s.accessToken - body := make(bmap.BodyMap) - body.SetBodyMap("tag", func(b bmap.BodyMap) { + body := make(bm.BodyMap) + body.SetBodyMap("tag", func(b bm.BodyMap) { b.Set("id", tagId) b.Set("name", tagName) }) 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 { @@ -67,12 +67,12 @@ func (s *SDK) UserTagUpdate(c context.Context, tagId int, tagName string) (err e // 文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/User_Tag_Management.html func (s *SDK) UserTagDelete(c context.Context, tagId int) (err error) { path := "/cgi-bin/tags/delete?access_token=" + s.accessToken - body := make(bmap.BodyMap) - body.SetBodyMap("tag", func(b bmap.BodyMap) { + body := make(bm.BodyMap) + body.SetBodyMap("tag", func(b bm.BodyMap) { b.Set("id", tagId) }) 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 { @@ -87,13 +87,13 @@ func (s *SDK) UserTagDelete(c context.Context, tagId int) (err error) { // 文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/User_Tag_Management.html func (s *SDK) UserTagFansList(c context.Context, tagId int, openid string) (utf *UserTagFansListRsp, err error) { path := "/cgi-bin/user/tag/get?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("tagid", tagId) if openid != "" { body.Set("next_openid", openid) } utf = &UserTagFansListRsp{} - if err = s.doRequestPost(c, path, body, utf); err != nil { + if _, err = s.doRequestPost(c, path, body, utf); err != nil { return nil, err } if utf.Errcode != Success { @@ -110,11 +110,11 @@ func (s *SDK) UserTagBatchTagging(c context.Context, tagId int, openidList []str return errors.New("openid_list is empty") } path := "/cgi-bin/tags/members/batchtagging?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("tagid", tagId) body.Set("openid_list", openidList) 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 { @@ -131,11 +131,11 @@ func (s *SDK) UserTagBatchUnTagging(c context.Context, tagId int, openidList []s return errors.New("openid_list is empty") } path := "/cgi-bin/tags/members/batchuntagging?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("tagid", tagId) body.Set("openid_list", openidList) 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 { @@ -152,10 +152,10 @@ func (s *SDK) UserTagIdList(c context.Context, openid string) (uti *UserTagIdLis return nil, errors.New("openid is empty") } path := "/cgi-bin/tags/getidlist?access_token=" + s.accessToken - body := make(bmap.BodyMap) + body := make(bm.BodyMap) body.Set("openid", openid) uti = &UserTagIdListRsp{} - if err = s.doRequestPost(c, path, body, uti); err != nil { + if _, err = s.doRequestPost(c, path, body, uti); err != nil { return nil, err } if uti.Errcode != Success { diff --git a/release_note.txt b/release_note.txt index ecf1fc6..10336fb 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1,3 +1,7 @@ +版本号:Release 1.1.6 +修改记录: + (1) big change + 版本号:Release 1.1.5 修改记录: (1) 微信公众号:新增 ticket获取,js-sdk使用校验签名接口