From 17d1ac013147c632de5ed012ffb66f8f91d05567 Mon Sep 17 00:00:00 2001 From: zhora Date: Fri, 12 Sep 2025 16:22:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5sn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/activity.go | 2 +- common/provider.go | 1 + modules/web/app/provider.go | 23 + modules/web/providers/all/all.go | 3 + modules/web/providers/sn/api.go | 220 ++++++++++ modules/web/providers/sn/base.go | 160 +++++++ modules/web/providers/sn/handler.go | 638 ++++++++++++++++++++++++++++ modules/web/providers/sn/values.go | 210 +++++++++ 8 files changed, 1256 insertions(+), 1 deletion(-) create mode 100644 modules/web/providers/sn/api.go create mode 100644 modules/web/providers/sn/base.go create mode 100644 modules/web/providers/sn/handler.go create mode 100644 modules/web/providers/sn/values.go diff --git a/common/activity.go b/common/activity.go index aa75ccc..e735ab7 100644 --- a/common/activity.go +++ b/common/activity.go @@ -675,7 +675,7 @@ type ConfigWeekCard struct { Switch int `gorm:"column:switch;type:int(11);default:0;comment:开关(1开2关)" json:"Switch" web:"switch"` Amount int64 `gorm:"column:amount;type:int(20);default:50000;comment:周卡价格" json:"Amount" web:"amount"` // []WeekCardDay json - AwardData string `gorm:"column:award_data;type:varchar(512);default:'';comment:奖励数据" json:"awardData" web:"award_data"` + AwardData string `gorm:"column:award_data;type:varchar(512);default:'';comment:奖励数据" json:"AwardData" web:"award_data"` AwardDetails map[int]WeekCardDay `gorm:"-"` UpdatedBase diff --git a/common/provider.go b/common/provider.go index d3fb78d..5f1e4c3 100644 --- a/common/provider.go +++ b/common/provider.go @@ -40,6 +40,7 @@ const ( ProviderPG3 ProviderJin ProviderJin2 + ProviderSn ProviderAll ) diff --git a/modules/web/app/provider.go b/modules/web/app/provider.go index d94e0b6..c5ea43b 100644 --- a/modules/web/app/provider.go +++ b/modules/web/app/provider.go @@ -44,3 +44,26 @@ func (g *Gin) ShouldRoute(req interface{}, fieldName string, apiType int) bool { } return true } + +// ShouldRouteByAccount 是否需要转发到其他服 +func (g *Gin) ShouldRouteByAccount(account *string, apiType int, req interface{}, headers map[string]string) bool { + flag, userName := ParseUser(*account) + log.Debug("flag:%v,userName:%v", flag, userName) + if config.GetBase().ServerFlag == flag { + if *account != userName { + *account = userName + } + return false + } + server := call.GetConfigServerFlag(flag) + if server == nil { + return false + } + apiURL := fmt.Sprintf("%s%s", server.APIURL, g.Context.Request.URL.Path) + if apiType == common.ProviderAPITypeJson { + util.HttpPost(apiURL, req, g.RetData, headers) + } else { + util.HttpPostForm(apiURL, req, g.RetData, headers) + } + return true +} diff --git a/modules/web/providers/all/all.go b/modules/web/providers/all/all.go index ebbf72b..f433834 100644 --- a/modules/web/providers/all/all.go +++ b/modules/web/providers/all/all.go @@ -13,6 +13,7 @@ import ( "server/modules/web/providers/pg2" "server/modules/web/providers/pg3" "server/modules/web/providers/pgsoft" + "server/modules/web/providers/sn" "server/modules/web/providers/tada" "github.com/gin-gonic/gin" @@ -57,6 +58,7 @@ type AllProvider struct { PG3 func(b *base.Base) Jin func(b *base.Base) Jin2 func(b *base.Base) + Sn func(b *base.Base) } var All = &AllProvider{} @@ -102,6 +104,7 @@ func initAll() { All.PG3 = pg3.NewSub All.Jin = jin.NewSub All.Jin2 = jin2.NewSub + All.Sn = sn.NewSub } func InitRouter(r *gin.RouterGroup) { diff --git a/modules/web/providers/sn/api.go b/modules/web/providers/sn/api.go new file mode 100644 index 0000000..36440e8 --- /dev/null +++ b/modules/web/providers/sn/api.go @@ -0,0 +1,220 @@ +package sn + +// Success Codes +const ( + CodeSuccess = 0 // 操作成功 + + SnAccount = "wjA77Game_N601" + DefaultLanguage = "en" + AgentId = 320 + SnId = 135 + SignKey = "2e0af20e8f0444a7decde7ae4c382dec" +) + +// Request Error Codes +const ( + CodeRequestSuccess = 1001 // 成功 + + CodeRequestInvalidGameId = 100214 // 无效的游戏id + CodeRequestInvalidGame = 100202 // 游戏不存在 + CodeRequestInvalidUser = 100213 // 玩家不存在 + CodeRequestExist = 100216 // 玩家已经存在 +) + +// Operation Error Codes +const ( + INVALIDREQUESTERR = 1 // 参数错误 + CodeOperationFailed = 3001 // 操作失败(没有具体的失败原因说明) + CodeUserNotFound = 3002 // 用户不存在 + CodeUserDataIncomplete = 3003 // 用户数据未加载完全 + CodeParameterProcessingError = 3004 // 参数处理异常(一般是数据不一致导致的) + CodeDuplicateOrder = 3005 // 订单号重复 + CodeTokenMismatch = 3006 // Token不一致 + CodeRequestRateLimit = 3007 // 请求频率过高 + CodeInsufficientBalance = 3008 // 余额不足 +) + +type BaseReq struct { + SnAccount string `json:"sn_account"` + Time int64 `json:"time"` + Sign string `json:"sign"` +} + +type GetBalanceReq struct { + CoinCode string `json:"coin_code"` + GameId int `json:"game_id"` + RoomType string `json:"room_type"` + Timestamp int64 `json:"timestamp"` + Sign string `json:"sign"` +} + +type GetBalanceResp struct { + Code int `json:"code"` + Data struct { + Chips int `json:"chips"` + } `json:"data"` + Msg string `json:"msg"` +} + +//type GameBetReq struct { +// IsEnd bool // 返奖时游戏结束标识(true: 当前对局已结束, false: 当前对局未结束) +// AppID string // 运营商唯一标识 +// AppSecret string // 运营商 AppSecret +// UserID string // 运营商的玩家唯一标识 +// TransactionID string // 交易订单号 +// Amount float64 // 增加/扣除金额(+ 增加, - 扣除) +// RoundID string // 本局游戏 ID +// GameID string // 游戏 ID +// ReqTime string // 请求时间 +// Reason string // bet 下注扣款; win 派奖; refund 服务器内部出错,退回下注 +//} + +type GameBetReq struct { + CoinCode string `json:"coin_code"` // 金币类型 + GameId int `json:"game_id"` // 游戏id + RoomType string `json:"room_type"` // 玩法 + OrderId string `json:"order_id"` // 订单id + MinAmount int `json:"min_amount"` // 最小下注值 + Amount int `json:"amount"` // 最大下注值 + BetId string `json:"bet_id"` // 下注id + Sign string `json:"sign"` // 签名 +} + +type GameBetResp struct { + Code int `json:"code"` // 0成功 1失败 + Msg string `json:"msg"` + Data struct { + Chips int `json:"chips"` // 余额 + DeductionAmount int `json:"deduction_amount"` // 本次扣除 + } `json:"data"` +} + +type JackpotReq struct { + Reference string `json:"reference" form:"reference"` // 当前注单号 + OperatorID string `json:"operator_id" form:"operator_id"` // 本平台提供的运营商ID + Accounts string `json:"accounts" form:"accounts"` // 运营的游戏帐号或ID + Token string `json:"token" form:"token"` // authentication 返回的 token + GameID string `json:"game_id" form:"game_id"` // 游戏类型ID + RoomID string `json:"room_id" form:"room_id"` // 游戏房间ID + WinAmount float64 `json:"win_amount" form:"win_amount"` // 当前游戏彩金金额 + RecordType string `json:"record_type" form:"record_type"` // 10 小彩金 11 大彩金 12 中等彩金 + BetReferenceID string `json:"bet_reference_id" form:"bet_reference_id"` // 压注注单号 + RoundID string `json:"round_id" form:"round_id"` // 局号 +} + +type JackpotResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + Amount float64 `json:"amount"` + } `json:"data"` +} + +type SettleReq struct { + BackAmount int `json:"back_amount"` + CoinCode string `json:"coin_code"` + Details []struct { + AllBets int `json:"all_bets"` + Amount int `json:"amount"` + BetId string `json:"bet_id"` + CodedQuantity int `json:"coded_quantity"` + Index int `json:"index"` + IsFinish bool `json:"is_finish"` + WinAmount int `json:"win_amount"` + } `json:"details"` + GameId int `json:"game_id"` + IsFree bool `json:"is_free"` + IsOrderFinish bool `json:"is_order_finish"` + JpBonus int `json:"jp_bonus"` + JpContri int `json:"jp_contri"` + OrderId string `json:"order_id"` + RoomType string `json:"room_type"` + RoundId string `json:"round_id"` + SettlementId string `json:"settlement_id"` + Sign string `json:"sign"` + Timestamp int `json:"timestamp"` +} + +type SettleResp struct { + Code int `json:"code"` // 0成功 1失败 + Msg string `json:"msg"` + Data struct { + Chips int `json:"chips"` // 余额 + } `json:"data"` +} + +type RollbackReq struct { + CoinCode string `json:"coin_code"` + GameId int `json:"game_id"` + RoomType string `json:"room_type"` + OrderId string `json:"order_id"` + Sign string `json:"sign"` +} + +type RollbackResp struct { + Code int `json:"code"` // 0成功 1失败 + Msg string `json:"msg"` + Data struct { + Chips int `json:"chips"` // 余额 + } `json:"data"` +} + +type UpdateReq struct { + CoinCode string `json:"coin_code"` // 金币类型 + GameId int `json:"game_id"` + RoomType string `json:"room_type"` + OrderId string `json:"order_id"` + SubTypeId int `json:"sub_type_id"` // 更新金币类型 + Amount int `json:"amount"` // 更新数值 + Extend map[string]interface{} `json:"extend"` // 扩展信息 + Sign string `json:"sign"` +} + +type UpdateResp struct { + Code int `json:"code"` // 0成功 1失败 + Msg string `json:"msg"` + Data struct { + Chips int `json:"chips"` // 余额 + } `json:"data"` +} + +type GameControlCallbackReq struct { + Type string `json:"type"` + ControlId string `json:"control_id"` + Sign string `json:"sign"` +} + +type GameControlCallbackResp struct { + Code int `json:"code"` // 0成功 1失败 + Msg string `json:"msg"` +} + +type ControlReq struct { + BaseReq + ThirdName string `json:"third_name"` + ControlId int `json:"control_id"` + TemplateId int `json:"template_id"` + Data []struct { + TargetRtp int `json:"target_rtp"` + } `json:"data"` + Sn int `json:"sn"` + ControlDesc string `json:"control_desc"` + AgentId int `json:"agent_id"` + UserId int `json:"user_id"` +} + +type ControlResp struct { + Code int `json:"code"` + Success bool `json:"success"` + StatusCode int `json:"status_code"` + System int `json:"system"` + Message string `json:"message"` + Msg string `json:"msg"` + Prompt string `json:"prompt"` + RequestId string `json:"request_id"` + RequestMethod string `json:"request_method"` + Provider string `json:"provider"` + Doc string `json:"doc"` + Data struct { + } `json:"data"` +} diff --git a/modules/web/providers/sn/base.go b/modules/web/providers/sn/base.go new file mode 100644 index 0000000..246d8cf --- /dev/null +++ b/modules/web/providers/sn/base.go @@ -0,0 +1,160 @@ +package sn + +import ( + "encoding/json" + "fmt" + "server/call" + "server/config" + "server/modules/web/providers/base" + "server/util" + "time" + + "github.com/liangdas/mqant/log" +) + +type Sub struct { + Base *base.Base +} + +func NewSub(base *base.Base) { + base.Sub = &Sub{Base: base} + base.SubInitRouter = Sn +} + +func (s *Sub) Init() { + API = APITest + APICreate = APICreateUserTest + APIControl = APIControlTest + AgentMap = AgentMapTest + if config.GetBase().Release { + API = APIRlease + APICreate = APICreateUserRlease + APIControl = APIControlRlease + AgentMap = AgentMapRelease + } +} + +type EnterReq struct { + BaseReq + + GameId int `json:"game_id"` // 游戏id + AgentId int `json:"agent_id"` // 代理id + ThirdName string `json:"third_name"` // 第三方昵称 + ClientIp string `json:"client_ip"` + + Language string `json:"language"` // 语言 +} + +type EnterResp struct { + Code int `json:"code"` + Success bool `json:"success"` + StatusCode int `json:"status_code"` + System int `json:"system"` + Msg string `json:"msg"` + Prompt string `json:"prompt"` + RequestId string `json:"request_id"` + RequestMethod string `json:"request_method"` + Provider string `json:"provider"` + Doc string `json:"doc"` + Data struct { + GameUrl string `json:"game_url"` + GameIdBase64 string `json:"game_id_base64"` + ApiGameBase64 string `json:"api_game_base64"` + ApiGameToken string `json:"api_game_token"` + Language string `json:"language"` + OrderIdList interface{} `json:"order_id_list"` + } `json:"data"` +} + +type CreateUserReq struct { + BaseReq + ThirdName string `json:"third_name"` + AgentId int `json:"agent_id"` + UserType int `json:"user_type"` +} + +type CreateUserResp struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data struct { + OpenId int64 `json:"open_id"` + } `json:"data"` +} + +func (s *Sub) EnterGame() string { + log.Debug("sn enter game, %+v", *s.Base.EnterGameReq) + providerID := s.Base.EnterGameReq.ProviderID + gameID := s.Base.EnterGameReq.GameID + game := call.GetGameListByByID(providerID, gameID) + if game == nil { + return "" + } + + req := &EnterReq{ + BaseReq: BaseReq{ + SnAccount: SnAccount, + Time: time.Now().Unix(), + }, + GameId: game.GameID, + AgentId: AgentId, + ThirdName: call.GetProviderUserName(fmt.Sprintf("%d", s.Base.UID)), + ClientIp: s.Base.IP, + Language: DefaultLanguage, + } + + reqBody, _ := json.Marshal(req) + var tmpValue map[string]interface{} + json.Unmarshal(reqBody, &tmpValue) + req.Sign = GeneratedSign(tmpValue, SignKey) + + var resp EnterResp + err := util.HttpPost(API, req, &resp, nil) + if err != nil { + log.Error("err:%v", err) + return "" + } + if resp.Code == CodeRequestInvalidUser { + err = s.createUser() + if err != nil { + log.Error("create err, %s", err.Error()) + return "" + } + return s.EnterGame() + } + if resp.Data.GameUrl == "" { + log.Error("err:%+v", resp) + return "" + } + + return resp.Data.GameUrl +} + +func (s *Sub) createUser() error { + log.Debug("sn create user, %+v", *s.Base.EnterGameReq) + req := &CreateUserReq{ + BaseReq: BaseReq{ + SnAccount: SnAccount, + Time: time.Now().Unix(), + }, + AgentId: AgentId, + ThirdName: call.GetProviderUserName(fmt.Sprintf("%d", s.Base.UID)), + } + + reqBody, _ := json.Marshal(req) + var tmpValue map[string]interface{} + json.Unmarshal(reqBody, &tmpValue) + req.Sign = GeneratedSign(tmpValue, SignKey) + + var resp CreateUserResp + err := util.HttpPost(APICreate, req, &resp, nil) + if err != nil { + log.Error("err:%v", err) + return err + } + if resp.Code != CodeRequestSuccess && resp.Code != CodeRequestExist { + log.Error("create uer err, %+v", resp) + return fmt.Errorf("create err, %+v ", resp) + } + + return nil +} diff --git a/modules/web/providers/sn/handler.go b/modules/web/providers/sn/handler.go new file mode 100644 index 0000000..4b44d90 --- /dev/null +++ b/modules/web/providers/sn/handler.go @@ -0,0 +1,638 @@ +package sn + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "server/call" + "server/common" + "server/db" + "server/modules/web/app" + "server/modules/web/providers/base" + "server/util" + "strconv" + "time" + + "github.com/gin-gonic/gin" + "github.com/liangdas/mqant/log" +) + +func Sn(e *gin.RouterGroup) { + e.POST("/wallet_request", GetBalance) + e.POST("/wallet_bet", GameBet) + e.POST("/wallet_settlement", Settle) + e.POST("/wallet_bet_rollback", Rollback) + e.POST("/wallet_update", Update) + e.POST("/game_control_callback", GameControlCallback) +} + +func GetBalance(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.ResponseB() + }() + req := &GetBalanceReq{} + resp := &GetBalanceResp{} + a.RetData = resp + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + log.Error("read body err: %v", err) + resp.Code = INVALIDREQUESTERR + return + } + log.Debug("get balance:%s", string(body)) + err = json.Unmarshal(body, &req) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + + account := c.GetHeader("account") + headers := make(map[string]string) + for key, values := range c.Request.Header { + if len(values) > 0 { + headers[key] = values[0] // 取第一个值 + } + } + if a.ShouldRouteByAccount(&account, common.ProviderAPITypeJson, req, headers) { + return + } + newBody, _ := json.Marshal(req) + var tmpValue map[string]interface{} + json.Unmarshal(newBody, &tmpValue) + tmpSign := GeneratedSign(tmpValue, SignKey) + if tmpSign != req.Sign { + log.Error("sign is wrong, %+v", req) + resp.Code = INVALIDREQUESTERR + return + } + uids := account + uid, err := strconv.Atoi(uids) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + + currency, err := db.Redis().GetInt(common.GetRedisKeyGameCurrency(uid)) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + + resp.Msg = "success" + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(currency), 0) * common.DecimalDigits) + log.Debug("GetBalanceResp:%+v", resp) +} + +func GameBet(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.ResponseB() + }() + req := &GameBetReq{} + resp := &GameBetResp{} + a.RetData = resp + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + log.Error("read body err: %v", err) + resp.Code = INVALIDREQUESTERR + return + } + log.Debug("game bet:%s", string(body)) + err = json.Unmarshal(body, &req) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + account := c.GetHeader("account") + headers := make(map[string]string) + for key, values := range c.Request.Header { + if len(values) > 0 { + headers[key] = values[0] // 取第一个值 + } + } + if a.ShouldRouteByAccount(&account, common.ProviderAPITypeJson, req, headers) { + return + } + //reqBody, _ := json.Marshal(req) + var tmpValue map[string]interface{} + err = json.Unmarshal(body, &tmpValue) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + tmpSign := GeneratedSign(tmpValue, SignKey) + if tmpSign != req.Sign { + log.Error("sign is wrong, %+v", req) + resp.Code = INVALIDREQUESTERR + return + } + uids := account + uid, err := strconv.Atoi(uids) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + provider := call.GetConfigGameProvider(common.ProviderSn) + now := time.Now().Unix() + configGame := call.GetGameListByByID(common.ProviderSn, req.GameId) + if configGame == nil { + log.Error("get game config err") + resp.Code = INVALIDREQUESTERR + return + } + betAmount := req.Amount + if betAmount < 0 { + betAmount = -req.Amount + } + betReq := &base.BetReq{ + UID: uid, + CurrencyType: common.CurrencyINR, + SessionType: base.SessionTypeBet, + GameID: req.GameId, + GameName: configGame.GameCode, + Provider: provider, + BetID: req.BetId, + SessionID: req.OrderId, + Time: now, + BetAmount: int64(betAmount), + TurnOver: int64(betAmount), + } + betResp := base.SessionBet(betReq) + if betResp.Code != base.CodeOk { + resp.Code = INVALIDREQUESTERR + if betResp.Code == base.CodeAccepted { + resp.Msg = "duplicate order" + } else if betResp.Code == base.CodeNotEnoughAmount { + resp.Msg = "insufficient balance" + } else { + resp.Msg = "operation failed." + } + log.Error("GameBetResp err:%v", resp.Code) + return + } + resp.Data.DeductionAmount = betAmount + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + resp.Msg = "success" + log.Debug("GameBetResp:%+v", resp) + a.Data = resp +} + +func Settle(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.ResponseB() + }() + req := &SettleReq{} + resp := &SettleResp{} + a.RetData = resp + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + log.Error("read body err: %v", err) + resp.Code = INVALIDREQUESTERR + return + } + log.Debug("sn Settle:%s", string(body)) + err = json.Unmarshal(body, &req) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + account := c.GetHeader("account") + headers := make(map[string]string) + for key, values := range c.Request.Header { + if len(values) > 0 { + headers[key] = values[0] // 取第一个值 + } + } + if a.ShouldRouteByAccount(&account, common.ProviderAPITypeJson, req, headers) { + return + } + var tmpValue map[string]interface{} + err = json.Unmarshal(body, &tmpValue) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + tmpSign := GeneratedSign(tmpValue, SignKey) + if tmpSign != req.Sign { + log.Error("sign is wrong, %+v", req) + resp.Code = INVALIDREQUESTERR + return + } + uids := account + uid, err := strconv.Atoi(uids) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + provider := call.GetConfigGameProvider(common.ProviderSn) + { // 订单是否合法 + record := &common.ProviderBetRecord{ + UID: uid, + Provider: provider.ProviderID, + Type: base.SessionTypeBet, + SessionID: req.OrderId, + } + db.Mysql().Get(record) + if record.ID == 0 { + resp.Code = INVALIDREQUESTERR + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + return + } + } + now := time.Now().Unix() + configGame := call.GetGameListByByID(common.ProviderSn, req.GameId) + if configGame == nil { + log.Error("get game config err") + resp.Code = INVALIDREQUESTERR + return + } + var betId string + if len(req.Details) > 0 { + betId = req.Details[0].BetId + } + settleAmount := int64(req.JpBonus + req.BackAmount) + betReq := &base.BetReq{ + UID: uid, + CurrencyType: common.CurrencyINR, + SessionType: base.SessionTypeSettle, + GameID: req.GameId, + GameName: configGame.GameCode, + Provider: provider, + BetID: betId, + SessionID: req.OrderId, + Time: now, + } + for _, detail := range req.Details { + settleAmount += int64(detail.WinAmount) + } + betReq.SettleAmount = settleAmount + betResp := base.SessionBet(betReq) + if betResp.Code != base.CodeOk { + resp.Code = INVALIDREQUESTERR + if betResp.Code == base.CodeAccepted { + resp.Msg = "duplicate order" + } else if betResp.Code == base.CodeNotEnoughAmount { + resp.Msg = "insufficient balance" + } else { + resp.Msg = "operation failed." + } + log.Error("GameBetResp err:%v", resp.Code) + return + } + + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + resp.Msg = "success" + log.Debug("SettleResp:%+v", resp) + a.Data = resp +} + +func Rollback(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.ResponseB() + }() + req := &RollbackReq{} + resp := &RollbackResp{} + a.RetData = resp + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + log.Error("read body err: %v", err) + resp.Code = INVALIDREQUESTERR + return + } + log.Debug("sn rollback:%s", string(body)) + err = json.Unmarshal(body, &req) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + account := c.GetHeader("account") + headers := make(map[string]string) + for key, values := range c.Request.Header { + if len(values) > 0 { + headers[key] = values[0] // 取第一个值 + } + } + if a.ShouldRouteByAccount(&account, common.ProviderAPITypeJson, req, headers) { + return + } + var tmpValue map[string]interface{} + err = json.Unmarshal(body, &tmpValue) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + tmpSign := GeneratedSign(tmpValue, SignKey) + if tmpSign != req.Sign { + log.Error("sign is wrong, %+v", req) + resp.Code = INVALIDREQUESTERR + return + } + uids := account + uid, err := strconv.Atoi(uids) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + provider := call.GetConfigGameProvider(common.ProviderSn) + + configGame := call.GetGameListByByID(common.ProviderSn, req.GameId) + if configGame == nil { + log.Error("get game config err") + resp.Code = INVALIDREQUESTERR + return + } + + // 订单是否合法 + record := &common.ProviderBetRecord{ + UID: uid, + Provider: provider.ProviderID, + SessionID: req.OrderId, + } + db.Mysql().Get(record) + if record.ID == 0 { + resp.Code = INVALIDREQUESTERR + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + return + } + + var rollbackAmount int64 + + if record.Type == base.SessionTypeBet { + rollbackAmount = record.Amount + } else if record.Type == base.SessionTypeSettle { + rollbackAmount = record.Settle - record.Amount + } + + adjustReq := &base.AdjustmentReq{ + UID: uid, + Amount: rollbackAmount, + GameID: req.GameId, + GameName: configGame.GameCode, + Provider: provider, + BetID: req.OrderId, + SessionID: req.OrderId, + Time: time.Now().Unix(), + Type: base.SessionTypeAdjustment, + Ess: fmt.Sprintf("%s rollback", configGame.Name), + } + adjustResp := base.Adjustment(adjustReq) + if adjustResp.Code != CodeSuccess { + log.Debug("rollback adjustResp code:%d", adjustResp.Code) + resp.Code = INVALIDREQUESTERR + resp.Msg = "operation failed." + return + } + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + resp.Msg = "success" + log.Debug("rollback:%+v", resp) + a.Data = resp +} + +func Update(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.ResponseB() + }() + req := &UpdateReq{} + resp := &UpdateResp{} + a.RetData = resp + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + log.Error("read body err: %v", err) + resp.Code = INVALIDREQUESTERR + return + } + log.Debug("sn update:%s", string(body)) + err = json.Unmarshal(body, &req) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + account := c.GetHeader("account") + headers := make(map[string]string) + for key, values := range c.Request.Header { + if len(values) > 0 { + headers[key] = values[0] // 取第一个值 + } + } + if a.ShouldRouteByAccount(&account, common.ProviderAPITypeJson, req, headers) { + return + } + var tmpValue map[string]interface{} + err = json.Unmarshal(body, &tmpValue) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + tmpSign := GeneratedSign(tmpValue, SignKey) + if tmpSign != req.Sign { + log.Error("sign is wrong, %+v", req) + resp.Code = INVALIDREQUESTERR + return + } + uids := account + uid, err := strconv.Atoi(uids) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + provider := call.GetConfigGameProvider(common.ProviderSn) + + configGame := call.GetGameListByByID(common.ProviderSn, req.GameId) + if configGame == nil { + log.Error("get game config err") + resp.Code = INVALIDREQUESTERR + return + } + + // 订单是否合法 + record := &common.ProviderBetRecord{ + UID: uid, + Provider: provider.ProviderID, + SessionID: req.OrderId, + } + db.Mysql().Get(record) + if record.ID == 0 { + resp.Code = INVALIDREQUESTERR + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + return + } + + updateAmount := int64(req.Amount) + desc := "game update" + + if req.SubTypeId == 80006 || req.SubTypeId == 80007 || req.SubTypeId == 80031 || req.SubTypeId == 101010 { + if updateAmount < 0 { + updateAmount *= -1 + } + } else if req.SubTypeId == 80016 { + + } else { + if updateAmount > 0 { + updateAmount *= -1 + } + } + + switch req.SubTypeId { + case 80005: // 小费 + desc = "game tip" + case 80006: + desc = "game activity" + case 80007: + desc = "game jp" + case 800016: + desc = "game award" + case 80030: + desc = "create room free" + case 80031: + desc = "create room award" + case 101010: + desc = "create room rollback" + } + + adjustReq := &base.AdjustmentReq{ + UID: uid, + Amount: updateAmount, + GameID: req.GameId, + GameName: configGame.GameCode, + Provider: provider, + BetID: req.OrderId, + SessionID: req.OrderId, + Time: time.Now().Unix(), + Type: base.SessionTypeAdjustment, + Ess: desc, + } + adjustResp := base.Adjustment(adjustReq) + if adjustResp.Code != CodeSuccess { + log.Debug("update adjustResp code:%d", adjustResp.Code) + resp.Code = INVALIDREQUESTERR + resp.Msg = "operation failed." + return + } + resp.Data.Chips = int(call.GetUserCurrencyFloat(uid, common.CurrencyType(0), 0) * common.DecimalDigits) + resp.Msg = "success" + log.Debug("rollback:%+v", resp) + a.Data = resp +} + +func GameControlCallback(c *gin.Context) { + a := app.NewApp(c) + defer func() { + a.ResponseB() + }() + req := &GameControlCallbackReq{} + resp := &GameControlCallbackResp{} + a.RetData = resp + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + log.Error("read body err: %v", err) + resp.Code = INVALIDREQUESTERR + return + } + log.Debug("sn gameControlCallback:%s", string(body)) + err = json.Unmarshal(body, &req) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + account := c.GetHeader("account") + headers := make(map[string]string) + for key, values := range c.Request.Header { + if len(values) > 0 { + headers[key] = values[0] // 取第一个值 + } + } + if a.ShouldRouteByAccount(&account, common.ProviderAPITypeJson, req, headers) { + return + } + var tmpValue map[string]interface{} + err = json.Unmarshal(body, &tmpValue) + if err != nil { + log.Error("unmarshal err, %s", err.Error()) + resp.Code = INVALIDREQUESTERR + return + } + tmpSign := GeneratedSign(tmpValue, SignKey) + if tmpSign != req.Sign { + log.Error("sign is wrong, %+v", req) + resp.Code = INVALIDREQUESTERR + return + } + uids := account + uid, err := strconv.Atoi(uids) + if err != nil { + log.Error("err:%v", err) + resp.Code = INVALIDREQUESTERR + return + } + resp.Msg = "success" + log.Debug("gameControlCallback resp:%+v", resp) + a.Data = resp + defer func() { + err = Control(uid, util.ToInt(req.ControlId)) + if err != nil { + log.Error("sn control err, %s", err.Error()) + } + }() +} + +func Control(uid int, controlId int) error { + if controlId == 0 { + controlId = 1 + } + req := &ControlReq{ + BaseReq: BaseReq{ + SnAccount: SnAccount, + Time: time.Now().Unix(), + }, + ThirdName: call.GetProviderUserName(fmt.Sprintf("%d", uid)), + ControlId: controlId, + Sn: SnId, + AgentId: AgentId, + Data: []struct { + TargetRtp int `json:"target_rtp"` + }{ + { + TargetRtp: call.GetProviderGameRtp(uid), + }, + }, + } + + log.Debug("sn control req, %+v", *req) + reqBody, _ := json.Marshal(req) + var tmpValue map[string]interface{} + json.Unmarshal(reqBody, &tmpValue) + req.Sign = GeneratedSign(tmpValue, SignKey) + + var resp ControlResp + err := util.HttpPost(APIControl, req, &resp, nil) + if err != nil { + log.Error("err:%v", err) + return err + } + if resp.Code != CodeRequestSuccess && resp.Code != CodeRequestExist { + log.Error("control err, %+v", resp) + return fmt.Errorf("control err, %+v ", resp) + } + + return nil +} diff --git a/modules/web/providers/sn/values.go b/modules/web/providers/sn/values.go new file mode 100644 index 0000000..6f4d0ce --- /dev/null +++ b/modules/web/providers/sn/values.go @@ -0,0 +1,210 @@ +package sn + +import ( + "crypto/md5" + "encoding/hex" + "encoding/json" + "fmt" + "github.com/liangdas/mqant/log" + "sort" + "strings" +) + +const ( + APIRlease = "https://api.nbetps.com/v2/launch_game" + APITest = "https://api.nbetps.com/v2/launch_game" + + APICreateUserRlease = "https://api.nbetps.com/v1/create_user" + APICreateUserTest = "https://api.nbetps.com/v1/create_user" + + APIControlRlease = "https://api.nbetps.com/v1/control" + APIControlTest = "https://api.nbetps.com/v1/control" + + // LaunchGameURL = "/api/usr/ingame" + // GetGameListURL = "/api/game/loadlist" + // Lang = "hi" +) + +type Agent struct { + MchId string `json:"mch_id"` + Key string `json:"key"` +} + +var ( + API = "" + APICreate = "" + APIControl = "" + AgentMap Agent + AgentMapTest = Agent{ + MchId: "slotgolden777test", + Key: "010804d1-7bbf-4ed5-9b50-60fbd2b22e34", + } + AgentMapRelease = Agent{ + MchId: "slotgolden777", + Key: "ddeaeb76-5624-41fe-a6ea-7ad9307d7701", + } +) + +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] + return signStr +} + +//func GeneratedSign(str string) string { +// signStr := getSignStr(str, "sign") + "&key=" + SignKey +// md5Value := createMd5(signStr) +// md5Value = strings.ToUpper(createMd5(md5Value)) +// log.Debug("sn signStr:%s, md5:%s", signStr, md5Value) +// return md5Value +//} + +func GeneratedSignMap(params map[string]interface{}) string { + keys := make([]string, 0, len(params)) + for k := range params { + if k != "" && k != "sign" && params[k] != nil { + keys = append(keys, k) + } + } + sort.Strings(keys) + var result string + for _, v := range keys { + if result != "" { + result += "&" + } + var value string + switch params[v].(type) { + case float64: + value = fmt.Sprintf("%d", int64(params[v].(float64))) + case int64: + value = fmt.Sprintf("%d", params[v].(int64)) + default: + value = fmt.Sprintf("%v", params[v]) + } + + result += v + "=" + value + } + return result +} + +func GeneratedSign(params map[string]interface{}, key string) string { + keys := make([]string, 0, len(params)) + for k := range params { + if k != "" && k != "sign" && params[k] != nil { + keys = append(keys, k) + } + } + sort.Strings(keys) + var sign string + for _, v := range keys { + var value string + switch params[v].(type) { + case float64: + value = fmt.Sprintf("%d", int64(params[v].(float64))) + case int64: + value = fmt.Sprintf("%d", params[v].(int64)) + case []interface{}, map[string]interface{}: + data, _ := json.Marshal(params[v]) + value = string(data) + default: + log.Debug("params[%s]: type=%T, value=%+v", v, params[v], params[v]) + value = fmt.Sprintf("%v", params[v]) + } + sign += v + "=" + value + "&" + } + sign += "key=" + key + result := strings.ToUpper(createMd5(sign)) + log.Debug("signStr:%v sign:%s\n", sign, result) + + return result +} + +// createMd5 生成md5字符串 +func createMd5(str string) string { + h := md5.New() + h.Write([]byte(str)) + return hex.EncodeToString(h.Sum(nil)) +} + +// var ( +// RtpMap = map[int]int{ +// 97: 11, +// 96: 12, +// 95: 13, +// 93: 14, +// 90: 15, +// 85: 16, +// 80: 17, +// 60: 18, +// 40: 19, +// } +// rtps = []int{97, 96, 95, 93, 90, 85, 80, 60, 40} +// LevelMap = map[int]int{ +// 11: 97, +// 12: 96, +// 13: 95, +// 14: 93, +// 15: 90, +// 16: 85, +// 17: 80, +// 18: 60, +// 19: 40, +// } +// ) + +// func GetLevel(uid int) int { +// rtp := call.GetProviderGameRtp(uid) +// if rtp >= rtps[0] { +// return RtpMap[97] +// } else if rtp <= rtps[len(rtps)-1] { +// return RtpMap[40] +// } +// for i := 1; i < len(rtps); i++ { +// if rtp <= rtps[i-1] && rtp >= rtps[i] { +// return RtpMap[rtps[i]] +// } +// } +// return 15 +// } + +// func GetRtp(uid int) int { +// rtp := call.GetProviderGameRtp(uid) +// if rtp >= rtps[0] { +// return LevelMap[RtpMap[97]] +// } else if rtp <= rtps[len(rtps)-1] { +// return LevelMap[RtpMap[40]] +// } +// for i := 1; i < len(rtps); i++ { +// if rtp <= rtps[i-1] && rtp >= rtps[i] { +// return LevelMap[RtpMap[rtps[i]]] +// } +// } +// return 90 +// }