373 lines
8.6 KiB
Go
373 lines
8.6 KiB
Go
package service
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"f5"
|
|
"main/constant"
|
|
"main/mt"
|
|
"q5"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type tokenItem struct {
|
|
token string
|
|
expire int64
|
|
}
|
|
|
|
type expireSession struct {
|
|
SessionTime int64
|
|
Time int64
|
|
}
|
|
type wxpay struct {
|
|
gamesGoods q5.ConcurrentMap[int64, map[int64]int64] //[gameid, [goodsid]count]
|
|
accessTokens q5.ConcurrentMap[int64, tokenItem] //[gameid, tokenitem]
|
|
|
|
expireInfo q5.ConcurrentMap[string, *expireSession] //[accountid, expireSession]
|
|
}
|
|
|
|
type WxQuery struct {
|
|
AccessToken string `json:"access_token"`
|
|
Signature string `json:"signature"`
|
|
SigMethod string `json:"sig_method"`
|
|
PaySig string `json:"pay_sig"`
|
|
}
|
|
|
|
type WxBalanceRsp struct {
|
|
ErrCode int32 `json:"errcode"`
|
|
ErrMsg string `json:"errmsg"`
|
|
Balance int64 `json:"balance"`
|
|
GiftBalance int64 `json:"present_balance"`
|
|
SumSave int64 `json:"sum_save"`
|
|
SumGift int64 `json:"sum_present"`
|
|
SumBalance int64 `json:"sum_balance"`
|
|
SumCost int64 `json:"sum_cost"`
|
|
FirstSave bool `json:"first_save"`
|
|
}
|
|
|
|
type WxPayRsp struct {
|
|
ErrCode int32 `json:"errcode"`
|
|
ErrMsg string `json:"errmsg"`
|
|
BillNo string `json:"bill_no"`
|
|
Balance int64 `json:"balance"`
|
|
UsedGift int64 `json:"used_present_amount"`
|
|
}
|
|
|
|
func (wp *wxpay) init() {
|
|
wp.gamesGoods = q5.ConcurrentMap[int64, map[int64]int64]{}
|
|
wp.accessTokens = q5.ConcurrentMap[int64, tokenItem]{}
|
|
wp.expireInfo = q5.ConcurrentMap[string, *expireSession]{}
|
|
|
|
mt.Table.Wxconfig.Traverse(func(w *mt.Wxconfig) bool {
|
|
filename := "../res/gamegoods/" + q5.SafeToString(w.GetGameid()) + ".json"
|
|
str, err := f5.ReadJsonFile(filename)
|
|
if err != nil {
|
|
return true
|
|
}
|
|
data := []map[string]interface{}{}
|
|
if json.Unmarshal([]byte(str), &data) != nil {
|
|
f5.GetSysLog().Error("parse [%s] error.", filename)
|
|
} else {
|
|
gamegoods := map[int64]int64{}
|
|
for _, data := range data {
|
|
gamegoods[q5.SafeToInt64(data["id"])] = q5.SafeToInt64(data["count"])
|
|
}
|
|
wp.gamesGoods.Store(w.GetGameid(), gamegoods)
|
|
wp.accessTokens.Store(w.GetGameid(), tokenItem{})
|
|
}
|
|
return true
|
|
})
|
|
|
|
wp.gamesGoods.Range(func(gameid int64, value map[int64]int64) bool {
|
|
wp.freshAccessToken(gameid)
|
|
return true
|
|
})
|
|
|
|
go wp.checkExpireInfo()
|
|
}
|
|
|
|
func (wp *wxpay) unInit() {
|
|
}
|
|
|
|
func (wp *wxpay) freshAccessToken(gameid int64) (token string) {
|
|
cfg := mt.Table.Wxconfig.GetById(gameid)
|
|
params := map[string]string{
|
|
"grant_type": "client_credential",
|
|
"appid": cfg.GetAppid(),
|
|
"secret": cfg.GetAppsecret(),
|
|
}
|
|
urls := mt.Table.Config.GetWxUrl()
|
|
queryuri := "cgi-bin/token"
|
|
for _, wxhost := range urls {
|
|
url := "https://" + wxhost + queryuri
|
|
sendok := false
|
|
f5.GetHttpCliMgr().SendGoStyleRequest(
|
|
url,
|
|
params,
|
|
func(hcr f5.HttpCliResponse) {
|
|
if hcr.GetErr() != nil {
|
|
return
|
|
}
|
|
|
|
rspObj := struct {
|
|
Token string `json:"access_token"`
|
|
Expire int64 `json:"expire_in"`
|
|
ErrCode int64 `json:"errcode"`
|
|
ErrMsg string `json:"errmsg"`
|
|
}{}
|
|
|
|
sendok = true
|
|
f5.GetSysLog().Debug("wx get access token rsp:%s", hcr.GetRawData())
|
|
if json.Unmarshal([]byte(hcr.GetRawData()), &rspObj) != nil {
|
|
return
|
|
}
|
|
|
|
if rspObj.ErrCode == 0 {
|
|
tokenitem, _ := wp.accessTokens.Load(gameid)
|
|
tokenitem.token = rspObj.Token
|
|
tokenitem.expire = rspObj.Expire + f5.GetApp().GetRealSeconds()
|
|
}
|
|
|
|
})
|
|
|
|
if sendok {
|
|
break
|
|
}
|
|
}
|
|
|
|
return token
|
|
}
|
|
|
|
func (wp *wxpay) getAccessToken(gameid int64) (token string) {
|
|
cfg, exist := wp.accessTokens.Load(gameid)
|
|
nowTime := f5.GetApp().GetRealSeconds()
|
|
if exist {
|
|
if cfg.expire > nowTime+60 {
|
|
return cfg.token
|
|
}
|
|
|
|
return wp.freshAccessToken(gameid)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (wp *wxpay) GetGoodsCount(gameid int64, goodsid int64) (count int64, err error) {
|
|
goods, ok := wp.gamesGoods.Load(gameid)
|
|
if !ok {
|
|
return 0, errors.New("no game")
|
|
}
|
|
|
|
count, ok = (*goods)[goodsid]
|
|
if !ok {
|
|
return 0, errors.New("no goods")
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
func (wp *wxpay) QueryBalance(openid string, gameid int64, userip string, sessionkey string) (balance int64, wxerrcode int32, err error) {
|
|
cfg := mt.Table.Wxconfig.GetById(gameid)
|
|
postbody := struct {
|
|
OpenId string `json:"openid"`
|
|
OfferId string `json:"offer_id"`
|
|
Ts int64 `json:"ts"`
|
|
ZoneId string `json:"zone_id"`
|
|
Env int32 `json:"env"`
|
|
UserIp string `json:"user_ip"`
|
|
}{
|
|
OpenId: openid,
|
|
OfferId: cfg.GetOfferid(),
|
|
Ts: f5.GetApp().GetRealSeconds(),
|
|
ZoneId: cfg.GetZoneid(),
|
|
UserIp: userip,
|
|
}
|
|
|
|
if !f5.IsOnlineEnv() {
|
|
postbody.Env = 1
|
|
}
|
|
|
|
poststr := q5.EncodeJson(postbody)
|
|
|
|
queryuri := "/wxa/game/getbalance"
|
|
query := WxQuery{
|
|
AccessToken: wp.getAccessToken(gameid),
|
|
Signature: wp.genSHA256Signature(poststr, sessionkey),
|
|
SigMethod: "hmac_sha256",
|
|
PaySig: wp.genSHA256Signature(queryuri+"&"+poststr, cfg.GetAppkey()),
|
|
}
|
|
|
|
params := map[string]string{}
|
|
data, _ := json.Marshal(query)
|
|
json.Unmarshal(data, ¶ms)
|
|
|
|
sendRequest := false
|
|
urls := mt.Table.Config.GetWxUrl()
|
|
for _, wxhost := range urls {
|
|
url := "https://" + wxhost + queryuri
|
|
f5.GetHttpCliMgr().SendGoStylePost(
|
|
url,
|
|
params,
|
|
"Content-Type: application/json",
|
|
poststr,
|
|
func(rsp f5.HttpCliResponse) {
|
|
if rsp.GetErr() != nil {
|
|
return
|
|
}
|
|
|
|
sendRequest = true
|
|
rspJson := WxBalanceRsp{}
|
|
f5.GetSysLog().Debug("wx balance rsp:%s", rsp.GetRawData())
|
|
err = q5.DecodeJson(rsp.GetRawData(), &rspJson)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
wxerrcode = rspJson.ErrCode
|
|
switch rspJson.ErrCode {
|
|
case constant.WX_ERRCODE_OK:
|
|
balance = rspJson.Balance
|
|
case constant.WX_ERRCODE_BUSY:
|
|
sendRequest = false
|
|
default:
|
|
f5.GetSysLog().Info("err msg:%s", rspJson.ErrMsg)
|
|
}
|
|
|
|
})
|
|
if sendRequest {
|
|
break
|
|
}
|
|
}
|
|
|
|
return balance, wxerrcode, err
|
|
}
|
|
|
|
func (wp *wxpay) QueryPay(openid string, gameid int64, userip string, sessionkey string, amount int32, billno string) (wxerrcode int32) {
|
|
cfg := mt.Table.Wxconfig.GetById(gameid)
|
|
postbody := struct {
|
|
OpenId string `json:"openid"`
|
|
OfferId string `json:"offer_id"`
|
|
Ts int64 `json:"ts"`
|
|
ZoneId string `json:"zone_id"`
|
|
Env int32 `json:"env"`
|
|
UserIp string `json:"user_ip"`
|
|
Amount int32 `json:"amount"`
|
|
BillNo string `json:"bill_no"`
|
|
}{
|
|
OpenId: openid,
|
|
OfferId: cfg.GetOfferid(),
|
|
Ts: f5.GetApp().GetRealSeconds(),
|
|
ZoneId: cfg.GetZoneid(),
|
|
UserIp: userip,
|
|
Amount: amount,
|
|
BillNo: billno,
|
|
}
|
|
|
|
if !f5.IsOnlineEnv() {
|
|
postbody.Env = 1
|
|
}
|
|
|
|
poststr := q5.EncodeJson(postbody)
|
|
|
|
queryuri := "/wxa/game/pay"
|
|
query := WxQuery{
|
|
AccessToken: wp.getAccessToken(gameid),
|
|
Signature: wp.genSHA256Signature(poststr, sessionkey),
|
|
SigMethod: "hmac_sha256",
|
|
PaySig: wp.genSHA256Signature(queryuri+"&"+poststr, cfg.GetAppkey()),
|
|
}
|
|
|
|
params := map[string]string{}
|
|
data, _ := json.Marshal(query)
|
|
json.Unmarshal(data, ¶ms)
|
|
|
|
sendRequest := false
|
|
urls := mt.Table.Config.GetWxUrl()
|
|
for _, wxhost := range urls {
|
|
url := "https://" + wxhost + queryuri
|
|
f5.GetHttpCliMgr().SendGoStylePost(
|
|
url,
|
|
params,
|
|
"Content-Type: application/json",
|
|
poststr,
|
|
func(rsp f5.HttpCliResponse) {
|
|
if rsp.GetErr() != nil {
|
|
return
|
|
}
|
|
|
|
sendRequest = true
|
|
rspJson := WxPayRsp{}
|
|
f5.GetSysLog().Debug("wx pay rsp:%s", rsp.GetRawData())
|
|
err := q5.DecodeJson(rsp.GetRawData(), &rspJson)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
wxerrcode = rspJson.ErrCode
|
|
switch rspJson.ErrCode {
|
|
case constant.WX_ERRCODE_OK:
|
|
case constant.WX_ERRCODE_BUSY:
|
|
sendRequest = false
|
|
default:
|
|
f5.GetSysLog().Info("err msg:%s", rspJson.ErrMsg)
|
|
}
|
|
|
|
})
|
|
if sendRequest {
|
|
break
|
|
}
|
|
}
|
|
|
|
return wxerrcode
|
|
}
|
|
|
|
func (wp *wxpay) AddExpireInfo(accountid string, sessiontime int64) {
|
|
info := expireSession{
|
|
SessionTime: sessiontime,
|
|
Time: f5.GetApp().GetRealSeconds(),
|
|
}
|
|
|
|
wp.expireInfo.Store(accountid, &info)
|
|
}
|
|
|
|
func (wp *wxpay) CheckExpireCache(accountid string, expire int64) bool {
|
|
info, exist := wp.expireInfo.Load(accountid)
|
|
if !exist {
|
|
return false
|
|
}
|
|
|
|
if (*info).SessionTime < expire {
|
|
wp.expireInfo.Delete(accountid)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (wp *wxpay) genSHA256Signature(str string, key string) string {
|
|
mac := hmac.New(sha256.New, []byte(key))
|
|
_, _ = mac.Write([]byte(str))
|
|
return strings.ToLower(hex.EncodeToString(mac.Sum(nil)))
|
|
}
|
|
|
|
func (wp *wxpay) checkExpireInfo() {
|
|
for {
|
|
time.Sleep(time.Minute * 30)
|
|
nowTime := f5.GetApp().GetRealSeconds()
|
|
deletelist := map[string]int64{}
|
|
wp.expireInfo.Range(func(accountid string, value *expireSession) bool {
|
|
if value.Time+3600 < nowTime {
|
|
deletelist[accountid] = value.Time
|
|
}
|
|
return true
|
|
})
|
|
|
|
for accountid := range deletelist {
|
|
wp.expireInfo.Delete(accountid)
|
|
}
|
|
}
|
|
}
|