package ingame import ( "encoding/json" "f5" "main/constant" "main/model" "main/service" "q5" "strings" "github.com/gin-gonic/gin" ) type InGameApi struct { } func (iga *InGameApi) PreOrder(c *gin.Context) { reqJson := struct { AccountId string `json:"account_id" binding:"required"` SessionId string `json:"session_id" binding:"required"` GoodsId int32 `json:"goods_id" binding:"required"` }{} if err := c.ShouldBindJSON(&reqJson); err != nil { f5.RspErr(c, 401, "params error") return } data := map[string]interface{}{} if !iga.isNopayChannel(reqJson.AccountId) { ret := true data, ret = iga.checkSessionData(c, reqJson.AccountId) if !ret { return } } nowTime := int32(f5.GetApp().GetRealSeconds()) order := new(model.InAppOrder) order.AccountId = reqJson.AccountId order.OrderId = q5.ToString(f5.GetApp().NewLockNodeUuid()) order.ItemId = reqJson.GoodsId order.GameId = q5.SafeToInt32(data["gameid"]) order.IP = iga.getIP(c) order.CreateTime = nowTime order.ModifyTime = nowTime if err := order.Create(); err != nil { f5.RspErr(c, 500, "server internal error") return } rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` }{ OrderId: order.OrderId, } c.JSON(200, rspObj) } func (iga *InGameApi) ServerPreOrder(c *gin.Context) { accountId := c.Query("account_id") goodsid := c.Query("goods_id") sessionid := c.Query("session_id") sign := c.Query("sign") if !strings.EqualFold(q5.Md5Str(accountId+goodsid+constant.GLOBAL_SALT+sessionid), strings.ToLower(sign)) { f5.RspErr(c, 401, "sign err") return } data, ret := iga.checkSessionData(c, accountId) if !ret { return } nowTime := int32(f5.GetApp().GetRealSeconds()) order := new(model.InAppOrder) order.AccountId = accountId order.OrderId = q5.ToString(f5.GetApp().NewLockNodeUuid()) order.ItemId = q5.SafeToInt32(goodsid) order.GameId = q5.SafeToInt32(data["gameid"]) order.IP = c.Query("user_ip") order.CreateTime = nowTime order.ModifyTime = nowTime if err := order.Create(); err != nil { f5.RspErr(c, 500, "server internal error") return } rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` }{ 0, "", order.OrderId, } c.JSON(200, rspObj) } func (iga *InGameApi) PayDone(c *gin.Context) { accountId := c.Query("account_id") orderid := c.Query("order_id") sessionid := c.Query("session_id") sign := c.Query("sign") if !strings.EqualFold(q5.Md5Str(accountId+orderid+constant.GLOBAL_SALT+sessionid), strings.ToLower(sign)) { f5.RspErr(c, 401, "sign err") return } orderModel := new(model.InAppOrder) if err, found := orderModel.Find(accountId, orderid); err != nil { f5.RspErr(c, 500, "server internal error") return } else if !found { f5.RspErr(c, 1, "order not found") return } data, ret := iga.checkSessionData(c, accountId) if !ret { return } sessionkey := q5.SafeToString(data["session_key"]) status := orderModel.Status rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` Diamond int64 `json:"diamond"` }{ OrderId: orderid, } if status < 2 { gameid := q5.SafeToInt64(data["gameid"]) openid := q5.SafeToString(data["openid"]) userip := iga.getIP(c) balance, errcode, err := int64(0), int32(0), error(nil) if status == 0 { balance, errcode, err = service.Wxpay.QueryBalance(openid, gameid, userip, sessionkey) if err != nil { f5.RspErr(c, 500, "system busy") return } } else { balance = int64(orderModel.SpAmount) } if errcode == constant.WX_ERRCODE_OK && balance > 0 { errcode = service.Wxpay.QueryPay(openid, gameid, userip, sessionkey, int32(balance), orderModel.OrderId) if errcode == constant.WX_ERRCODE_OK { status = 1 orderModel.Status = 2 orderModel.UpdateFields([]string{"status"}) rspObj.Diamond = balance } } if errcode == constant.WX_ERRCODE_SESSIONERR || errcode == constant.WX_ERRCODE_SIGERR { rspObj.ErrorCode = 402 rspObj.ErrMsg = "session overtime" } } c.JSON(200, rspObj) } func (iga *InGameApi) ServerPrePurchase(c *gin.Context) { req := struct { AccountId string `binding:"required" json:"account_id"` SessionId string `binding:"required" json:"session_id"` UserIp string `binding:"required" json:"user_ip"` Sign string `binding:"required" json:"sign"` SigData string `binding:"required" json:"sig_data"` }{} if err := c.ShouldBindJSON(&req); err != nil { f5.RspErr(c, 401, "post content error") return } if !strings.EqualFold(q5.Md5Str(req.AccountId+constant.GLOBAL_SALT+req.SessionId), req.Sign) { f5.RspErr(c, 401, "sign err") return } sigdata := map[string]interface{}{} if json.Unmarshal([]byte(req.SigData), &sigdata) != nil { f5.RspErr(c, 401, "sigdata err") return } goodsid := q5.SafeToInt32(sigdata["productId"]) if goodsid == 0 { f5.RspErr(c, 401, "sigdata productid err") return } data, ret := iga.checkSessionData(c, req.AccountId) if !ret { return } sessionkey := q5.SafeToString(data["session_key"]) gameid := q5.SafeToInt64(data["gameid"]) nowTime := int32(f5.GetApp().GetRealSeconds()) order := new(model.InAppOrder) order.AccountId = req.AccountId order.OrderId = "p" + q5.ToString(f5.GetApp().NewLockNodeUuid()) order.GameId = int32(gameid) order.ItemId = goodsid order.IP = req.UserIp order.CreateTime = nowTime order.ModifyTime = nowTime sigdata["outTradeNo"] = order.OrderId sigdatabyte, _ := json.Marshal(sigdata) fullsigdata := string(sigdatabyte) paysig, signature := service.Wxpay.GetPurchaseSig(gameid, fullsigdata, sessionkey) if len(paysig) == 0 || len(signature) == 0 { f5.RspErr(c, 403, "account error") return } if err := order.Create(); err != nil { f5.RspErr(c, 500, "server internal error") return } rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` PaySig string `json:"pay_sig"` Signature string `json:"signature"` SigData string `json:"sig_data"` }{ 0, "", order.OrderId, paysig, signature, fullsigdata, } c.JSON(200, rspObj) } func (iga *InGameApi) OrderInfo(c *gin.Context) { reqJson := struct { AccountId string `json:"account_id" binding:"required"` SessionId string `json:"session_id" binding:"required"` OrderId string `json:"order_id" binding:"required"` }{} if err := c.ShouldBindJSON(&reqJson); err != nil { f5.RspErr(c, 401, "params error") return } if !iga.isNopayChannel(reqJson.AccountId) { rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` GoodsId int32 `json:"goods_id"` Count int32 `json:"count"` Others int32 `json:"others"` Status int32 `json:"status"` }{ OrderId: reqJson.OrderId, Status: 1, } c.JSON(200, rspObj) return } data, ret := iga.checkSessionData(c, reqJson.AccountId) if !ret { return } orderModel := new(model.InAppOrder) if err, found := orderModel.Find(reqJson.AccountId, reqJson.OrderId); err != nil { f5.RspErr(c, 500, "server internal error") return } else if !found { f5.RspErr(c, 1, "not found") return } rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` GoodsId int32 `json:"goods_id"` Count int32 `json:"count"` Others int32 `json:"others"` Status int32 `json:"status"` }{ OrderId: orderModel.OrderId, GoodsId: orderModel.ItemId, Count: orderModel.SpAmount, Others: orderModel.SpOthers, Status: orderModel.Status, } c.JSON(200, rspObj) if orderModel.Status == 0 { gameid := q5.SafeToInt64(data["gameid"]) openid := q5.SafeToString(data["openid"]) userip := iga.getIP(c) sessionkey := q5.SafeToString(data["session_key"]) balance, errcode, err := service.Wxpay.QueryBalance(openid, gameid, userip, sessionkey) if err != nil { return } if errcode == constant.WX_ERRCODE_OK { count, err := service.Wxpay.GetGoodsCount(gameid, int64(orderModel.ItemId)) if err != nil { return } if balance >= count { errcode = service.Wxpay.QueryPay(openid, gameid, userip, sessionkey, int32(balance), orderModel.OrderId) if errcode == constant.WX_ERRCODE_OK { orderModel.Status = 1 orderModel.SpAmount = int32(count) orderModel.SpOthers = int32(balance - count) orderModel.UpdateFields([]string{"status", "sp_amount", "sp_others"}) } } } if errcode == constant.WX_ERRCODE_SESSIONERR || errcode == constant.WX_ERRCODE_SIGERR { sessionkeytime := q5.SafeToInt64(data["update_time"]) service.Wxpay.AddExpireInfo(reqJson.AccountId, sessionkeytime) } } else if orderModel.Status == 1 { orderModel.Status = 2 orderModel.UpdateFields([]string{"status"}) } } func (iga *InGameApi) OtherOrder(c *gin.Context) { reqJson := struct { AccountId string `json:"account_id" binding:"required"` SessionId string `json:"session_id" binding:"required"` }{} if err := c.ShouldBindJSON(&reqJson); err != nil { f5.RspErr(c, 401, "params error") return } data, ret := iga.checkSessionData(c, reqJson.AccountId) if !ret { return } sessionkey := q5.SafeToString(data["session_key"]) sessionkeytime := q5.SafeToInt64(data["update_time"]) rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` Count int64 `json:"count"` }{} gameid := q5.SafeToInt64(data["gameid"]) openid := q5.SafeToString(data["openid"]) userip := iga.getIP(c) balance, errcode, err := service.Wxpay.QueryBalance(openid, gameid, userip, sessionkey) if err != nil { f5.RspErr(c, 500, "wx server busy") return } if errcode == constant.WX_ERRCODE_OK && balance > 0 { nowTime := int32(f5.GetApp().GetRealSeconds()) order := new(model.InAppOrder) order.AccountId = reqJson.AccountId order.OrderId = "o" + q5.ToString(f5.GetApp().NewLockNodeUuid()) errcode = service.Wxpay.QueryPay(openid, gameid, userip, sessionkey, int32(balance), order.OrderId) if errcode == constant.WX_ERRCODE_OK { order.GameId = int32(gameid) order.Channel = q5.SafeToInt32(data["channel"]) order.IP = iga.getIP(c) order.Status = 2 order.SpOthers = int32(balance) order.CreateTime = nowTime order.ModifyTime = nowTime if err := order.Create(); err != nil { f5.GetSysLog().Error("record other order error:%s, %s, %d", reqJson.AccountId, order.OrderId, balance) } rspObj.Count = balance } } else if errcode == constant.WX_ERRCODE_SESSIONERR || errcode == constant.WX_ERRCODE_SIGERR { service.Wxpay.AddExpireInfo(reqJson.AccountId, sessionkeytime) rspObj.ErrorCode = 402 rspObj.ErrMsg = "invalid session 2" } if errcode == constant.WX_ERRCODE_OK { rspObj.Count += model.FindOtherCount(reqJson.AccountId) } c.JSON(200, rspObj) } func (iga *InGameApi) QueryPay(c *gin.Context) { reqJson := struct { AccountId string `json:"account_id" binding:"required"` SessionId string `json:"session_id" binding:"required"` OrderId string `json:"order_id" binding:"required"` }{} if err := c.ShouldBindJSON(&reqJson); err != nil { f5.RspErr(c, 401, "params error") return } _, ret := iga.checkSessionData(c, reqJson.AccountId) if !ret { return } orderModel := new(model.InAppOrder) if err, found := orderModel.Find(reqJson.AccountId, reqJson.OrderId); err != nil { f5.RspErr(c, 500, "server internal error") return } else if !found { f5.RspErr(c, 1, "not found") return } rspObj := struct { ErrorCode int32 `json:"errcode"` ErrMsg string `json:"errmsg"` OrderId string `json:"order_id"` GoodsId int32 `json:"goods_id"` Count int32 `json:"count"` Others int32 `json:"others"` Status int32 `json:"status"` }{ OrderId: orderModel.OrderId, GoodsId: orderModel.ItemId, Count: orderModel.SpAmount, Others: orderModel.SpOthers, Status: orderModel.Status, } c.JSON(200, rspObj) if orderModel.Status == 1 { orderModel.Status = 2 orderModel.UpdateFields([]string{"status"}) } } func (iga *InGameApi) checkSessionData(c *gin.Context, accountId string) (data map[string]interface{}, ret bool) { strs := strings.Split(accountId, "_") if len(strs) < 3 { f5.RspErr(c, 401, "params error1") return } rediskey := "ls:accountid:" + accountId str, err := service.Redis.Get(constant.LOGIN_REDIS, rediskey) if err != nil { f5.RspErr(c, 402, "invalid session") return } data = map[string]interface{}{} if json.Unmarshal([]byte(str), &data) != nil { f5.RspErr(c, 402, "invalid session 1") return } sessionkey := q5.SafeToString(data["session_key"]) if len(sessionkey) == 0 { f5.GetSysLog().Debug("empty sessionkey:%s", accountId) f5.RspErr(c, 402, "invalid session 2") return } sessionkeytime := q5.SafeToInt64(data["update_time"]) if service.Wxpay.CheckExpireCache(accountId, sessionkeytime) { f5.RspErr(c, 402, "session expired") return } data["channel"] = strs[0] data["gameid"] = strs[1] return data, true } func (iga *InGameApi) getIP(c *gin.Context) (ip string) { ip = c.Request.Header.Get("X-Real-Ip") if ip == "" { ip = strings.Split(c.Request.Header.Get("X-Forwarded-For"), ",")[0] } if ip == "" { ip = c.Request.RemoteAddr } return ip } func (iga *InGameApi) isNopayChannel(accountId string) (ret bool) { strs := strings.Split(accountId, "_") if len(strs) < 2 { return } return strs[0] == "6000" }