wechat_client.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package wechat
  2. import (
  3. "eta_mini_ht_api/component/cache"
  4. config2 "eta_mini_ht_api/component/config"
  5. "eta_mini_ht_api/component/log"
  6. "github.com/medivhzhan/weapp/v3/auth"
  7. "github.com/medivhzhan/weapp/v3/request"
  8. "github.com/mitchellh/mapstructure"
  9. "net/http"
  10. "sync"
  11. )
  12. const (
  13. baseURL = "https://api.weixin.qq.com"
  14. )
  15. var (
  16. wechatClient *Client
  17. once sync.Once
  18. )
  19. type Client struct {
  20. // HTTP请求客户端
  21. request *request.Request
  22. // 数据缓存器
  23. cache *cache.RedisCache
  24. // 日志记录器
  25. logger logger.Logger
  26. // 小程序后台配置: 小程序ID
  27. appid string
  28. // 小程序后台配置: 小程序密钥
  29. secret string
  30. // 用户自定义获取access_token的方法
  31. accessTokenGetter AccessTokenGetter
  32. }
  33. func GetInstance() *Client {
  34. once.Do(func() {
  35. wechatConf, ok := config2.GetConfig("wechat").(*config2.WechatConfig)
  36. if !ok {
  37. // 处理错误情况,比如记录日志或返回错误信息
  38. logger.Info("加载wechat配置失败")
  39. return // 或者采取其他适当的错误处理措施
  40. }
  41. opts, ok := wechatConf.GetConfig().(config2.WechatOpts)
  42. if !ok {
  43. // 处理错误情况,比如记录日志或返回错误信息
  44. logger.Info("加载wechat配置失败")
  45. return // 或者采取其他适当的错误处理措施
  46. }
  47. // 默认配置
  48. wechatClient = NewClient(opts.Appid, opts.Secret,
  49. WithHttpClient(http.DefaultClient),
  50. WithCache(cache.GetInstance()),
  51. WithLogger(logger.GetInstance()),
  52. )
  53. })
  54. return wechatClient
  55. }
  56. // AccessTokenGetter 用户自定义获取access_token的方法
  57. type AccessTokenGetter func(appid, secret string) (token string, expireIn uint)
  58. // NewClient 初始化客户端并用自定义配置替换默认配置
  59. func NewClient(appid, secret string, opts ...func(*Client)) *Client {
  60. cli := &Client{
  61. appid: appid,
  62. secret: secret,
  63. }
  64. // 执行额外的配置函数
  65. for _, fn := range opts {
  66. fn(cli)
  67. }
  68. if cli.cache == nil {
  69. //cli.cache = cache.NewMemoryCache()
  70. }
  71. if cli.request == nil {
  72. //cli.request = request.NewRequest(http.DefaultClient, request.ContentTypeJSON, cli.Logger)
  73. }
  74. if cli.logger == nil {
  75. //cli.logger = logger.NewLogger(log.New(os.Stdout, "\r\n", log.LstdFlags), logger.Info, true)
  76. }
  77. return cli
  78. }
  79. // WithHttpClient 自定义 HTTP Client
  80. func WithHttpClient(hc *http.Client) func(*Client) {
  81. return func(cli *Client) {
  82. //cli.request = request.NewRequest(hc, request.ContentTypeJSON, cli.Logger)
  83. }
  84. }
  85. // WithCache 自定义缓存
  86. func WithCache(cc *cache.RedisCache) func(*Client) {
  87. return func(cli *Client) {
  88. cli.cache = cc
  89. }
  90. }
  91. // WithAccessTokenSetter 自定义获取access_token的方法
  92. func WithAccessTokenSetter(getter AccessTokenGetter) func(*Client) {
  93. return func(cli *Client) {
  94. cli.accessTokenGetter = getter
  95. }
  96. }
  97. // WithLogger 自定义日志
  98. func WithLogger(logger logger.Logger) func(*Client) {
  99. return func(cli *Client) {
  100. cli.logger = logger
  101. }
  102. }
  103. // POST 参数
  104. type requestParams map[string]interface{}
  105. // URL 参数
  106. type requestQueries map[string]interface{}
  107. // tokenAPI 获取带 token 的 API 地址
  108. func tokenAPI(api, token string) (string, error) {
  109. queries := requestQueries{
  110. "access_token": token,
  111. }
  112. return request.EncodeURL(api, queries)
  113. }
  114. // convert bool to int
  115. func bool2int(ok bool) uint8 {
  116. if ok {
  117. return 1
  118. }
  119. return 0
  120. }
  121. // Logger 获取日志记录器
  122. func (cli *Client) Logger() logger.Logger { return cli.logger }
  123. // AccessToken 获取小程序全局唯一后台接口调用凭据(access_token)。
  124. // 调调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存,注意缓存。
  125. func (cli *Client) AccessToken() (string, error) {
  126. return "", nil
  127. ////key := cli.tokenCacheKey()
  128. //data, ok := cli.cache.Get(key)
  129. //if ok {
  130. // return data.(string), nil
  131. //}
  132. //
  133. //if cli.accessTokenGetter != nil {
  134. //// token, expireIn := cli.accessTokenGetter(cli.appid, cli.secret)
  135. // //cli.cache.Set(key, token, time.Duration(expireIn)*time.Second)
  136. //// return token, nil
  137. //} else {
  138. //
  139. // req := auth.GetStableAccessTokenRequest{
  140. // Appid: cli.appid,
  141. // Secret: cli.secret,
  142. // GrantType: "client_credential",
  143. // }
  144. // rsp, err := cli.NewAuth().GetStableAccessToken(&req)
  145. // if err != nil {
  146. // return "", err
  147. // }
  148. //
  149. // if err := rsp.GetResponseError(); err != nil {
  150. // return "", err
  151. // }
  152. //
  153. // err = cli.cache.SetString(key, rsp.AccessToken, time.Duration(rsp.ExpiresIn)*time.Second)
  154. // if err != nil {
  155. // return "", err
  156. // }
  157. // return rsp.AccessToken, nil
  158. //}
  159. }
  160. // 拼凑完整的 URI
  161. func (cli *Client) combineURI(url string, req interface{}, withToken bool) (string, error) {
  162. output := make(map[string]interface{})
  163. config := &mapstructure.DecoderConfig{
  164. Metadata: nil,
  165. Result: &output,
  166. TagName: "query",
  167. }
  168. decoder, err := mapstructure.NewDecoder(config)
  169. if err != nil {
  170. return "", err
  171. }
  172. err = decoder.Decode(req)
  173. if err != nil {
  174. return "", err
  175. }
  176. if withToken {
  177. token, err := cli.AccessToken()
  178. if err != nil {
  179. return "", err
  180. }
  181. output["access_token"] = token
  182. }
  183. return request.EncodeURL(baseURL+url, output)
  184. }
  185. // NewAuth 用户信息
  186. func (cli *Client) NewAuth() *auth.Auth {
  187. return auth.NewAuth(cli.request, cli.combineURI)
  188. }