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

744 lines
16 KiB

1 year ago
package values
import (
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
1 year ago
"net/url"
"reflect"
1 year ago
"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
2 months ago
SPay
VendooPay
1 year ago
EaniPay
1 year ago
AgroPay
3 months ago
H4Pay
NativePay
FeiPay
VTPay
NewbePay
RoosPay
ProPay
FoxPay
SuperPay
STGopay
Qeelinpay
Airpay
NSpay
Rupeepay
Fpay
Kingpay
TKPay
GalloPay
MLPay2
GlobalPay
DDayPay
HongxinPay
RichPay
MoneydealerPay
MtxxPay
RobusPay
MoneydealerNativePay
2 months ago
VirgoPay
1 year ago
PayAll
)
2 months ago
type WithdrawWay int
const (
FunzoneWithdraw WithdrawWay = iota
WellWithdraw
OctroWithdraw
IGeekWithdraw
CloudWithdraw
VSWithdraw
JoyWithdraw
FFWithdraw
BestWithdraw
HXWithdraw
MGWithdraw
OOWithdraw
ZWWithdraw
FastWithdraw
HaoWithdraw
QPWithdraw
OwlWithdraw
SkyWithdraw
GreWithdraw
MoonWithdraw
AceWithdraw
MccWithdraw
YoduWithdraw
WordWithdraw
HWWithdraw
JJWithdraw
AntWithdraw
MLWithdraw
RojWithdraw
QuantaWithdraw
InnoWithdraw
PeWithdraw
FF8Withdraw
FlaWithdraw
DidaWithdraw
CYGGWithdraw
ZWithdraw
HappyWithdraw
FastPlusWithdraw
GoWithdraw
LemonWithdraw
CamelWithdraw
MoonWithdraw2
SWithdraw
VendooWithdraw
MtxxPayWithdraw
RobusWithdraw
WithdrawAll
)
1 year ago
// 错误码
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 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)
}
1 year ago
func PayFail(w PayWay) {
2 months ago
if w == MoneydealerPay {
return
}
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)
1 year ago
}
1 year ago
func PaySuccess(w PayWay) {
2 months ago
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)
1 year ago
}
// 获取支付回调路径
func GetPayCallback(way PayWay) string {
1 year ago
return config.GetConfig().Pay.CallbackURL + "/callback/pay/" + fmt.Sprintf("%d", way)
1 year ago
}
// 获取退出回调路径
func GetWithdrawCallback(way PayWay) string {
1 year ago
return config.GetConfig().Pay.CallbackURL + "/callback/withdraw/" + fmt.Sprintf("%d", way)
1 year ago
}
func GetFrontCallback() string {
1 year ago
return config.GetConfig().Pay.CallbackURL + "/common/front/payCallback"
1 year ago
}
func GetFrontCallbackFail() string {
1 year ago
return config.GetConfig().Pay.CallbackURL + "/common/front/payCallback/fail"
1 year ago
}
// 根据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) {
channel := &common.ConfigWithdrawChannels{
ChannelID: p,
}
db.Mysql().Get(&channel)
if channel.WithdrawPer+amount > 100 {
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)
}
}
}
1 year ago
func AddPayChannel(p int, amount int) {
2 months ago
log.Debug("update pay per, %d:%d", p, amount)
if err := db.Mysql().C().Model(&common.ConfigPayChannels{}).Where("channel_id = ? and pay_per > 0 ", p).
Updates(map[string]interface{}{"pay_per": gorm.Expr("pay_per + ?", amount)}).Error; err != nil {
log.Error("err:%v", err)
1 year ago
}
}
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)))
})
}
1 year ago
// 根据body里的字段直接拼接出签名字符串
func GetSignStrURLEncode(str string, pass ...string) string {
sortStrs := []string{}
all, err := url.ParseQuery(str)
if err != nil {
log.Error("err:%e", err)
return ""
}
for k := range all {
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
}
tmp := all.Get(v)
if len(tmp) > 1 && tmp[0] == 34 {
tmp = tmp[1 : len(tmp)-1]
}
if len(tmp) == 0 {
continue
}
signStr += fmt.Sprintf("%v=%v", v, string(tmp))
signStr += "&"
}
signStr = signStr[:len(signStr)-1]
log.Debug("signStr:%v", signStr)
return signStr
}
func GetSignStrFormURLEncode(c *gin.Context, model interface{}, pass ...string) string {
sortStrs := []string{}
for k := range c.Request.URL.Query() {
sortStrs = append(sortStrs, k)
}
// ref := reflect.ValueOf(model)
reft := reflect.TypeOf(model)
if reft.Kind() == reflect.Ptr {
// ref = ref.Elem()
reft = reft.Elem()
}
signStr := ""
sort.Strings(sortStrs)
for _, v := range sortStrs {
shouldPass := false
for _, s := range pass {
if v == s {
shouldPass = true
break
}
}
if shouldPass {
continue
}
param := c.Query(v)
if len(param) == 0 {
continue
}
first := v[0]
tmpName := strings.ToUpper(string(first)) + v[1:]
field, ok := reft.FieldByName(tmpName)
if ok && field.Tag.Get("encode") == "1" { // 需要urlencode
param, _ = url.QueryUnescape(param)
}
signStr += fmt.Sprintf("%v=%v", v, param)
signStr += "&"
}
fmt.Println(signStr)
signStr = signStr[:len(signStr)-1]
log.Debug("signStr:%v", signStr)
return signStr
}
2 months ago
func GetSignStrGet(vals url.Values, pass ...string) string {
sortStrs := []string{}
for k := range vals {
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(vals.Get(v)) == 0 {
continue
}
signStr += fmt.Sprintf("%v=%v", v, vals.Get(v))
signStr += "&"
}
signStr = signStr[:len(signStr)-1]
log.Debug("signStr:%v", signStr)
return signStr
}