|
|
@@ -1,6 +1,9 @@
|
|
|
package model
|
|
|
|
|
|
import (
|
|
|
+ "crypto/md5"
|
|
|
+ "encoding/hex"
|
|
|
+ "encoding/json"
|
|
|
"errors"
|
|
|
"fmt"
|
|
|
"math"
|
|
|
@@ -11,6 +14,8 @@ import (
|
|
|
"rocommon/util"
|
|
|
"roserver/baseserver/model"
|
|
|
"roserver/serverproto"
|
|
|
+ "sort"
|
|
|
+ "strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
|
"unicode/utf8"
|
|
|
@@ -59,6 +64,7 @@ type RoleOuter interface {
|
|
|
SetHardFight(b int)
|
|
|
SetYuanRankScore()
|
|
|
SetSdkJson(a string)
|
|
|
+ SetSdkJson2(a string)
|
|
|
GetSdkJson() string
|
|
|
}
|
|
|
|
|
|
@@ -507,6 +513,7 @@ type Role struct {
|
|
|
activeCode string //激活码
|
|
|
isHardFight int //是否是困难模式 //0普通.1困难,2噩梦
|
|
|
Guid string //小七uid
|
|
|
+ Guid2 string //小七uid
|
|
|
|
|
|
base *RoleBase //角色基础信息
|
|
|
roleHero *RoleHero //伙伴信息
|
|
|
@@ -692,6 +699,9 @@ func (this *Role) GetSdkJson() string {
|
|
|
func (this *Role) SetSdkJson(a string) {
|
|
|
this.Guid = a
|
|
|
}
|
|
|
+func (this *Role) SetSdkJson2(a string) {
|
|
|
+ this.Guid2 = a
|
|
|
+}
|
|
|
func (this *Role) SetSelectZone(selectZone int32) {
|
|
|
if selectZone <= 0 {
|
|
|
this.selectZone = int32(service.GetServiceConfig().Node.Zone)
|
|
|
@@ -3695,12 +3705,52 @@ func (this *Role) PayInfoGet(goodsType, goodsId, count int32, rushStage, rushRou
|
|
|
util.InfoF("uid=%v pc mode: shop:%v id:%v, count:%v, price:%v", this.GetUUid(), payOrderInfo.GoodsType, payOrderInfo.GoodsId, payOrderInfo.Count, payOrderInfo.Amount)
|
|
|
return
|
|
|
}
|
|
|
+ server := int(payOrderInfo.SId / 2)
|
|
|
+ corderid := strconv.FormatUint(payOrderInfo.CpOrderId, 10)
|
|
|
+ price := fmt.Sprintf("%.2f", payOrderInfo.Amount)
|
|
|
+ guid, _ := strconv.Atoi(this.Guid2)
|
|
|
+ name := this.GetNickName()
|
|
|
+ if name == "" {
|
|
|
+ name = "Player"
|
|
|
+ }
|
|
|
+ ordeinfo := OrderRequest{
|
|
|
+ GameArea: strconv.Itoa(server),
|
|
|
+ GameLevel: strconv.Itoa(int(this.GetRoleLevel())),
|
|
|
+ GameOrderId: corderid,
|
|
|
+ GameCurrency: "USD",
|
|
|
+ GamePrice: price,
|
|
|
+ GameRoleId: strconv.Itoa(int(this.GetUUid())),
|
|
|
+ GameRoleName: name,
|
|
|
+ GameGuid: guid,
|
|
|
+ NotifyId: service.GetServiceConfig().Node.PayCallBack,
|
|
|
+ Subject: price + " Pack",
|
|
|
+ GameAccessVersion: "2507",
|
|
|
+ }
|
|
|
+ extra := &Extras{
|
|
|
+ ServerId: server,
|
|
|
+ Platform: this.platform,
|
|
|
+ CpOrderId: corderid,
|
|
|
+ }
|
|
|
+ v, _ := json.Marshal(extra)
|
|
|
+ ordeinfo.ExtendsInfoData = string(v)
|
|
|
+
|
|
|
payOrderInfo.SdkOrderId = sdkOrderId
|
|
|
//保存订单信息到数据库
|
|
|
ackMsg.Amount = payOrderInfo.Amount
|
|
|
ackMsg.CpOrderId = payOrderInfo.CpOrderId
|
|
|
- ackMsg.GoodsName = payOrderInfo.GoodsName
|
|
|
- //ackMsg.GoodsName = service.GetServiceConfig().Node.PayCallBack
|
|
|
+ //ackMsg.GoodsName = payOrderInfo.GoodsName
|
|
|
+ info, err := GenerateGameSign(ordeinfo, "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCfYd3FqSaWqCpWLSktBSSgAelt0F6T+tO4C25YKR/6X/sPacDBbX662/0fW+H+YbXigHWFB/yangkhiZTpD/VmiOo5lISX6L0/m+13ti9b8jzTZcfVngfLsP+Ztbk81N1Jk0gWF4bndZxREJ3IxcEDHnIrwXgLGA2GJ89kdgudwIDAQAB")
|
|
|
+ if err != nil {
|
|
|
+ ackMsg.Error = int32(serverproto.ErrorCode_ERROR_PAY_NOT_OPEN)
|
|
|
+ this.ReplayGate(ackMsg, true)
|
|
|
+ util.ErrorF("uid=%v GenerateGameSign err:%v", this.GetUUid(), err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ordeinfo.GameSign = info
|
|
|
+ b, _ := json.Marshal(ordeinfo)
|
|
|
+ payOrderInfo.GoodsName = string(b)
|
|
|
+
|
|
|
+ util.ErrorF("uid:%v pay info platform:%v order:%v", this.GetUUid(), this.platform, payOrderInfo)
|
|
|
ssSaveReqMsg := &serverproto.SSPayInfoSaveReq{
|
|
|
PayOrderInfo: payOrderInfo,
|
|
|
SaveNotify: true,
|
|
|
@@ -3711,6 +3761,139 @@ func (this *Role) PayInfoGet(goodsType, goodsId, count int32, rushStage, rushRou
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+func GenerateGameSign(params interface{}, rsaPublicKey string) (string, error) {
|
|
|
+ // 1. 将结构体转换为 map
|
|
|
+ paramsMap, err := structToMap(params)
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 过滤掉 game_sign 字段
|
|
|
+ delete(paramsMap, "game_sign")
|
|
|
+
|
|
|
+ // 3. 获取所有 key 并排序(字典序)
|
|
|
+ keys := make([]string, 0, len(paramsMap))
|
|
|
+ for k := range paramsMap {
|
|
|
+ keys = append(keys, k)
|
|
|
+ }
|
|
|
+ sort.Strings(keys)
|
|
|
+
|
|
|
+ // 4. 按顺序构建 QueryString
|
|
|
+ var queryParts []string
|
|
|
+ for _, k := range keys {
|
|
|
+ v := paramsMap[k]
|
|
|
+ // 跳过空值或零值(根据实际需求调整)
|
|
|
+ if v == "" || v == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ // 将值转换为字符串
|
|
|
+ strValue := fmt.Sprintf("%v", v)
|
|
|
+ queryParts = append(queryParts, fmt.Sprintf("%s=%s", k, strValue))
|
|
|
+ }
|
|
|
+ queryString := strings.Join(queryParts, "&")
|
|
|
+
|
|
|
+ // 5. 在 QueryString 后面拼接 RSA 公钥
|
|
|
+ stringToSign := queryString + rsaPublicKey
|
|
|
+
|
|
|
+ // 6. 计算 MD5
|
|
|
+ hash := md5.Sum([]byte(stringToSign))
|
|
|
+ sign := hex.EncodeToString(hash[:])
|
|
|
+
|
|
|
+ return sign, nil
|
|
|
+}
|
|
|
+
|
|
|
+// structToMap 将结构体转换为 map[string]interface{}
|
|
|
+// 使用 json tag 作为 key
|
|
|
+func structToMap(obj interface{}) (map[string]interface{}, error) {
|
|
|
+ result := make(map[string]interface{})
|
|
|
+
|
|
|
+ v := reflect.ValueOf(obj)
|
|
|
+ t := reflect.TypeOf(obj)
|
|
|
+
|
|
|
+ // 如果是指针,获取其指向的值
|
|
|
+ if v.Kind() == reflect.Ptr {
|
|
|
+ v = v.Elem()
|
|
|
+ t = t.Elem()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保是结构体类型
|
|
|
+ if v.Kind() != reflect.Struct {
|
|
|
+ return nil, fmt.Errorf("expected struct, got %v", v.Kind())
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 0; i < v.NumField(); i++ {
|
|
|
+ field := t.Field(i)
|
|
|
+ value := v.Field(i)
|
|
|
+
|
|
|
+ // 获取 json tag
|
|
|
+ jsonTag := field.Tag.Get("json")
|
|
|
+ if jsonTag == "" || jsonTag == "-" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理 omitempty(去除后面的,omitempty)
|
|
|
+ jsonTag = strings.Split(jsonTag, ",")[0]
|
|
|
+
|
|
|
+ // 获取字段值
|
|
|
+ if value.Kind() == reflect.Ptr && value.IsNil() {
|
|
|
+ result[jsonTag] = nil
|
|
|
+ } else {
|
|
|
+ result[jsonTag] = value.Interface()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result, nil
|
|
|
+}
|
|
|
+
|
|
|
+type OrderRequest struct {
|
|
|
+ // 訂單擴展數據,支持JSON或QueryString格式
|
|
|
+ ExtendsInfoData string `json:"extends_info_data"` // 最大128字符
|
|
|
+
|
|
|
+ // 角色所在的遊戲區,須與X7game平台上傳的開服表信息中的支付顯示區服欄位一致
|
|
|
+ GameArea string `json:"game_area"` // 最大20字符,必填
|
|
|
+
|
|
|
+ // 用戶遊戲中角色等級
|
|
|
+ GameLevel string `json:"game_level"` // 最大30字符,必填
|
|
|
+
|
|
|
+ // 遊戲訂單號
|
|
|
+ GameOrderId string `json:"game_orderid"` // 最大100字符,必填
|
|
|
+
|
|
|
+ // 貨幣單位,可用值:CNY,USD,HKD,VND,KRW (game_access_version=7.98時新增)
|
|
|
+ GameCurrency string `json:"game_currency"` // 最大10字符,必填
|
|
|
+
|
|
|
+ // 商品價格,保留小數點後兩位
|
|
|
+ GamePrice string `json:"game_price"` // 格式:10,2,必填
|
|
|
+
|
|
|
+ // 用戶遊戲中角色id信息
|
|
|
+ GameRoleId string `json:"game_role_id"` // 最大30字符,必填
|
|
|
+
|
|
|
+ // 用戶遊戲中角色名稱
|
|
|
+ GameRoleName string `json:"game_role_name"` // 最大30字符,必填
|
|
|
+
|
|
|
+ // 用戶遊戲小號的唯一標識
|
|
|
+ GameGuid int `json:"game_guid"` // 最大12位整數,必填
|
|
|
+
|
|
|
+ // 支付回調通知id,可設置為-1,但不允許為0
|
|
|
+ NotifyId string `json:"notify_id"` // 最大11字符,必填
|
|
|
+
|
|
|
+ // 道具簡介
|
|
|
+ Subject string `json:"subject"` // 最大100字符,必填
|
|
|
+
|
|
|
+ // 簽名,將其他所有字段按字典序生成QueryString後拼接小7RSA公鑰,再MD5
|
|
|
+ GameSign string `json:"game_sign"` // 最大32字符,必填
|
|
|
+
|
|
|
+ // 接入簽名方式版本,新遊戲接入選擇 '2507'
|
|
|
+ GameAccessVersion string `json:"game_access_version"` // 最大10字符,必填
|
|
|
+}
|
|
|
+
|
|
|
+type Extras struct {
|
|
|
+ ServerId int `json:"serverId"`
|
|
|
+ Platform string `json:"platform"`
|
|
|
+ SubPlatform string `json:"subPlatform"`
|
|
|
+ Bima string `json:"bima"`
|
|
|
+ CpOrderId string `json:"cpOrderId"`
|
|
|
+}
|
|
|
+
|
|
|
func (this *Role) payInfoGet(goodsType, goodsId, count int32, rushStage, rushRound int32, cpOrderId uint64) (serverproto.ErrorCode, *serverproto.PayOrderSaveInfo) {
|
|
|
if count <= 0 {
|
|
|
return serverproto.ErrorCode_ERROR_PAY_ITEM_NO, nil
|
|
|
@@ -3820,8 +4003,8 @@ func (this *Role) payInfoGet(goodsType, goodsId, count int32, rushStage, rushRou
|
|
|
return serverproto.ErrorCode_ERROR_FAIL, nil
|
|
|
}
|
|
|
|
|
|
- payRewardInfo.GoodsName = service.GetServiceConfig().Node.PayCallBack
|
|
|
- util.ErrorF("uid:%v pay info platform:%v order:%v", this.GetUUid(), this.platform, payRewardInfo)
|
|
|
+ //payRewardInfo.GoodsName = service.GetServiceConfig().Node.PayCallBack
|
|
|
+ //util.ErrorF("uid:%v pay info platform:%v order:%v", this.GetUUid(), this.platform, payRewardInfo)
|
|
|
//if this.platform == SDKPlatform_YouYi_IOS || this.platform == "PC" {
|
|
|
// payRewardInfo.GoodsName += ",1"
|
|
|
//}
|