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 ( InvalidPay PayWay = iota IGeekPay PlusPay LuckinPay BFPay Grepay PayAll ) // 错误码 const ( CodeOk = iota ) var ( PayWeightLock = 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 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 }