459 lines
17 KiB
Lua
459 lines
17 KiB
Lua
local skynet = require "skynet"
|
||
local oo = require "Class"
|
||
local gameCmd = require "GameCmd"
|
||
local json =require "json"
|
||
local log = require "Log"
|
||
local sqlUrl = require "SqlUrl"
|
||
local errorInfo = require "ErrorInfo"
|
||
local serverId = tonumber(skynet.getenv "serverId")
|
||
local redisKeyUrl = require "RedisKeyUrl"
|
||
local clusterServer = require "ClusterServer"
|
||
local crypt = require "skynet.crypt"
|
||
local dataType = require "DataType"
|
||
local serverManage = require "ServerManage"
|
||
local mail = require "Mail"
|
||
local personal = require "Personal"
|
||
local sha1 = crypt.sha1
|
||
|
||
local PayServer = oo.class(clusterServer)
|
||
PayServer.apiKey = "407dcc74075cee33f40e76f0ec2f5817"
|
||
|
||
--初始化
|
||
function PayServer:Init()
|
||
--self.orderList = {} --记录订单,防止重复 废除
|
||
|
||
self.diamondOrderList = {} --官网充值 钻石订单
|
||
self.WXOrderList = {} --微信通知
|
||
end
|
||
|
||
--跨天
|
||
function PayServer:OnNewDay()
|
||
|
||
end
|
||
|
||
--1秒Timer
|
||
function PayServer:On1SecTimer()
|
||
|
||
end
|
||
|
||
--5秒Timer
|
||
function PayServer:On5SecTimer()
|
||
--[[废除
|
||
local t1 = skynet.GetTime()
|
||
for k, v in pairs( self.orderList ) do --删除6小时的订单记录
|
||
if t1 >= v + 21600 then
|
||
self.orderList[ k ] = nil
|
||
end
|
||
end
|
||
]]
|
||
end
|
||
|
||
--接收集群数据
|
||
function PayServer:ClusterRecv(...)
|
||
local cmd , c2sData = ...
|
||
local s2cData = {}
|
||
s2cData.code = errorInfo.Suc
|
||
|
||
if self.Center2All_ServerManageCmd == cmd then --中心服集群消息
|
||
skynet.server.serverManage:DoManageCmd( c2sData , s2cData )
|
||
elseif self.Center2All_SyncClusterInfo == cmd then
|
||
self:RecvSyncClusterInfo( c2sData )
|
||
elseif self.Center2All_SyncServerConfig == cmd then --同步服务器配置
|
||
self:RecvSyncServerConfig( c2sData )
|
||
else
|
||
log.warning(string.format("集群服务器 消息接口 %d 不存在", cmd))
|
||
s2cData.code = errorInfo.ErrorCode.NoExistInterface
|
||
end
|
||
|
||
log.info("集群服务器 消息接口", cmd , "返回信息",s2cData.code)
|
||
return s2cData
|
||
end
|
||
|
||
--[[
|
||
[addr]=192.168.50.188,
|
||
[sign]=8513b67c21afc1238adb734771cebdfc43b9c917,
|
||
[paymentMethod]=$%7BpaymentMethod%7D,
|
||
[timestamp]=1566793027,
|
||
[rebate]=$%7BurlEncode%28rebateInfo%29%7D,
|
||
[provider]=$%7Bprovider%7D,
|
||
[currency]=CNY,
|
||
[gameId]=h5_test,
|
||
[price]=60.0,
|
||
[extra]=$%7BurlEncode%28userdata%29%7D,
|
||
[gameAccountId]=12345,
|
||
[gameOrderId]=15667930060415003,
|
||
[cpOrderId]=960198,
|
||
[itemId]=com_1,
|
||
[minPrice]=6000,
|
||
}
|
||
|
||
]]
|
||
--接收HTTP数据
|
||
function PayServer:HttpRecv( c2sData , url , addr )
|
||
local s2cData = {}
|
||
s2cData.state = {}
|
||
|
||
--组装签名参数{post方式可用,目前只有微信游戏圈发货采用}
|
||
local signParam = {}
|
||
if c2sData.bodyStr ~=nil and c2sData.bodyStr ~= "" then
|
||
signParam["_body"]=c2sData.bodyStr:gsub("%s+", "")
|
||
|
||
--删除多余参数{影响签名}
|
||
c2sData.bodyStr = nil
|
||
end
|
||
|
||
if c2sData.getData ~= nil and type(c2sData.getData) == "string" then
|
||
local getData = skynet.server.httpServer:Translate(c2sData.getData)
|
||
if next(getData) then
|
||
|
||
--合并参数
|
||
for key, value in pairs(getData) do
|
||
c2sData[key]=value
|
||
signParam[key]=value
|
||
end
|
||
end
|
||
|
||
--删除多余参数{影响签名}
|
||
c2sData.getData = nil
|
||
end
|
||
|
||
s2cData.state.code = errorInfo.Suc
|
||
c2sData.addr = addr
|
||
|
||
if "AddPayInfo" == url then
|
||
self:AddPayInfo( c2sData , s2cData )
|
||
elseif "AddOfficialPayInfo" == url then
|
||
self:AddOfficialPayInfo( c2sData , s2cData )
|
||
else
|
||
log.info(string.format("Http服务器 消息接口 %s 不存在", url))
|
||
s2cData.code = errorInfo.ErrorCode.NoExistInterface
|
||
end
|
||
log.info("Http服务器 消息接口 ",url ,"返回信息",s2cData.code)
|
||
return s2cData
|
||
end
|
||
|
||
--新增充值信息
|
||
function PayServer:AddPayInfo( c2sData , s2cData )
|
||
local clusterReturn = {}
|
||
--c2sData.extra = skynet.server.common:UrlDecode( c2sData.extra or "" ) --先进行URL解码
|
||
--c2sData.extra = json:decode(c2sData.extra) --把JSON再转成表
|
||
--[[废除
|
||
if self.orderList[ c2sData.cpOrderId ] then
|
||
s2cData.state.code = 1 --重复订单
|
||
return
|
||
else
|
||
self.orderList[ c2sData.cpOrderId ] = skynet.GetTime()
|
||
end
|
||
]]
|
||
|
||
--根据发的数据查找对应的配置
|
||
local cpOrderId = skynet.server.common:Split( c2sData.cpOrderId ,"_" )
|
||
cpOrderId = tonumber(cpOrderId[3])
|
||
local cfgStorePrice = skynet.server.gameConfig.StorePrice
|
||
local cfgCur = nil
|
||
for k, v in pairs(cfgStorePrice) do
|
||
if cpOrderId == v.storePackId then
|
||
cfgCur = v
|
||
break
|
||
end
|
||
end
|
||
|
||
--充值账号
|
||
local account = tostring(c2sData.gameAccountId)
|
||
if not self:CheckPayInfo( c2sData , s2cData , cfgCur , cpOrderId ) then
|
||
return
|
||
else
|
||
s2cData.state.code = 1 --进这里面都能表示成功
|
||
|
||
--充值信息
|
||
local sendData = {}
|
||
sendData.account = account
|
||
sendData.storeId = cfgCur.storePackId
|
||
sendData.count = 1
|
||
|
||
--缓存失败的充值
|
||
local function CacheFailedAccount()
|
||
--将失败数据插入到redis中去
|
||
--[[
|
||
local redisKey = redisKeyUrl.PayServerPayFailedAccountSet
|
||
skynet.server.redis:sadd( redisKey , account )
|
||
|
||
redisKey = string.format( redisKeyUrl.PayServerPayFailedAccountList , account )
|
||
skynet.server.redis:rpush( redisKey , json:encode(sendData) )
|
||
|
||
--通知道其它游戏服
|
||
local tmpData = {}
|
||
tmpData.account = account
|
||
self:SendMsgToGameServer( self.Pay2Game_CacheFailedAccount , tmpData , s2cData )
|
||
log.info(string.format("充值 玩家 %s 充值失败,缓存到充值失败队列中 充值平台id %s", account , cfgCur.storePackId))
|
||
]]
|
||
local userDBInfo = skynet.server.redisCenter:GetRedisDBInfo( account )
|
||
if userDBInfo then
|
||
--将充值失败的数据保存到离线消息中
|
||
local myPartnerId = userDBInfo.PartnerId
|
||
skynet.server.personal:AddOfflineMsg( myPartnerId , dataType.OfflineMsgType_PayFailed , sendData , 45 , 0)
|
||
else
|
||
log.info(string.format("充值 玩家 %s 缓存失败的充值未成功 充值平台id %s", account , cfgCur.storePackId))
|
||
end
|
||
end
|
||
|
||
--获取玩家登陆信息
|
||
local redisKey = string.format( redisKeyUrl.RouteServerLoginInfoHash , account )
|
||
local isExistLogin = skynet.server.redis:exists( redisKey )
|
||
|
||
if isExistLogin then
|
||
|
||
--存在玩家的登录信息
|
||
local gameServerId = tonumber(skynet.server.redis:hget( redisKey , "GameServerID"))
|
||
if not gameServerId or not self.clusterInfo[ gameServerId ] then
|
||
--并没有相关的游戏服
|
||
log.info(string.format("充值 玩家 %s 未找到该游戏服信息", account ))
|
||
CacheFailedAccount()
|
||
else
|
||
log.info(string.format("充值 玩家 %s 开始发放充值 充值平台id %s", account , sendData.storeId))
|
||
local callData = {}
|
||
local isSuc = self:SendMsgToOneGameServer( self.Pay2Game_AddPayInfo , gameServerId , sendData , callData )
|
||
if not isSuc then
|
||
if errorInfo.ErrorCode.NoExistUser == callData.code then
|
||
log.info(string.format("充值 玩家 %s 玩家未在线1", account ))
|
||
CacheFailedAccount()
|
||
else
|
||
log.info(string.format("充值 玩家 %s 可能某个条件限制,发货失败 错误码 %d", account , callData.code))
|
||
s2cData.state.code = errorInfo.ErrorCode.PayInfoStoreLimit
|
||
end
|
||
end
|
||
end
|
||
else
|
||
log.info(string.format("充值 玩家 %s 玩家未在线2", account ))
|
||
CacheFailedAccount()
|
||
end
|
||
|
||
--将充值数据保存到DB
|
||
local sql = string.format(sqlUrl.insertPayRecord , json:encode( c2sData ))
|
||
local insertData = skynet.server.db:Query("game" , sql )
|
||
if 1 ~= insertData.affected_rows then
|
||
log.info(string.format("充值 玩家 %s 插入服务器配置失败 %s", account , sql ))
|
||
end
|
||
end
|
||
end
|
||
|
||
--新增官网充值信息
|
||
function PayServer:AddOfficialPayInfo( c2sData , s2cData )
|
||
|
||
--测试代码注意取消注释
|
||
if self.diamondOrderList[ c2sData.paymentId ] then
|
||
s2cData.state.code = 1 --重复订单
|
||
return
|
||
end
|
||
|
||
--参数
|
||
--local serverId = c2sData.serverId
|
||
local account = tostring(c2sData.gameAccountId)
|
||
|
||
--获取商品列表
|
||
local items = json:decode(skynet.server.common:UrlDecode(c2sData.items))
|
||
|
||
--判断配置是否为空
|
||
if items == nil or next(items) == nil then
|
||
log.debug("官网充值 items is nil")
|
||
s2cData.state.code = 2 --参数错误
|
||
return
|
||
end
|
||
|
||
--根据发的数据查找对应的配置
|
||
local cfgDiamondPrices = skynet.server.gameConfig.DiamondPrice
|
||
local cfgEffective = {}
|
||
for _, v in ipairs(cfgDiamondPrices) do
|
||
for _, item in ipairs(items) do
|
||
if tonumber(item.itemId) == v.diamondPackId then
|
||
table.insert(cfgEffective, v)
|
||
break
|
||
end
|
||
end
|
||
end
|
||
|
||
--检查配置 不准确
|
||
if next(cfgEffective) == nil or #cfgEffective ~= #items then
|
||
s2cData.state.code = 2 --参数错误
|
||
log.info(string.format("官网充值 配置数量不正确 #cfgEffective :%d #items :%d",#cfgEffective , #items))
|
||
return
|
||
end
|
||
|
||
--验证签名
|
||
local sign = self:GenerateSign( c2sData )
|
||
log.info(string.format("充值 玩家 %s 生成的Sign %s 收到的Sign %s", account , sign , c2sData.sign))
|
||
if sign ~= c2sData.sign then
|
||
s2cData.state.code = 2 --发货失败
|
||
log.info(string.format("充值 玩家 %s Sign不一致" , account ))
|
||
return
|
||
end
|
||
|
||
s2cData.state.code = 1 --进这里面都能表示成功
|
||
|
||
--充值信息
|
||
local sendData = {}
|
||
sendData.account = account
|
||
sendData.items = items
|
||
|
||
--缓存失败的充值
|
||
local function OfficialPayFailedAccount()
|
||
|
||
--将失败数据插入到redis中去
|
||
local redisKey = redisKeyUrl.PayServerOfficialPayFailedAccountSet
|
||
skynet.server.redis:sadd( redisKey , account )
|
||
|
||
redisKey = string.format( redisKeyUrl.PayServerOfficialPayFailedAccountList , account )
|
||
skynet.server.redis:rpush( redisKey , json:encode(sendData) )
|
||
|
||
--通知道其它游戏服
|
||
local tmpData = {}
|
||
tmpData.account = account
|
||
self:SendMsgToGameServer( self.Pay2Game_OfficialPayFailedAccount , tmpData , s2cData )
|
||
end
|
||
|
||
local redisKey = string.format( redisKeyUrl.RouteServerLoginInfoHash , account )
|
||
local isExistLogin = skynet.server.redis:exists( redisKey )
|
||
if isExistLogin then
|
||
--存在玩家的登录信息
|
||
local gameServerId = tonumber(skynet.server.redis:hget( redisKey , "GameServerID"))
|
||
if not gameServerId or not self.clusterInfo[ gameServerId ] then
|
||
--并没有相关的游戏服
|
||
log.info(string.format("官网充值 玩家 %s 未找到该游戏服信息", account ))
|
||
OfficialPayFailedAccount()
|
||
else
|
||
local callData = {}
|
||
local isSuc = self:SendMsgToOneGameServer( self.Pay2Game_OfficialAddPayInfo , gameServerId , sendData , callData )
|
||
if not isSuc then
|
||
if errorInfo.ErrorCode.NoExistUser == callData.code then
|
||
log.info(string.format("官网充值 玩家 %s 玩家未在线1", account ))
|
||
OfficialPayFailedAccount()
|
||
else
|
||
log.info(string.format("官网充值 玩家 %s 可能某个条件限制,发货失败 错误码 %d", account , callData.code))
|
||
s2cData.state.code = 2 --发货失败
|
||
end
|
||
end
|
||
end
|
||
else
|
||
log.info(string.format("官网充值 玩家 %s 玩家未在线2", account ))
|
||
OfficialPayFailedAccount()
|
||
end
|
||
|
||
--将充值数据保存到DB
|
||
local sql = string.format(sqlUrl.insertPayRecord , json:encode( c2sData ))
|
||
local insertData = skynet.server.db:Query("game" , sql )
|
||
if 1 ~= insertData.affected_rows then
|
||
log.info(string.format("官网充值 玩家 %s 插入服务器配置失败 %s", account , sql ))
|
||
end
|
||
|
||
self.diamondOrderList[ c2sData.paymentId ] = skynet.GetTime()
|
||
end
|
||
|
||
--对充值信息的合法性检测
|
||
function PayServer:CheckPayInfo( c2sData , s2cData , cfgCur , cpOrderId)
|
||
local account = tostring(c2sData.gameAccountId)
|
||
|
||
local minPrice = c2sData.minPrice
|
||
local buyPrice = cfgCur.price
|
||
if not cfgCur then
|
||
s2cData.state.code = errorInfo.ErrorCode.PayInfoNoCfg
|
||
log.info(string.format("充值 玩家 %s 不存在充值礼包 %s 配置" , account , cpOrderId))
|
||
return false
|
||
elseif minPrice ~= buyPrice then
|
||
s2cData.state.code = errorInfo.ErrorCode.PayInfoPriceUnlike
|
||
log.info(string.format("充值 玩家 %s 礼包 %d 价格不一致配置 %d %d" , account , cfgCur.storePackId , buyPrice , minPrice))
|
||
return false
|
||
else
|
||
local sign = self:GenerateSign( c2sData )
|
||
log.info(string.format("充值 玩家 %s 生成的Sign %s 收到的Sign %s", account , sign , c2sData.sign))
|
||
|
||
if sign ~= c2sData.sign then
|
||
s2cData.state.code = errorInfo.ErrorCode.PayInfoSignUnlike
|
||
log.info(string.format("充值 玩家 %s Sign不一致" , account ))
|
||
return false
|
||
end
|
||
|
||
return true
|
||
end
|
||
end
|
||
|
||
--生成签名
|
||
function PayServer:GenerateSign( c2sData )
|
||
local param = ""
|
||
local allData = {}
|
||
for k, v in pairs( c2sData ) do
|
||
table.insert( allData , { key = k , value = v })
|
||
end
|
||
|
||
--对参数进行一个升序
|
||
table.sort( allData , function(a,b)
|
||
return a.key < b.key
|
||
end)
|
||
|
||
for k, v in pairs( allData ) do
|
||
if "sign" ~= v.key and "addr" ~= v.key then
|
||
log.debug("签名参数:",v.key,"值:",v.value)
|
||
local tmpText = ""
|
||
if "table" == type(v.value) then
|
||
--如果是表需要进行转JSON,URL编码
|
||
tmpText = json:encode(v.value)
|
||
tmpText = skynet.server.common:UrlEncode(tmpText)
|
||
elseif "extra" == v.key and not skynet.server.common:IsUrlEncode( v.value ) then --extra如果未url编码就进行一次编码
|
||
tmpText = skynet.server.common:UrlEncode( v.value )
|
||
else
|
||
tmpText = v.value
|
||
end
|
||
local tmp = v.key.."="..tmpText
|
||
if "" == param then
|
||
param = param .. tmp
|
||
else
|
||
param = param .. "&"
|
||
param = param .. tmp
|
||
end
|
||
end
|
||
end
|
||
|
||
param = param..(skynet.server.gameConfig.BasicConfig.payApiKey or self.apiKey)
|
||
--param = "cpOrderId=960198¤cy=CNY&gameAccountId=12345&gameId=h5_test&gameOrderId=15667930060415003&itemId=com_1&minPrice=6000&paymentMethod=${paymentMethod}&price=60.0&provider=${provider}&rebate=${urlEncode(rebateInfo)}×tamp=1566793027407dcc74075cee33f40e76f0ec2f5817"
|
||
local sign = string.lower(skynet.server.common:HexToStr(sha1(param)))
|
||
log.debug("加密前生成的参数组合:",param)
|
||
log.debug("加密后的数据:",sign)
|
||
return sign
|
||
end
|
||
|
||
--发送消息到GS
|
||
function PayServer:SendMsgToGameServer( cmd , c2sData , s2cData)
|
||
for k, v in pairs(self.clusterInfo) do
|
||
if self:IsGameServer( v.serverId ) and v.status == self.Status_Running or v.status == self.Status_Stop then
|
||
self:SendMsgToServer(v.serverId , cmd , c2sData )
|
||
end
|
||
end
|
||
end
|
||
|
||
--发送消息到GS
|
||
function PayServer:SendMsgToOneGameServer( cmd , gameServerId , sendData , callData )
|
||
local clusterReturn = {}
|
||
local account = tostring(sendData.account)
|
||
|
||
for k, v in pairs(self.clusterInfo) do
|
||
if gameServerId == v.serverId and self:IsGameServer( v.serverId ) then
|
||
|
||
log.info(string.format("充值 玩家 %s 充值服向游戏服 %d 发送消息 %d 开始" , account , v.serverId , cmd ))
|
||
clusterReturn = self:CallMsgToServer( v.serverId , cmd , sendData )
|
||
|
||
if clusterReturn and errorInfo.Suc == clusterReturn.code then
|
||
log.info(string.format("充值 玩家 %s 充值服向游戏服 %d 发送消息 %d 成功" , account , v.serverId , cmd ))
|
||
callData.code = clusterReturn.code
|
||
return true
|
||
else
|
||
log.info(string.format("充值 玩家 %s 充值服向游戏服 %d 发送消息 %d 失败" , account , v.serverId , cmd ))
|
||
callData.code = clusterReturn.code
|
||
return false
|
||
end
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
skynet.server.payServer = PayServer
|
||
return PayServer
|