HomeServer/Server/AllServer/PayServer/PayServer.lua
2024-11-20 15:41:37 +08:00

459 lines
17 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
--如果是表需要进行转JSONURL编码
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&currency=CNY&gameAccountId=12345&gameId=h5_test&gameOrderId=15667930060415003&itemId=com_1&minPrice=6000&paymentMethod=${paymentMethod}&price=60.0&provider=${provider}&rebate=${urlEncode(rebateInfo)}&timestamp=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