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) }