123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- package wechat
- 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"
- "net/http"
- "sync"
- )
- const (
- baseURL = "https://api.weixin.qq.com"
- )
- var (
- wechatClient *Client
- once sync.Once
- )
- type Client struct {
- // HTTP请求客户端
- request *request.Request
- // 数据缓存器
- cache *cache.RedisCache
- // 日志记录器
- logger logger.Logger
- // 小程序后台配置: 小程序ID
- appid string
- // 小程序后台配置: 小程序密钥
- secret string
- // 用户自定义获取access_token的方法
- accessTokenGetter AccessTokenGetter
- }
- func GetInstance() *Client {
- once.Do(func() {
- wechatConf, ok := config2.GetConfig("wechat").(*config2.WechatConfig)
- if !ok {
- // 处理错误情况,比如记录日志或返回错误信息
- logger.Info("加载wechat配置失败")
- return // 或者采取其他适当的错误处理措施
- }
- opts, ok := wechatConf.GetConfig().(config2.WechatOpts)
- if !ok {
- // 处理错误情况,比如记录日志或返回错误信息
- logger.Info("加载wechat配置失败")
- return // 或者采取其他适当的错误处理措施
- }
- // 默认配置
- wechatClient = NewClient(opts.Appid, opts.Secret,
- WithHttpClient(http.DefaultClient),
- WithCache(cache.GetInstance()),
- WithLogger(logger.GetInstance()),
- )
- })
- return wechatClient
- }
- // AccessTokenGetter 用户自定义获取access_token的方法
- type AccessTokenGetter func(appid, secret string) (token string, expireIn uint)
- // NewClient 初始化客户端并用自定义配置替换默认配置
- func NewClient(appid, secret string, opts ...func(*Client)) *Client {
- cli := &Client{
- appid: appid,
- secret: secret,
- }
- // 执行额外的配置函数
- for _, fn := range opts {
- 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
- }
- // WithHttpClient 自定义 HTTP Client
- func WithHttpClient(hc *http.Client) func(*Client) {
- return func(cli *Client) {
- //cli.request = request.NewRequest(hc, request.ContentTypeJSON, cli.Logger)
- }
- }
- // WithCache 自定义缓存
- func WithCache(cc *cache.RedisCache) func(*Client) {
- return func(cli *Client) {
- cli.cache = cc
- }
- }
- // WithAccessTokenSetter 自定义获取access_token的方法
- func WithAccessTokenSetter(getter AccessTokenGetter) func(*Client) {
- return func(cli *Client) {
- cli.accessTokenGetter = getter
- }
- }
- // WithLogger 自定义日志
- func WithLogger(logger logger.Logger) func(*Client) {
- return func(cli *Client) {
- cli.logger = logger
- }
- }
- // 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,
- }
- return request.EncodeURL(api, queries)
- }
- // convert bool to int
- func bool2int(ok bool) uint8 {
- if ok {
- return 1
- }
- return 0
- }
- // 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
- //}
- }
- // 拼凑完整的 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)
- if err != nil {
- 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)
- }
|