印度包网
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.

491 lines
11 KiB

1 year ago
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
1 year ago
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
1 year ago
PayAll
)
// 错误码
const (
CodeOk = iota
)
var (
PayWeightLock = new(sync.RWMutex)
WithdrawWeightLock = new(sync.RWMutex)
1 year ago
)
// 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 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 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)))
})
}