package platformPay import ( "errors" "fmt" "github.com/sirupsen/logrus" "leafstalk/log" "net/http" "sort" "strconv" "strings" "time" ) var ( dyAccessToken string dyAccessTokenExpires int64 DyAppId = "tt657f13c2fa40ef9802" DYBalanceUri = "/api/apps/game/wallet/get_balance" DYpayUri = "/api/apps/game/wallet/game_pay" DyPaySecret = "8a25288267fa81f75581b5018378cb0e" ) // 从中台获取抖音支付TOKEN // 抖音查询余额签名函数 func DyMakeQueryBalanceSig(md map[string]interface{}, uri string) string { var str string var ms []string for k, v := range md { switch v := v.(type) { case string: str = k + "=" + v ms = append(ms, str) case int: str = k + "=" + strconv.FormatInt(int64(v), 10) ms = append(ms, str) case int64: str = k + "=" + strconv.FormatInt(v, 10) ms = append(ms, str) } } sort.Strings(ms) str = "org_loc=" + uri ms = append(ms, str) str = "method=POST" ms = append(ms, str) var nstr string = strings.Join(ms, "&") r := hmacSha256(nstr, DyPaySecret) return r } // 查询余额接口 func DyQueryBalance(openid string) (*ResponseGetBalance, error) { req := NewHttpRequest() requestData := make(map[string]interface{}) requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U" requestData["appid"] = DyAppId //"wx831355257c862ac2" // requestData["offer_id"] = offerId //"1450030892" requestData["ts"] = time.Now().Unix() requestData["zone_id"] = "1" requestData["pf"] = "android" requestData["access_token"] = dyAccessToken //dyAccessToken requestData["mp_sig"] = DyMakeQueryBalanceSig(requestData, DYBalanceUri) //(requestData, getBalanceUri) // https://developer.toutiao.com/api/apps/game/wallet/get_balance url := "https://developer.toutiao.com" + DYBalanceUri resp, err := req.JSON(requestData).Post(url) if err != nil { //log.Warnln(err) return nil, err } defer func() { if resp.GetBody() != nil { resp.GetBody().Close() } }() if resp.GetStatusCode() != http.StatusOK { return nil, errors.New(fmt.Sprintf("请求余额失败:%v", resp.GetStatusCode())) } res := new(ResponseGetBalance) err = resp.UnmarshalBody(res) if err != nil { return nil, err } if res.ErrCode != 0 { return nil, errors.New(res.ErrMsg) } return res, nil } func DyQueryBalanceAndCheck(openid string) (*ResponseGetBalance, error) { // token不存在或过期则去请求 if len(dyAccessToken) == 0 || time.Now().Unix() > dyAccessTokenExpires-60 { token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires) if err == nil { dyAccessToken = token dyAccessTokenExpires = expired } } rgb, err := DyQueryBalance(openid) if err != nil { return rgb, err } // 繁忙再请求 if rgb.ErrCode == -1 { rgb, err = DyQueryBalance(openid) } // token失效再请求 if rgb.ErrCode == 90017 || rgb.ErrCode == 90018 { // rgb.ErrCode == 40001 || rgb.ErrCode == 41001 || token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires) if err == nil { dyAccessToken = token dyAccessTokenExpires = expired return DyQueryBalance(openid) } } return rgb, err } // 扣除余额接口 func DyPay(openid string, billNo string, amt int) (*ResponsePay, error) { req := NewHttpRequest() requestData := make(map[string]interface{}) requestData["openid"] = openid //"oNEBv5CU3aOz7FcWp5ZDlhCNc3-U" requestData["appid"] = DyAppId //"wx831355257c862ac2" // requestData["offer_id"] = offerId //"1450030892" requestData["ts"] = time.Now().Unix() requestData["zone_id"] = "1" requestData["pf"] = "android" requestData["amt"] = amt requestData["bill_no"] = billNo //requestData["pay_item"] = "钻石" requestData["access_token"] = dyAccessToken requestData["mp_sig"] = DyMakeQueryBalanceSig(requestData, DYpayUri) // https://developer.toutiao.com/api/apps/game/wallet/game_pay url := "https://developer.toutiao.com" + DYpayUri logrus.Infof("DyPay params: %+v", requestData) resp, err := req.JSON(requestData).Post(url) if err != nil { //log.Warnln(err) return nil, err } defer func() { if resp.GetBody() != nil { resp.GetBody().Close() } }() if resp.GetStatusCode() == 200 { res := new(ResponsePay) resp.UnmarshalBody(res) //log.Warnf("%#v", res) return res, nil } return nil, nil } func DyPayAndCheck(openid string, billNo string, amt int) (*ResponsePay, error) { var rp *ResponsePay var err error for i := 0; i < 3; i++ { rp, err = DyPay(openid, billNo, amt) if err != nil { log.Warnf("DyPayAndCheck error: %v", err) time.Sleep(time.Millisecond * 10) continue } if rp.ErrCode == 0 { return rp, err } if rp.ErrCode == -1 { continue } if rp.ErrCode == 90017 || rp.ErrCode == 90018 { token, expired, err := QueryAccessToken(int(DyPlat), dyAccessTokenExpires) if err != nil { return rp, err } dyAccessToken = token dyAccessTokenExpires = expired continue } if rp.ErrCode < 0 { time.Sleep(time.Millisecond * 10) continue } return rp, err } return rp, err } // // 有效期2小时,定时刷新,提前刷新,会导致前一个token有效期变为5分钟; // func QueryDouYinAccessToken() error { // req := NewHttpRequest() // requestData := make(map[string]string) // requestData["grant_type"] = "client_credential" // requestData["appid"] = service.appId // requestData["secret"] = service.appSecret // resp, err := req.Query(requestData).Get(config.AppConfig.WxRefreshTokenUrl) // logrus.Info("query params:", requestData) // if err != nil { // //log.Warnln(err) // return err // } // defer func() { // if resp.GetBody() != nil { // resp.GetBody().Close() // } // }() // if resp.GetStatusCode() == 200 { // rt := new(ResponseAccessToken) // err := resp.UnmarshalBody(rt) // if err != nil { // logrus.Warnln("parse AccessToken err:", err.Error()) // return err // } // if rt.ErrCode == 0 { // AccessToken := rt.AccessToken // //失效时间缩短一分钟 // AccessTokenExpiredAt := time.Now().Add(time.Second * time.Duration(rt.ExpiresIn-60)).Unix() // service.UpdateAccessToken(AccessToken, AccessTokenExpiredAt) // atomic.StoreInt32(&service.ExpiredReportCount, 0) // } // logrus.Info("query resp:", rt) // } else { // logrus.Info("query resp code:", resp.GetStatusCode()) // body, err := resp.GetBodyAsString() // logrus.Info("query resp body:", body) // logrus.Info("query resp err:", err.Error()) // } // return nil, nil // }