|
@@ -1,18 +1,25 @@
|
|
package wechat
|
|
package wechat
|
|
|
|
|
|
import (
|
|
import (
|
|
- "eta_mini_ht_api/component/cache"
|
|
|
|
- config2 "eta_mini_ht_api/component/config"
|
|
|
|
- "eta_mini_ht_api/component/log"
|
|
|
|
- "github.com/medivhzhan/weapp/v3/auth"
|
|
|
|
- "github.com/medivhzhan/weapp/v3/request"
|
|
|
|
- "github.com/mitchellh/mapstructure"
|
|
|
|
|
|
+ "encoding/json"
|
|
|
|
+ "errors"
|
|
|
|
+ "eta_mini_ht_api/common/component/config"
|
|
|
|
+ "eta_mini_ht_api/common/component/log"
|
|
|
|
+ "eta_mini_ht_api/common/component/wechat/we_http"
|
|
|
|
+ "eta_mini_ht_api/common/contants"
|
|
|
|
+ "eta_mini_ht_api/common/utils/client"
|
|
"net/http"
|
|
"net/http"
|
|
|
|
+ "net/url"
|
|
"sync"
|
|
"sync"
|
|
)
|
|
)
|
|
|
|
|
|
const (
|
|
const (
|
|
baseURL = "https://api.weixin.qq.com"
|
|
baseURL = "https://api.weixin.qq.com"
|
|
|
|
+ codeAPI = "/sns/jscode2session"
|
|
|
|
+)
|
|
|
|
+const (
|
|
|
|
+ // WeChatServerError 微信服务器错误时返回返回消息
|
|
|
|
+ WeChatServerError = "微信服务器发生错误"
|
|
)
|
|
)
|
|
|
|
|
|
var (
|
|
var (
|
|
@@ -22,39 +29,24 @@ var (
|
|
|
|
|
|
type Client struct {
|
|
type Client struct {
|
|
// HTTP请求客户端
|
|
// HTTP请求客户端
|
|
- request *request.Request
|
|
|
|
- // 数据缓存器
|
|
|
|
- cache *cache.RedisCache
|
|
|
|
- // 日志记录器
|
|
|
|
- logger logger.Logger
|
|
|
|
|
|
+ client *client.HttpClient
|
|
// 小程序后台配置: 小程序ID
|
|
// 小程序后台配置: 小程序ID
|
|
appid string
|
|
appid string
|
|
// 小程序后台配置: 小程序密钥
|
|
// 小程序后台配置: 小程序密钥
|
|
secret string
|
|
secret string
|
|
- // 用户自定义获取access_token的方法
|
|
|
|
- accessTokenGetter AccessTokenGetter
|
|
|
|
}
|
|
}
|
|
|
|
|
|
func GetInstance() *Client {
|
|
func GetInstance() *Client {
|
|
once.Do(func() {
|
|
once.Do(func() {
|
|
- wechatConf, ok := config2.GetConfig("wechat").(*config2.WechatConfig)
|
|
|
|
- if !ok {
|
|
|
|
- // 处理错误情况,比如记录日志或返回错误信息
|
|
|
|
- logger.Info("加载wechat配置失败")
|
|
|
|
- return // 或者采取其他适当的错误处理措施
|
|
|
|
- }
|
|
|
|
- opts, ok := wechatConf.GetConfig().(config2.WechatOpts)
|
|
|
|
|
|
+ wechatConf, ok := config.GetConfig(contants.WECHAT).(*config.WechatConfig)
|
|
if !ok {
|
|
if !ok {
|
|
// 处理错误情况,比如记录日志或返回错误信息
|
|
// 处理错误情况,比如记录日志或返回错误信息
|
|
logger.Info("加载wechat配置失败")
|
|
logger.Info("加载wechat配置失败")
|
|
return // 或者采取其他适当的错误处理措施
|
|
return // 或者采取其他适当的错误处理措施
|
|
}
|
|
}
|
|
// 默认配置
|
|
// 默认配置
|
|
- wechatClient = NewClient(opts.Appid, opts.Secret,
|
|
|
|
- WithHttpClient(http.DefaultClient),
|
|
|
|
- WithCache(cache.GetInstance()),
|
|
|
|
- WithLogger(logger.GetInstance()),
|
|
|
|
- )
|
|
|
|
|
|
+ wechatClient = NewClient(wechatConf.GetAppid(), wechatConf.GetSecret())//WithHttpClient(http.DefaultClient),
|
|
|
|
+
|
|
})
|
|
})
|
|
return wechatClient
|
|
return wechatClient
|
|
}
|
|
}
|
|
@@ -74,142 +66,73 @@ func NewClient(appid, secret string, opts ...func(*Client)) *Client {
|
|
fn(cli)
|
|
fn(cli)
|
|
}
|
|
}
|
|
|
|
|
|
- if cli.cache == nil {
|
|
|
|
- //cli.cache = cache.NewMemoryCache()
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if cli.request == nil {
|
|
|
|
- //cli.request = request.NewRequest(http.DefaultClient, request.ContentTypeJSON, cli.Logger)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if cli.logger == nil {
|
|
|
|
- //cli.logger = logger.NewLogger(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Info, true)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
return cli
|
|
return cli
|
|
}
|
|
}
|
|
|
|
|
|
// WithHttpClient 自定义 HTTP Client
|
|
// WithHttpClient 自定义 HTTP Client
|
|
-func WithHttpClient(hc *http.Client) func(*Client) {
|
|
|
|
|
|
+func WithHttpClient(hc *client.HttpClient) func(*Client) {
|
|
return func(cli *Client) {
|
|
return func(cli *Client) {
|
|
//cli.request = request.NewRequest(hc, request.ContentTypeJSON, cli.Logger)
|
|
//cli.request = request.NewRequest(hc, request.ContentTypeJSON, cli.Logger)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-// WithCache 自定义缓存
|
|
|
|
-func WithCache(cc *cache.RedisCache) func(*Client) {
|
|
|
|
- return func(cli *Client) {
|
|
|
|
- cli.cache = cc
|
|
|
|
- }
|
|
|
|
|
|
+type loginResponse struct {
|
|
|
|
+ we_http.BaseResponse
|
|
|
|
+ we_http.LoginResponse
|
|
}
|
|
}
|
|
|
|
|
|
-// WithAccessTokenSetter 自定义获取access_token的方法
|
|
|
|
-func WithAccessTokenSetter(getter AccessTokenGetter) func(*Client) {
|
|
|
|
- return func(cli *Client) {
|
|
|
|
- cli.accessTokenGetter = getter
|
|
|
|
|
|
+// 小程序登录
|
|
|
|
+func (cli *Client) Login(code string) (lres we_http.LoginResponse, err error) {
|
|
|
|
+ if code == "" {
|
|
|
|
+ err = errors.New("code不能为空")
|
|
|
|
+ return
|
|
}
|
|
}
|
|
-}
|
|
|
|
-
|
|
|
|
-// WithLogger 自定义日志
|
|
|
|
-func WithLogger(logger logger.Logger) func(*Client) {
|
|
|
|
- return func(cli *Client) {
|
|
|
|
- cli.logger = logger
|
|
|
|
|
|
+ api, err := code2url(cli.appid, cli.secret, code)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
}
|
|
}
|
|
-}
|
|
|
|
-
|
|
|
|
-// POST 参数
|
|
|
|
-type requestParams map[string]interface{}
|
|
|
|
-
|
|
|
|
-// URL 参数
|
|
|
|
-type requestQueries map[string]interface{}
|
|
|
|
-
|
|
|
|
-// tokenAPI 获取带 token 的 API 地址
|
|
|
|
-func tokenAPI(api, token string) (string, error) {
|
|
|
|
- queries := requestQueries{
|
|
|
|
- "access_token": token,
|
|
|
|
|
|
+ res, err := http.Get(api)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
}
|
|
}
|
|
|
|
+ defer res.Body.Close()
|
|
|
|
|
|
- return request.EncodeURL(api, queries)
|
|
|
|
-}
|
|
|
|
|
|
+ if res.StatusCode != 200 {
|
|
|
|
+ err = errors.New(WeChatServerError)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
|
|
-// convert bool to int
|
|
|
|
-func bool2int(ok bool) uint8 {
|
|
|
|
|
|
+ var data loginResponse
|
|
|
|
+ err = json.NewDecoder(res.Body).Decode(&data)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
|
|
- if ok {
|
|
|
|
- return 1
|
|
|
|
|
|
+ if data.Errcode != 0 {
|
|
|
|
+ err = errors.New(data.Errmsg)
|
|
|
|
+ return
|
|
}
|
|
}
|
|
|
|
|
|
- return 0
|
|
|
|
|
|
+ lres = data.LoginResponse
|
|
|
|
+ return
|
|
}
|
|
}
|
|
|
|
|
|
-// Logger 获取日志记录器
|
|
|
|
-func (cli *Client) Logger() logger.Logger { return cli.logger }
|
|
|
|
-
|
|
|
|
-// AccessToken 获取小程序全局唯一后台接口调用凭据(access_token)。
|
|
|
|
-// 调调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存,注意缓存。
|
|
|
|
-func (cli *Client) AccessToken() (string, error) {
|
|
|
|
- return "", nil
|
|
|
|
- ////key := cli.tokenCacheKey()
|
|
|
|
- //data, ok := cli.cache.Get(key)
|
|
|
|
- //if ok {
|
|
|
|
- // return data.(string), nil
|
|
|
|
- //}
|
|
|
|
- //
|
|
|
|
- //if cli.accessTokenGetter != nil {
|
|
|
|
- //// token, expireIn := cli.accessTokenGetter(cli.appid, cli.secret)
|
|
|
|
- // //cli.cache.Set(key, token, time.Duration(expireIn)*time.Second)
|
|
|
|
- //// return token, nil
|
|
|
|
- //} else {
|
|
|
|
- //
|
|
|
|
- // req := auth.GetStableAccessTokenRequest{
|
|
|
|
- // Appid: cli.appid,
|
|
|
|
- // Secret: cli.secret,
|
|
|
|
- // GrantType: "client_credential",
|
|
|
|
- // }
|
|
|
|
- // rsp, err := cli.NewAuth().GetStableAccessToken(&req)
|
|
|
|
- // if err != nil {
|
|
|
|
- // return "", err
|
|
|
|
- // }
|
|
|
|
- //
|
|
|
|
- // if err := rsp.GetResponseError(); err != nil {
|
|
|
|
- // return "", err
|
|
|
|
- // }
|
|
|
|
- //
|
|
|
|
- // err = cli.cache.SetString(key, rsp.AccessToken, time.Duration(rsp.ExpiresIn)*time.Second)
|
|
|
|
- // if err != nil {
|
|
|
|
- // return "", err
|
|
|
|
- // }
|
|
|
|
- // return rsp.AccessToken, nil
|
|
|
|
- //}
|
|
|
|
-}
|
|
|
|
|
|
+// 拼接 获取 session_key 的 URL
|
|
|
|
+func code2url(appID, secret, code string) (string, error) {
|
|
|
|
|
|
-// 拼凑完整的 URI
|
|
|
|
-func (cli *Client) combineURI(url string, req interface{}, withToken bool) (string, error) {
|
|
|
|
- output := make(map[string]interface{})
|
|
|
|
- config := &mapstructure.DecoderConfig{
|
|
|
|
- Metadata: nil,
|
|
|
|
- Result: &output,
|
|
|
|
- TagName: "query",
|
|
|
|
- }
|
|
|
|
- decoder, err := mapstructure.NewDecoder(config)
|
|
|
|
|
|
+ url, err := url.Parse(baseURL + codeAPI)
|
|
if err != nil {
|
|
if err != nil {
|
|
return "", err
|
|
return "", err
|
|
}
|
|
}
|
|
- err = decoder.Decode(req)
|
|
|
|
- if err != nil {
|
|
|
|
- return "", err
|
|
|
|
- }
|
|
|
|
- if withToken {
|
|
|
|
- token, err := cli.AccessToken()
|
|
|
|
- if err != nil {
|
|
|
|
- return "", err
|
|
|
|
- }
|
|
|
|
- output["access_token"] = token
|
|
|
|
- }
|
|
|
|
- return request.EncodeURL(baseURL+url, output)
|
|
|
|
-}
|
|
|
|
|
|
|
|
-// NewAuth 用户信息
|
|
|
|
-func (cli *Client) NewAuth() *auth.Auth {
|
|
|
|
- return auth.NewAuth(cli.request, cli.combineURI)
|
|
|
|
|
|
+ query := url.Query()
|
|
|
|
+
|
|
|
|
+ query.Set("appid", appID)
|
|
|
|
+ query.Set("secret", secret)
|
|
|
|
+ query.Set("js_code", code)
|
|
|
|
+ query.Set("grant_type", "authorization_code")
|
|
|
|
+
|
|
|
|
+ url.RawQuery = query.Encode()
|
|
|
|
+
|
|
|
|
+ return url.String(), nil
|
|
}
|
|
}
|