local skynet = require "skynet" local mysql = require "skynet.db.mysql" local oo = require "Class" local cmd = require "GameCmd" local errorInfo = require "ErrorInfo" local pb = require "pb" local log = require "Log" local serverId = tonumber(skynet.getenv "serverId") local ClusterServer = oo.class() --中心服简称C 主服简称M 登陆服L 游戏服G ClusterServer.centerServerID = 0 --中心服 ClusterServer.routerServerMinID = 1 --路由服 1-5 ClusterServer.routerServerMaxID = 5 --路由服 1-5 ClusterServer.monitorServerID = 6 --监控服和防黑功能 ClusterServer.multiServerID = 7 --多功能服 ClusterServer.rankServerID = 8 --榜单服 ClusterServer.payServerID = 9 --充值服 ClusterServer.gameServerMinID = 100 --游戏服开始 ClusterServer.gameServerMaxID = 199 --游戏服结束 --通用消息 ClusterServer.All_Start = 1000 ClusterServer.All_Reg = 1001 --注册 ClusterServer.All_UnReg = 1002 --注销 ClusterServer.All_Ping = 1003 --Ping ClusterServer.All_SyncServerInfoToCenter = 1004 --同步服务器信息到中心服 ClusterServer.All_ErrorInfo = 1005 --错误信息 ClusterServer.All_End = 1999 --中心服消息 ClusterServer.CenterServer_Start = 1100 ClusterServer.Center2All_ServerManageCmd = 1101 --发送管理命令 ClusterServer.Center2All_SyncClusterInfo = 1102 --同步集群服信息 ClusterServer.Center2All_SyncServerConfig = 1103 --同步服务器配置 ClusterServer.Center2All_WebMsg = 1104 --后台数据 ClusterServer.CenterServer_End = 1199 --路由服消息 ClusterServer.RouteServer_Start = 1200 ClusterServer.Route2Monitor_VerifyValid = 1201 --验证该连接是否有效 ClusterServer.Route2Game_QueryUserOnline = 1202 --查询用户是否在线 ClusterServer.Route2Game_UserLoginToken = 1203 --发送登陆Token ClusterServer.RouteServer_End = 1299 --监控服消息 ClusterServer.MoniterServer_Start = 1300 ClusterServer.All2Moniter_AddAccountToBlack = 1301 --添加账号到黑名单 ClusterServer.All2Moniter_AddIPToBlack = 1302 --添加IP到黑名单 ClusterServer.MoniterServer_End = 1399 --多功能服消息 ClusterServer.MultiServer_Start = 1400 ClusterServer.MultiServer_End = 1499 --榜单服消息 ClusterServer.RankServer_Start = 1500 ClusterServer.RankServer_End = 1599 --充值服消息 ClusterServer.PayServer_Start = 1600 ClusterServer.Pay2Game_AddPayInfo = 1601 --新增充值信息 ClusterServer.PayServer_End = 1699 --游戏服消息 ClusterServer.GameServer_Start = 2000 ---------------------------------------------------------------------------------------------------------------游戏服发往帐号服消息----------------------------------------- ClusterServer.GameToMonitor_UpdateUserStatus = 2001 --修改玩家状态 1-正常玩家 2-白名单 3-灰名单 4-黑名单 ClusterServer.GameToMulti_GetRedeemBonus = 2100 --获取兑换码奖励 ClusterServer.GameToMulti_GetMailList = 2101 --获取邮件列表 ClusterServer.GameToMulti_GetMailBonus = 2102 --获取邮件奖励 ClusterServer.GameToRank_UpdateScore = 3100 --更新玩家的分数 ClusterServer.GameToRank_GetRankData = 3101 --获取排行榜数据 ClusterServer.GameServer_End = 3999 ClusterServer.Status_Running = 1 --服务器运行 ClusterServer.Status_PingTimeout = 2 --PING超时 ClusterServer.Status_Stop = 3 --服务器停止 function ClusterServer:Init() self.clusterInfo = {} --集群服所有服务器的信息 self.serverInfo = {} --当前服务器的信息 self.platformInfo = {} --平台信息 self.allServerConfig = {} --所有服务器配置 self.curClusterConfig = {} --当前集群配置 self.curServerConfig = {} --当前服务器配置 self.serverName = self:GetServerTypeName( serverId ) --服务器名称 self.isConnectCenter = false --是否连接中心服 self.lastSendPingTime = skynet.GetTime() self.lastSyncServerInfoTime = skynet.GetTime() self.isConnectCenterServer = false --是否连接中心服务器 self.isForceDisconnectCenter =false --是否强制断开中心服务器的连接 self.isTodayDeleteLog = false --今日是否删除日志 self.isTodayDeleteDB = false --今日是否删除数据库无用的记录 end --跨天 function ClusterServer:OnNewDay() self.isTodayDeleteLog = false self.isTodayDeleteDB = false end --1秒Timer function ClusterServer:On1SecTimer() end --5秒Timer function ClusterServer:On5SecTimer() function Do() --删除日志文件 self:DeleteLogFile() if self:IsCenterServer( serverId ) then return end --连接断开 或者 未强制断开可以注册 if not self.isConnectCenterServer and not self.isForceDisconnectCenter then --注册服务器 self:Reg() else --向中心服发送ping消息 if skynet.GetTime() - self.lastSendPingTime >= self.curClusterConfig.ClusterSlaveSendPingTime then self:Ping() end --向中心服同步服务器信息 if skynet.GetTime() - self.lastSyncServerInfoTime >= self.curClusterConfig.SyncServerInfoTime then self:SyncServerInfoToCenter() end end end local isSuc,err = pcall(Do) if not isSuc then self.isConnectCenterServer = false log.info("与上级服务器断开连接,准备重新注册",err) end end --接收集群服的消息 function ClusterServer:ClusterRecv( ... ) local cmd , clusterMsg = ... local s2sData = {} s2sData.code = errorInfo.Suc s2sData.data = {} if 0 == serverId and clusterMsg.serverId == serverId then --主服不接收主服发来的消息 return s2sData end if not cmd or not clusterMsg then s2sData.code = errorInfo.ErrorCode.ErrRequestParam return s2sData end local serverName = self:GetServerTypeName( serverId ) serverName = serverName:gsub("^%u",string.lower) --将首字母从大写变成小写 s2sData = skynet.server[ serverName ]:ClusterRecv(...) s2sData.desc = errorInfo.ErrorMsg[ s2sData.code ] or "暂无消息提示" return s2sData end --向主服务器注册 function ClusterServer:Reg() local s2sData = {} local cfgCluster = skynet.server.common:GetClusterConfig( serverId ) if not cfgCluster then s2sData.code = -1 return s2sData end local clusterMsg = {} clusterMsg.serverId = serverId clusterMsg.serverName = self.serverName.."_"..serverId local clusterName = self:GetServerTypeClusterName( serverId ) local s2sData = self:CallMsgToCenterServer( self.All_Reg , clusterMsg) if errorInfo.Suc == s2sData.code then self.isConnectCenterServer = true self.isForceDisconnectCenter = false --同步服务器信息到中心服 self:SyncServerInfoToCenter() log.info(string.format("集群服务器 %s 向中心服注册成功", clusterName)) else log.info(string.format("集群服务器 %s 向中心服注册失败", clusterName)) end end --向主服务器注销 function ClusterServer:UnReg() local s2sData = {} local cfgCluster = skynet.server.common:GetClusterConfig( serverId ) if not cfgCluster then s2sData.code = -1 return s2sData end local clusterMsg = {} clusterMsg.serverId = serverId clusterMsg.serverName = self.serverName.."_"..serverId local clusterName = self:GetServerTypeClusterName( serverId ) local s2sData = self:CallMsgToCenterServer( self.All_UnReg , clusterMsg) if errorInfo.Suc == s2sData.code then self.isConnectCenterServer = false self.isForceDisconnectCenter = true self:SyncServerInfoToCenter() log.info(string.format("集群服务器 %s 向中心服注销成功", clusterName)) else log.info(string.format("集群服务器 %s 向中心服注销失败", clusterName)) end end --向主服务器发心跳包 function ClusterServer:Ping() self.lastSendPingTime = skynet.GetTime() local clusterMsg = {} clusterMsg.serverId = serverId local clusterName = self:GetServerTypeClusterName( serverId ) local s2sData,srcServerName,dstServerName = self:CallMsgToCenterServer( self.All_Ping , clusterMsg) if errorInfo.Suc ~= s2sData.code then log.info(string.format("集群服务器 %s 向中心服Ping失败", clusterName)) end end --同步服务器信息 function ClusterServer:SyncServerInfoToCenter() self.lastSyncServerInfoTime = skynet.GetTime() local c2sData = {} c2sData.serverId = serverId c2sData.serverInfo = self.serverInfo self:SendMsgToCenterServer( self.All_SyncServerInfoToCenter , c2sData) end --错误信息发送到中心服 function ClusterServer:SendErrorInfoToCenter( errorCode , errorText ) local c2sData = {} c2sData.serverId = serverId c2sData.errorCode = errorCode c2sData.errorText = errorText self:SendMsgToCenterServer( self.All_ErrorInfo , c2sData) end function ClusterServer:GetServerName() return self.serverName end --是否为中心服务器 function ClusterServer:IsCenterServer( serverId ) if self.centerServerID == tonumber(serverId) then return true else return false end end --是否为路由服务器 function ClusterServer:IsRouteServer( serverId ) if tonumber(serverId) >= self.routerServerMinID and tonumber(serverId) <= self.routerServerMaxID then return true else return false end end --是否为监视服务器 function ClusterServer:IsMonitorServer( serverId ) if self.monitorServerID == tonumber(serverId) then return true else return false end end --是否为多功能服务器 function ClusterServer:IsMultiServer( serverId ) if self.multiServerID == tonumber(serverId) then return true else return false end end --是否为排行榜服务器 function ClusterServer:IsRankServer( serverId ) if self.rankServerID == tonumber(serverId) then return true else return false end end --是否为多功能服务器 function ClusterServer:IsPayServer( serverId ) if self.payServerID == tonumber(serverId) then return true else return false end end --是否为游戏服务器 function ClusterServer:IsGameServer( serverId ) if tonumber(serverId) >= self.gameServerMinID and tonumber(serverId) <= self.gameServerMaxID then return true else return false end end --根据服务器ID获取类型名称 function ClusterServer:GetServerTypeName( serverId ) serverId = tonumber(serverId) for k, v in pairs(skynet.server.gameConfig.ClusterServerConfig) do if serverId == v.serverId then return v.serverName end end log.info("获取集群配置出错",serverId ) return "" end --根据服务器ID获取类型集群名称 function ClusterServer:GetServerTypeClusterName( serverId ) local serverName = self:GetServerTypeName(serverId) return serverName.."_"..serverId end --接收同步集群信息 function ClusterServer:RecvSyncClusterInfo( c2sData ) --这类接收操作必须要按下面方式赋值,否则基类的地址会改变,导致基类无法调用 self.clusterInfo = {} for k, v in pairs( c2sData.clusterInfo ) do self.clusterInfo[ k ] = v end end --接收同步服务器配置 function ClusterServer:RecvSyncServerConfig( c2sData ) --这类接收操作必须要按下面方式赋值,否则基类的地址会改变,导致基类无法调用 for k, v in pairs( c2sData.allServerConfig[ "ClusterServer" ] ) do self.curClusterConfig[ k ] = v end --这类接收操作必须要按下面方式赋值,否则基类的地址会改变,导致基类无法调用 if c2sData.allServerConfig[ skynet.ServerName ] then for k, v in pairs( c2sData.allServerConfig[ skynet.ServerName ] ) do self.curServerConfig[ k ] = v end end log.info("接收同步服务器配置") end --重新注册最新的节点 function ClusterServer:ReloadClusterNode() skynet.server.gameConfig:LoadConfig() skynet.server.gameConfig:LoadJson() log.info("成功载入集群信息 ") local clusterList = {} local serverName = "" for k, v in pairs(skynet.server.gameConfig.ClusterServerConfig) do serverName = self:GetServerTypeClusterName( v.serverId ) clusterList[ serverName ] = string.format("%s:%s",v.internalIp ,v.clusterPort) end skynet.server.cluster.reload(clusterList) log.info("成功载入集群信息 ",skynet.server.common:TableToString(clusterList)) end --根据登陆和游戏服的ID获取网关服务器ID function ClusterServer:GetGameServerID( serverId ) serverId = tonumber(serverId) local gameServerId = nil if serverId >= self.loginServerMinID and serverId <= self.loginServerMaxID then gameServerId = math.floor((serverId % 100) / 2) gameServerId = gameServerId + self.gameServerMinID elseif serverId >= self.gameServerMinID and serverId <= self.gameServerMaxID then gameServerId = math.floor((serverId % 100) / 10) gameServerId = gameServerId + self.gameServerMinID end return gameServerId end --发向中心服 function ClusterServer:SendMsgToCenterServer( cmd , msg ) local centerName = "CenterServer_0" skynet.server.cluster.send(centerName,"@"..centerName, "ClusterMsg", cmd , msg or {} ) end --调用中心服 function ClusterServer:CallMsgToCenterServer( cmd , msg ) local centerName = "CenterServer_0" return skynet.server.cluster.call(centerName,"@"..centerName, "ClusterMsg", cmd , msg or {}) end --发向指定服务器 function ClusterServer:SendMsgToServer( serverId , cmd , msg ) if self.clusterInfo[ serverId ] then local serverName = self:GetServerTypeClusterName( serverId ) skynet.server.cluster.send(serverName,"@"..serverName, "ClusterMsg", cmd , msg or {}) return true else return false end end --调用指定服务器 function ClusterServer:CallMsgToServer( serverId , cmd , msg ) local isDo,s2cData = false,nil function Do( serverId , cmd , msg ) local serverName = self:GetServerTypeClusterName( serverId ) return skynet.server.cluster.call(serverName,"@"..serverName, "ClusterMsg", cmd , msg or {} ) end if self.clusterInfo[ serverId ] then isDo,s2cData = pcall( Do , serverId , cmd , msg ) if isDo then return s2cData else return nil end else return nil end end --删除过期日志文件 function ClusterServer:DeleteLogFile() function Do() local nowTime = skynet.GetTime() --凌晨3点删除3天前的日志 if 3 == os.date("*t", nowTime).hour and not self.isTodayDeleteLog then self.isTodayDeleteLog = true log.info("开始删除文件夹") local nowTime = skynet.GetTime() local delTime=os.time({year=os.date("*t", nowTime).year, month=os.date("*t", nowTime).month, day=os.date("*t", nowTime).day - self.curClusterConfig.DeleteLogDayNum}) local path = string.format("rm -rf log/Server_%d/%d-%d-%d-%d",serverId,serverId,os.date("*t", delTime).year ,os.date("*t", delTime).month,os.date("*t", delTime).day) os.execute(path) log.info("删除文件"..path) log.info("结束删除文件夹") end --主服才执行 if 4 == os.date("*t", nowTime).hour and not self.isTodayDeleteDB then self.isTodayDeleteDB = true end end local isSuc,err = pcall(Do) if not isSuc then log.info("删除过期文件内部错误 DeleteLogFile",err) end end skynet.server.clusterServer= ClusterServer return ClusterServer