You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
534 lines
12 KiB
534 lines
12 KiB
package values |
|
|
|
import ( |
|
"encoding/json" |
|
"fmt" |
|
"io/ioutil" |
|
"math/rand" |
|
"net/http" |
|
"server/call" |
|
"server/common" |
|
"server/config" |
|
"server/db" |
|
"server/util" |
|
"sort" |
|
"strings" |
|
"sync" |
|
|
|
"github.com/gin-gonic/gin" |
|
"github.com/liangdas/mqant/log" |
|
"gorm.io/gorm" |
|
) |
|
|
|
// 支付方式 |
|
type PayWay int |
|
|
|
const ( |
|
FunzonePay PayWay = iota |
|
WellPay |
|
OctroPay |
|
IGeekPay |
|
CloudPay |
|
VSPay |
|
JoyPay |
|
FFPay |
|
BestPay |
|
HXPay |
|
MGPay |
|
OOPay |
|
ZWPay |
|
FastPay |
|
HaoPay |
|
QPPay |
|
OwlPay |
|
SkyPay |
|
GrePay |
|
MoonPay |
|
AcePay |
|
MccPay |
|
YoduPay |
|
WordPay |
|
HWPay |
|
JJPay |
|
AntPay |
|
MLPay |
|
RojPay |
|
QuantaPay |
|
InnoPay |
|
PePay |
|
FF8Pay |
|
FlaPay |
|
DidaPay |
|
CYGGPay |
|
ZPay |
|
HappyPay |
|
FastPlusPay |
|
GoPay |
|
LemonPay |
|
CamelPay |
|
MoonPay2 |
|
PayPlus |
|
LuckyinPay |
|
PayAll |
|
) |
|
|
|
// 错误码 |
|
const ( |
|
CodeOk = iota |
|
) |
|
|
|
var ( |
|
PayWeightLock = new(sync.RWMutex) |
|
WithdrawWeightLock = new(sync.RWMutex) |
|
) |
|
|
|
// SelectPayWay 特定条件为玩家优先选择渠道 |
|
// func SelectPayWay(uid int, amount int64) PayWay { |
|
// if !config.GetConfig().Pay.SelectPayWay { |
|
// return -1 |
|
// } |
|
// banList := []int{} |
|
// zlist := db.Redis().ZRange(common.GetRedisKeyPlayerPay(uid)) |
|
// for _, v := range zlist { |
|
// banList = append(banList, util.GetInt(v.Member)) |
|
// } |
|
// lastSuccess := &common.RechargeOrder{UID: uid, Event: int(common.CurrencyEventReCharge), Status: common.StatusROrderPay} |
|
// err := db.Mysql().GetLast(lastSuccess) |
|
// if err == nil { // 直接按上次成功的渠道作为首选推荐渠道 |
|
// if !util.SliceContain(banList, lastSuccess.PayChannel) && IsTopChannel(lastSuccess.PayChannel, 3, amount) { |
|
// return PayWay(lastSuccess.PayChannel) |
|
// } |
|
// } |
|
// banAll := GetValidPayChannelsWithBanList(amount, banList) |
|
// if PayStatus == PayStatusChannel { |
|
// for _, v := range banAll { |
|
// return PayWay(v.ChannelID) |
|
// } |
|
// } |
|
// // 尝试当前权重最高的 |
|
// all := GetValidPayChannels(amount) |
|
// if len(all) > 0 { |
|
// if !util.SliceContain(banList, all[0].ChannelID) { |
|
// return PayWay(all[0].ChannelID) |
|
// } |
|
// } |
|
// return GetPayWayWeight(banAll) |
|
// } |
|
|
|
// 手动选择模式获取支付渠道 |
|
func GetPayWayChannel(index int, all []*common.ConfigPayChannels) (w PayWay) { |
|
if len(all) == 0 { |
|
w = -1 |
|
return |
|
} |
|
if index > len(all)-1 || index < 0 { |
|
index = 0 |
|
} |
|
w = PayWay(all[index].ChannelID) |
|
return |
|
} |
|
|
|
// 权重模式获取支付渠道 |
|
func GetPayWayWeight(all []*common.ConfigPayChannels) PayWay { |
|
total := 0 |
|
for _, v := range all { |
|
total += v.PayPer |
|
} |
|
if total > 0 { |
|
ran := rand.Intn(total) |
|
rans := 0 |
|
for i := 0; i < len(all); i++ { |
|
rans += all[i].PayPer |
|
if ran < rans { |
|
return PayWay(all[i].ChannelID) |
|
} |
|
} |
|
} |
|
return -1 |
|
} |
|
|
|
// ChoosePayWay 选择充值渠道 |
|
// func ChoosePayWay(uid, index int, amount int64) PayWay { |
|
// pw := SelectPayWay(uid, amount) |
|
// if pw >= 0 { |
|
// return pw |
|
// } |
|
// if PayStatus == PayStatusChannel { |
|
// return GetPayWayChannel(index, GetValidPayChannels(amount)) |
|
// } |
|
// return GetPayWayWeight(GetValidPayChannels(amount)) |
|
// } |
|
|
|
func WithdrawFail(w PayWay) { |
|
failWeight := config.GetConfig().Pay.PayFailWeight |
|
if failWeight <= 0 { |
|
return |
|
} |
|
PayWeightLock.Lock() |
|
for _, v := range call.ConfigPayChannels { |
|
if v.ChannelID == int(w) { |
|
v.PayPer -= failWeight |
|
break |
|
} |
|
} |
|
sort.Slice(call.ConfigPayChannels, func(i, j int) bool { |
|
return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer |
|
}) |
|
PayWeightLock.Unlock() |
|
AddWithdrawChannel(int(w), -failWeight) |
|
} |
|
|
|
func WithdrawSuccess(w PayWay) { |
|
successWeight := config.GetConfig().Pay.PaySuccessWeight |
|
if successWeight <= 0 { |
|
return |
|
} |
|
PayWeightLock.Lock() |
|
for _, v := range call.ConfigPayChannels { |
|
if v.ChannelID == int(w) { |
|
v.PayPer += successWeight |
|
break |
|
} |
|
} |
|
sort.Slice(call.ConfigPayChannels, func(i, j int) bool { |
|
return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer |
|
}) |
|
PayWeightLock.Unlock() |
|
AddWithdrawChannel(int(w), successWeight) |
|
} |
|
|
|
func PayFail(w PayWay) { |
|
failWeight := config.GetConfig().Pay.PayFailWeight |
|
if failWeight <= 0 { |
|
return |
|
} |
|
PayWeightLock.Lock() |
|
for _, v := range call.ConfigPayChannels { |
|
if v.ChannelID == int(w) { |
|
v.PayPer -= failWeight |
|
break |
|
} |
|
} |
|
sort.Slice(call.ConfigPayChannels, func(i, j int) bool { |
|
return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer |
|
}) |
|
PayWeightLock.Unlock() |
|
AddPayChannel(int(w), -failWeight) |
|
} |
|
|
|
func PayCallback(w PayWay) { |
|
successWeight := config.GetConfig().Pay.PaySuccessWeight |
|
if successWeight <= 0 { |
|
return |
|
} |
|
PayWeightLock.Lock() |
|
for _, v := range call.ConfigPayChannels { |
|
if v.ChannelID == int(w) { |
|
v.PayPer += successWeight |
|
break |
|
} |
|
} |
|
sort.Slice(call.ConfigPayChannels, func(i, j int) bool { |
|
return call.ConfigPayChannels[i].PayPer > call.ConfigPayChannels[j].PayPer |
|
}) |
|
PayWeightLock.Unlock() |
|
AddPayChannel(int(w), successWeight) |
|
} |
|
|
|
// 获取支付回调路径 |
|
func GetPayCallback(way PayWay) string { |
|
return config.GetConfig().Pay.CallbackURL + config.GetConfig().Pay.Addr + "/callback/pay/" + fmt.Sprintf("%d", way) |
|
} |
|
|
|
// 获取退出回调路径 |
|
func GetWithdrawCallback(way PayWay) string { |
|
return config.GetConfig().Pay.CallbackURL + config.GetConfig().Pay.Addr + "/callback/withdraw/" + fmt.Sprintf("%d", way) |
|
} |
|
|
|
func GetFrontCallback() string { |
|
return config.GetConfig().Pay.CallbackURL + config.GetConfig().Pay.Addr + "/common/front/payCallback" |
|
} |
|
|
|
func GetFrontCallbackFail() string { |
|
return config.GetConfig().Pay.CallbackURL + config.GetConfig().Pay.Addr + "/common/front/payCallback/fail" |
|
} |
|
|
|
// 根据body里的字段直接拼接出签名字符串 |
|
func GetSignStr(str string, pass ...string) string { |
|
m := map[string]json.RawMessage{} |
|
sortStrs := []string{} |
|
json.Unmarshal([]byte(str), &m) |
|
for i := range m { |
|
sortStrs = append(sortStrs, i) |
|
} |
|
signStr := "" |
|
sort.Strings(sortStrs) |
|
for _, v := range sortStrs { |
|
shouldPass := false |
|
for _, s := range pass { |
|
if v == s { |
|
shouldPass = true |
|
break |
|
} |
|
} |
|
if shouldPass { |
|
continue |
|
} |
|
if len(m[v]) > 1 && m[v][0] == 34 { |
|
m[v] = m[v][1 : len(m[v])-1] |
|
} |
|
if len(m[v]) == 0 { |
|
continue |
|
} |
|
signStr += fmt.Sprintf("%v=%v", v, string(m[v])) |
|
signStr += "&" |
|
} |
|
signStr = signStr[:len(signStr)-1] |
|
log.Debug("signStr:%v", signStr) |
|
return signStr |
|
} |
|
|
|
// 根据body里的字段直接拼接出签名字符串(去除null) |
|
func GetSignStrNull(str string, pass ...string) string { |
|
m := map[string]json.RawMessage{} |
|
sortStrs := []string{} |
|
json.Unmarshal([]byte(str), &m) |
|
for i := range m { |
|
sortStrs = append(sortStrs, i) |
|
} |
|
signStr := "" |
|
sort.Strings(sortStrs) |
|
for _, v := range sortStrs { |
|
shouldPass := false |
|
for _, s := range pass { |
|
if v == s { |
|
shouldPass = true |
|
break |
|
} |
|
} |
|
if shouldPass { |
|
continue |
|
} |
|
if len(m[v]) > 1 && m[v][0] == 34 { |
|
m[v] = m[v][1 : len(m[v])-1] |
|
} |
|
if len(m[v]) == 0 || string(m[v]) == "null" { |
|
continue |
|
} |
|
signStr += fmt.Sprintf("%v=%v", v, string(m[v])) |
|
signStr += "&" |
|
} |
|
signStr = signStr[:len(signStr)-1] |
|
log.Debug("signStr:%v", signStr) |
|
return signStr |
|
} |
|
|
|
// 根据body里的字段直接拼接出签名字符串(包括空字符串) |
|
func GetSignStrAll(str string, pass ...string) string { |
|
m := map[string]json.RawMessage{} |
|
sortStrs := []string{} |
|
json.Unmarshal([]byte(str), &m) |
|
for i := range m { |
|
sortStrs = append(sortStrs, i) |
|
} |
|
signStr := "" |
|
sort.Strings(sortStrs) |
|
for _, v := range sortStrs { |
|
shouldPass := false |
|
for _, s := range pass { |
|
if v == s { |
|
shouldPass = true |
|
break |
|
} |
|
} |
|
if shouldPass { |
|
continue |
|
} |
|
if len(m[v]) > 1 && m[v][0] == 34 { |
|
m[v] = m[v][1 : len(m[v])-1] |
|
} |
|
signStr += fmt.Sprintf("%v=%v", v, string(m[v])) |
|
signStr += "&" |
|
} |
|
signStr = signStr[:len(signStr)-1] |
|
log.Debug("signStr:%v", signStr) |
|
return signStr |
|
} |
|
|
|
// 根据body里的字段直接拼接出签名字符串(包括空字符串,unicode转码) |
|
func GetSignStrAllUnicode(str string, pass ...string) string { |
|
m := map[string]json.RawMessage{} |
|
sortStrs := []string{} |
|
json.Unmarshal([]byte(str), &m) |
|
for i := range m { |
|
sortStrs = append(sortStrs, i) |
|
} |
|
signStr := "" |
|
sort.Strings(sortStrs) |
|
for _, v := range sortStrs { |
|
shouldPass := false |
|
for _, s := range pass { |
|
if v == s { |
|
shouldPass = true |
|
break |
|
} |
|
} |
|
if shouldPass { |
|
continue |
|
} |
|
str := string(m[v]) |
|
if len(str) > 1 && str[0] == 34 { |
|
str = str[1 : len(str)-1] |
|
} |
|
tmp, err := util.ZhToUnicode(str) |
|
if err == nil { |
|
str = tmp |
|
} |
|
str = strings.ReplaceAll(str, `\`, "") |
|
signStr += fmt.Sprintf("%v=%v", v, str) |
|
signStr += "&" |
|
} |
|
signStr = signStr[:len(signStr)-1] |
|
log.Debug("signStr:%v", signStr) |
|
return signStr |
|
} |
|
|
|
func GetSignStrForm(c *gin.Context, pass ...string) string { |
|
sortStrs := []string{} |
|
for k := range c.Request.PostForm { |
|
sortStrs = append(sortStrs, k) |
|
} |
|
signStr := "" |
|
sort.Strings(sortStrs) |
|
for _, v := range sortStrs { |
|
shouldPass := false |
|
for _, s := range pass { |
|
if v == s { |
|
shouldPass = true |
|
break |
|
} |
|
} |
|
if shouldPass { |
|
continue |
|
} |
|
if len(c.PostForm(v)) == 0 { |
|
continue |
|
} |
|
signStr += fmt.Sprintf("%v=%v", v, c.PostForm(v)) |
|
signStr += "&" |
|
} |
|
signStr = signStr[:len(signStr)-1] |
|
log.Debug("signStr:%v", signStr) |
|
return signStr |
|
} |
|
|
|
// status=1时,属于不知道第三方是什么情况的报错,不能当成业务中断 |
|
// status=0时,可以根据返回判断是否是业务错误 |
|
func Post(req *http.Request, ret interface{}) int { |
|
client := &http.Client{} |
|
log.Debug("req:%+v", req) |
|
resp, err := client.Do(req) |
|
if err != nil { |
|
log.Error("http post call err:%v", err) |
|
return 1 |
|
} |
|
defer resp.Body.Close() |
|
body, _ := ioutil.ReadAll(resp.Body) |
|
log.Debug("response Body%v:", string(body)) |
|
if err := json.Unmarshal(body, ret); err != nil { |
|
log.Error("unmarshal fail err:%v", err) |
|
return 1 |
|
} |
|
return 0 |
|
} |
|
|
|
func AddWithdrawChannel(p int, amount int) { |
|
if err := db.Mysql().C().Model(&common.ConfigWithdrawChannels{}).Where("channel_id = ?", p).Updates(map[string]interface{}{"withdraw_per": gorm.Expr("withdraw_per + ?", amount)}).Error; err != nil { |
|
log.Error("err:%v", err) |
|
} |
|
} |
|
|
|
func AddPayChannel(p int, amount int) { |
|
if err := db.Mysql().C().Model(&common.ConfigPayChannels{}).Where("channel_id = ?", p).Updates(map[string]interface{}{"pay_per": gorm.Expr("pay_per + ?", amount)}).Error; err != nil { |
|
log.Error("err:%v", err) |
|
} |
|
} |
|
|
|
func SetPayChannel(p int, amount int) { |
|
if err := db.Mysql().C().Model(&common.ConfigPayChannels{}).Where("channel_id = ?", p).Updates(map[string]interface{}{"pay_per": amount}).Error; err != nil { |
|
log.Error("err:%v", err) |
|
} |
|
} |
|
|
|
func GetValidPayChannels(amount int64) []*common.ConfigPayChannels { |
|
PayWeightLock.RLock() |
|
defer PayWeightLock.RUnlock() |
|
all := []*common.ConfigPayChannels{} |
|
for _, v := range call.ConfigPayChannels { |
|
if v.PayPer > 0 && amount >= v.PayDown && (amount <= v.PayUp || v.PayUp <= 0) { |
|
all = append(all, v) |
|
} |
|
} |
|
return all |
|
} |
|
|
|
func GetValidPayChannelsWithBanList(amount int64, banList []int) []*common.ConfigPayChannels { |
|
all := []*common.ConfigPayChannels{} |
|
PayWeightLock.RLock() |
|
defer PayWeightLock.RUnlock() |
|
for _, v := range call.ConfigPayChannels { |
|
if v.PayPer > 0 && amount >= v.PayDown && (amount <= v.PayUp || v.PayUp <= 0) { |
|
if !util.SliceContain(banList, v.ChannelID) { |
|
all = append(all, v) |
|
} |
|
} |
|
} |
|
return all |
|
} |
|
|
|
func IsPayChannelValid(cid int, amount int64) bool { |
|
PayWeightLock.RLock() |
|
defer PayWeightLock.RUnlock() |
|
for _, v := range call.ConfigPayChannels { |
|
if cid == v.ChannelID { |
|
if v.PayPer > 0 && amount >= v.PayDown && (amount <= v.PayUp || v.PayUp <= 0) { |
|
return true |
|
} |
|
break |
|
} |
|
} |
|
return false |
|
} |
|
|
|
// IsTopChannel 判断渠道是否是排名前几的可用渠道 |
|
func IsTopChannel(cid, top int, amount int64) bool { |
|
PayWeightLock.RLock() |
|
defer PayWeightLock.RUnlock() |
|
for i := 0; i < top; i++ { |
|
v := call.ConfigPayChannels[i] |
|
if cid == v.ChannelID { |
|
if v.PayPer > 0 && amount >= v.PayDown && (amount <= v.PayUp || v.PayUp <= 0) { |
|
return true |
|
} |
|
} |
|
} |
|
return false |
|
} |
|
|
|
func WithdrawAmount(w PayWay, success bool, amount int64) { |
|
WithdrawWeightLock.Lock() |
|
defer WithdrawWeightLock.Unlock() |
|
con := call.GetConfigWithdrawChannelsByID(int(w), common.CurrencyINR) |
|
if con == nil { |
|
return |
|
} |
|
fee := con.CalAmount(amount) |
|
// 成功扣除余额,失败的情况,余额退回 |
|
if success { |
|
fee = -fee |
|
} |
|
con.Amount += fee |
|
util.Go(func() { |
|
db.Mysql().UpdateW(&common.ConfigWithdrawChannels{}, map[string]interface{}{"amount": gorm.Expr("amount + ?", fee)}, fmt.Sprintf("channel_id = %d", int(w))) |
|
}) |
|
}
|
|
|