douyin.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package platformPay
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/sirupsen/logrus"
  6. "leafstalk/log"
  7. "net/http"
  8. "sort"
  9. "strconv"
  10. "strings"
  11. "time"
  12. )
  13. var (
  14. dyAccessToken string
  15. dyAccessTokenExpires int64
  16. DyAppId = "tt657f13c2fa40ef9802"
  17. DYBalanceUri = "/api/apps/game/wallet/get_balance"
  18. DYpayUri = "/api/apps/game/wallet/game_pay"
  19. DyPaySecret = "8a25288267fa81f75581b5018378cb0e"
  20. )
  21. // 从中台获取抖音支付TOKEN
  22. // 抖音查询余额签名函数
  23. func DyMakeQueryBalanceSig(md map[string]interface{}, uri string) string {
  24. var str string
  25. var ms []string
  26. for k, v := range md {
  27. switch v := v.(type) {
  28. case string:
  29. str = k + "=" + v
  30. ms = append(ms, str)
  31. case int:
  32. str = k + "=" + strconv.FormatInt(int64(v), 10)
  33. ms = append(ms, str)
  34. case int64:
  35. str = k + "=" + strconv.FormatInt(v, 10)
  36. ms = append(ms, str)
  37. }
  38. }
  39. sort.Strings(ms)
  40. str = "org_loc=" + uri
  41. ms = append(ms, str)
  42. str = "method=POST"
  43. ms = append(ms, str)
  44. var nstr string = strings.Join(ms, "&")
  45. r := hmacSha256(nstr, DyPaySecret)
  46. return r
  47. }
  48. // 查询余额接口
  49. func DyQueryBalance(openid string) (*ResponseGetBalance, error) {
  50. req := NewHttpRequest()
  51. requestData := make(map[string]interface{})
  52. requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
  53. requestData["appid"] = DyAppId //"wx831355257c862ac2"
  54. // requestData["offer_id"] = offerId //"1450030892"
  55. requestData["ts"] = time.Now().Unix()
  56. requestData["zone_id"] = "1"
  57. requestData["pf"] = "android"
  58. requestData["access_token"] = dyAccessToken //dyAccessToken
  59. requestData["mp_sig"] = DyMakeQueryBalanceSig(requestData, DYBalanceUri) //(requestData, getBalanceUri)
  60. // https://developer.toutiao.com/api/apps/game/wallet/get_balance
  61. url := "https://developer.toutiao.com" + DYBalanceUri
  62. resp, err := req.JSON(requestData).Post(url)
  63. if err != nil {
  64. //log.Warnln(err)
  65. return nil, err
  66. }
  67. defer func() {
  68. if resp.GetBody() != nil {
  69. resp.GetBody().Close()
  70. }
  71. }()
  72. if resp.GetStatusCode() != http.StatusOK {
  73. return nil, errors.New(fmt.Sprintf("请求余额失败:%v", resp.GetStatusCode()))
  74. }
  75. res := new(ResponseGetBalance)
  76. err = resp.UnmarshalBody(res)
  77. if err != nil {
  78. return nil, err
  79. }
  80. if res.ErrCode != 0 {
  81. return nil, errors.New(res.ErrMsg)
  82. }
  83. return res, nil
  84. }
  85. func DyQueryBalanceAndCheck(openid string) (*ResponseGetBalance, error) {
  86. // token不存在或过期则去请求
  87. if len(dyAccessToken) == 0 || time.Now().Unix() > dyAccessTokenExpires-60 {
  88. token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires)
  89. if err == nil {
  90. dyAccessToken = token
  91. dyAccessTokenExpires = expired
  92. }
  93. }
  94. rgb, err := DyQueryBalance(openid)
  95. if err != nil {
  96. return rgb, err
  97. }
  98. // 繁忙再请求
  99. if rgb.ErrCode == -1 {
  100. rgb, err = DyQueryBalance(openid)
  101. }
  102. // token失效再请求
  103. if rgb.ErrCode == 90017 || rgb.ErrCode == 90018 { // rgb.ErrCode == 40001 || rgb.ErrCode == 41001 ||
  104. token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires)
  105. if err == nil {
  106. dyAccessToken = token
  107. dyAccessTokenExpires = expired
  108. return DyQueryBalance(openid)
  109. }
  110. }
  111. return rgb, err
  112. }
  113. // 扣除余额接口
  114. func DyPay(openid string, billNo string, amt int) (*ResponsePay, error) {
  115. req := NewHttpRequest()
  116. requestData := make(map[string]interface{})
  117. requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U"
  118. requestData["appid"] = DyAppId //"wx831355257c862ac2"
  119. // requestData["offer_id"] = offerId //"1450030892"
  120. requestData["ts"] = time.Now().Unix()
  121. requestData["zone_id"] = "1"
  122. requestData["pf"] = "android"
  123. requestData["amt"] = amt
  124. requestData["bill_no"] = billNo
  125. //requestData["pay_item"] = "钻石"
  126. requestData["access_token"] = dyAccessToken
  127. requestData["mp_sig"] = DyMakeQueryBalanceSig(requestData, DYpayUri)
  128. // https://developer.toutiao.com/api/apps/game/wallet/game_pay
  129. url := "https://developer.toutiao.com" + DYpayUri
  130. logrus.Infof("DyPay params: %+v", requestData)
  131. resp, err := req.JSON(requestData).Post(url)
  132. if err != nil {
  133. //log.Warnln(err)
  134. return nil, err
  135. }
  136. defer func() {
  137. if resp.GetBody() != nil {
  138. resp.GetBody().Close()
  139. }
  140. }()
  141. if resp.GetStatusCode() == 200 {
  142. res := new(ResponsePay)
  143. resp.UnmarshalBody(res)
  144. //log.Warnf("%#v", res)
  145. return res, nil
  146. }
  147. return nil, nil
  148. }
  149. func DyPayAndCheck(openid string, billNo string, amt int) (*ResponsePay, error) {
  150. var rp *ResponsePay
  151. var err error
  152. for i := 0; i < 3; i++ {
  153. rp, err = DyPay(openid, billNo, amt)
  154. if err != nil {
  155. log.Warnf("DyPayAndCheck error: %v", err)
  156. time.Sleep(time.Millisecond * 10)
  157. continue
  158. }
  159. if rp.ErrCode == 0 {
  160. return rp, err
  161. }
  162. if rp.ErrCode == -1 {
  163. continue
  164. }
  165. if rp.ErrCode == 90017 || rp.ErrCode == 90018 {
  166. token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires)
  167. if err != nil {
  168. return rp, err
  169. }
  170. dyAccessToken = token
  171. dyAccessTokenExpires = expired
  172. continue
  173. }
  174. if rp.ErrCode < 0 {
  175. time.Sleep(time.Millisecond * 10)
  176. continue
  177. }
  178. return rp, err
  179. }
  180. return rp, err
  181. }
  182. // // 有效期2小时,定时刷新,提前刷新,会导致前一个token有效期变为5分钟;
  183. // func QueryDouYinAccessToken() error {
  184. // req := NewHttpRequest()
  185. // requestData := make(map[string]string)
  186. // requestData["grant_type"] = "client_credential"
  187. // requestData["appid"] = service.appId
  188. // requestData["secret"] = service.appSecret
  189. // resp, err := req.Query(requestData).Get(config.AppConfig.WxRefreshTokenUrl)
  190. // logrus.Info("query params:", requestData)
  191. // if err != nil {
  192. // //log.Warnln(err)
  193. // return err
  194. // }
  195. // defer func() {
  196. // if resp.GetBody() != nil {
  197. // resp.GetBody().Close()
  198. // }
  199. // }()
  200. // if resp.GetStatusCode() == 200 {
  201. // rt := new(ResponseAccessToken)
  202. // err := resp.UnmarshalBody(rt)
  203. // if err != nil {
  204. // logrus.Warnln("parse AccessToken err:", err.Error())
  205. // return err
  206. // }
  207. // if rt.ErrCode == 0 {
  208. // AccessToken := rt.AccessToken
  209. // //失效时间缩短一分钟
  210. // AccessTokenExpiredAt := time.Now().Add(time.Second * time.Duration(rt.ExpiresIn-60)).Unix()
  211. // service.UpdateAccessToken(AccessToken, AccessTokenExpiredAt)
  212. // atomic.StoreInt32(&service.ExpiredReportCount, 0)
  213. // }
  214. // logrus.Info("query resp:", rt)
  215. // } else {
  216. // logrus.Info("query resp code:", resp.GetStatusCode())
  217. // body, err := resp.GetBodyAsString()
  218. // logrus.Info("query resp body:", body)
  219. // logrus.Info("query resp err:", err.Error())
  220. // }
  221. // return nil, nil
  222. // }