/* Sog 游戏基础库 2016 by zouwei */ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Sog; using Sog.Gate; using ProtoCSStruct; namespace Version { public class VersionMsgHandler { private ServerApp m_app; private VersionSvc m_versionSvc; public VersionMsgHandler(ServerApp app) { m_app = app; m_versionSvc = new VersionSvc(app); } public VersionSvc GetVersionSvcObj() { return m_versionSvc; } public ServerApp GetApp() { return m_app; } public void Dispose() { m_app = null; m_versionSvc.Dispose(); m_versionSvc = null; } public void HandlerMessage(uint remoteAppID, MessageData message) { int iServerType = ServerIDUtils.GetServerType(remoteAppID); if (iServerType == (int)ServerType.VersionGate) { TraceLog.Trace("VersionMsgHandler.HandlerMessage recv msg from gate length {0}", message.Header.Length); HandlerGateMessage(remoteAppID, message); return; } else { TraceLog.Trace("VersionMsgHandler.HandlerMessage recv msg from server type {0} length {1}", iServerType, message.Header.Length); HandlerOtherServerMessage(remoteAppID, message); return; } } private void HandlerGateMessage(uint remoteAppID, MessageData message) { GateMsgHeader header = new GateMsgHeader(); GateMsgHeaderPacker.UnPack(message.Buffer.Data, ref header); // trans msg to client if (header.OpCode == (int)GateMsgOpCode.Trans) { HandlerClientGateMessage(remoteAppID, message); return; } if (header.OpCode == (int)GateMsgOpCode.ConnectedReq) { OnSessionConnected(remoteAppID, header.SessionID); return; } if (header.OpCode == (int)GateMsgOpCode.DisconnectedReq) { OnSessionDisconnected(remoteAppID, header.SessionID); return; } //int headLength = GateMsgHeaderPacker.GetLength(); } private void OnSessionConnected(uint gateServerID, long sessionID) { TraceLog.Trace("VersionMsgHandler.OnSessionConnected session {0} connected, new PlayerSession", sessionID); //回应 GateMsgHeader gateHeader; gateHeader.OpCode = (int)GateMsgOpCode.ConnectedRes; gateHeader.SessionID = sessionID; GateService.NotifyGateServer(m_app,gateServerID, ref gateHeader); m_versionSvc.AddClientConnectData(gateServerID, sessionID); } private void OnSessionDisconnected(uint gateServerID, long sessionID) { TraceLog.Debug("VersionMsgHandler.OnSessionDisconnected session {0} disconnected, delete PlayerSession" , sessionID); m_versionSvc.RemoveClientConnectData(gateServerID, sessionID); } private void HandlerClientGateMessage(uint gateServerID, MessageData gateMessage) { long sessionID = gateMessage.Header.ObjectID; int headLength = GateMsgHeaderPacker.GetLength(); MessageData message = new MessageData(); message.Header.Type = gateMessage.Header.Type; message.Header.Length = gateMessage.Header.Length - headLength; if (message.Header.Length < 0) { TraceLog.Trace("VersionMsgHandler.HandlerClientGateMessage recv session {0} message ,gateMessage length error ", sessionID); return; } message.MallocData(message.Header.Length); //message.Data = new byte[message.Header.Length]; Buffer.BlockCopy(gateMessage.Buffer.Data, headLength, message.Buffer.Data, 0, message.Buffer.Length); try { HandlerClientMessage(gateServerID, sessionID, message); } finally { message.FreeData(); } } private void HandlerClientMessage(uint gateServerID, long sessionID, MessageData message) { try { StructPacket packet; bool result = VersionServerUtils.GetProtoPacker().UnpackMessage(message, out packet); if (result) { //预先判断,提高效率 if (TraceLog.GetLogLevel() <= (int)Sog.Log.LogLevel.TraceDetail && TraceLog.IsSkipLogMsgID(packet.MsgID) == false) { // log message TraceLog.TraceDetail("VersionMsgHandler.HandlerClientMessage recv from session {0} from gateServer {1}, message type {2} length {3} : {4}->{5}" , sessionID , ServerIDUtils.IDToString(gateServerID) , message.Header.Type , message.Header.Length , packet.MessageName() , packet.ToString()); } ProcessClientPacket(gateServerID, sessionID, packet); } } catch (Exception ex) { TraceLog.Error("VersionMsgHandler.HandlerClientMessage Received from session:{0} error:{1}", sessionID, ex.Message); TraceLog.Exception(ex); } } private void HandlerOtherServerMessage(uint remoteAppID, MessageData message) { try { StructPacket packet; bool result = VersionServerUtils.GetProtoPacker().UnpackMessage(message, out packet); if (result) { if (TraceLog.GetLogLevel() <= (int)Sog.Log.LogLevel.TraceDetail && TraceLog.IsSkipLogMsgID(packet.MsgID) == false) { // log message TraceLog.TraceDetail("VersionMsgHandler.HandlerOtherServerMessage recv message from server {0}, message type {1} length {2} : {3}->{4}" , ServerIDUtils.IDToString(remoteAppID) , message.Header.Type , message.Header.Length , packet.MessageName() , packet.ToString()); } ProcessServerPacket(remoteAppID, packet); } } catch (Exception ex) { TraceLog.Error("VersionMsgHandler.HandlerOtherServerMessage Received from server:{0} error:{1}", ServerIDUtils.IDToString(remoteAppID), ex.Message); TraceLog.Exception(ex); } } private void ProcessClientPacket(uint gateServerID, long sessionID, StructPacket packet) { if(packet.MsgID == (int)CSMsgID.VersionReq) { ProcessVersionReq(gateServerID,sessionID,packet); } } private void ProcessVersionReq(uint gateServerID, long sessionID, StructPacket packet) { ref CSVersionCheckReq req = ref packet.GetMessage(); //非法消息可以不用管 if (m_versionSvc.CheckValidVersionInfo(ref req.Version) == false) { TraceLog.Error("VersionMsgHandler.ProcessVersionReq versioninfo invalid! session {0}", sessionID); return; } long reqVersion = AppVersion.ToIntVersion(req.Version.AppVersion.GetString()); if(reqVersion == 0) { TraceLog.Error("VersionMsgHandler.ProcessVersionReq versioninfo invalid, session {0}, version {1}", sessionID, req.Version.AppVersion); return; } // 强行把windows版本修改成android版本, 方便unity下测试 if (req.Version.Os.Equals("win")) { req.Version.Os.SetString("android"); } long currVer = m_versionSvc.GetCurrentVersion(ref req.Version); CSVersionCheckRes res = new CSVersionCheckRes(); //最先判断服务器是否在维护 if (m_versionSvc.IsMaintenanceMode()) { res.Ret = 0; res.MaintenanceMode = 1; res.MaintenanceNotice.SetString( m_versionSvc.GetMaintenanceNotice()); TraceLog.Trace("VersionMsgHandler.ProcessVersionReq server maintenance now, session {0} version {1}" , sessionID, req.Version.AppVersion); GateService.SendToGate(0, m_app.GetCluster(), gateServerID, sessionID, (int)CSMsgID.VersionRes, ref res); return; } // 当前版本有热更包, 客户端在更新完upk后再更新hotPatch if (m_versionSvc.HasHotPatch()) { string currVerStr = AppVersion.ToStringVersion(currVer); int hotPatchSize = m_versionSvc.GetHotPatchFileSizeAndMd5(ref req.Version, currVerStr, out string hotMd5); if (hotPatchSize > 0) { res.HotPatchFileMd5.SetString(hotMd5); res.HotPatchFileSize = hotPatchSize; string hotUrl = m_versionSvc.GetHotPatchFileUrl(ref req.Version, currVerStr); res.HotPatchDownloadUrl.SetString(hotUrl); TraceLog.Trace("VersionMsgHandler.ProcessVersionReq hot url {0} size {1} md5 {2}" , hotUrl, hotPatchSize, hotMd5); } } int forReview = 0; // 版本服务器配置了不更新, win版本由客户端屏蔽更新, 方便unity下测试 //if (m_versionSvc.IsSkipCheckVersion() || req.Version.Os.Equals( "win")) if (m_versionSvc.IsSkipCheckVersion()) { res.Ret = 0; res.NewVersion.SetString(req.Version.AppVersion.GetPtr()); res.GateUrl.SetString( m_versionSvc.SelectGateUrl(ref req, out forReview)); res.ForReview = forReview; TraceLog.Trace("VersionMsgHandler.ProcessVersionReq version is need not check {0} , need not update, gateUrl {1}", req.Version, res.GateUrl); GateService.SendToGate(0,m_app.GetCluster(), gateServerID, sessionID, (int)CSMsgID.VersionRes, ref res); return; } TraceLog.Debug("VersionMsgHandler.ProcessVersionReq versioninfo session {0}, Appversion {1} Os {2}, Language {3}, currVer {4}, reqVersion {5}", sessionID, req.Version.AppVersion, req.Version.Os, req.Version.Language, currVer, reqVersion); //版本号比当前版本大, 不需要更新 if (reqVersion >= currVer) { res.Ret = 0; res.NewVersion.SetString( AppVersion.ToStringVersion(currVer)); res.GateUrl.SetString( m_versionSvc.SelectGateUrl(ref req, out forReview)); res.ForReview = forReview; TraceLog.Trace("VersionMsgHandler.ProcessVersionReq reqVersion {0} >= curVersion {1}, need not udpate, gateUrl {2}" , req.Version, res.NewVersion, res.GateUrl); GateService.SendToGate(0,m_app.GetCluster(), gateServerID, sessionID, (int)CSMsgID.VersionRes, ref res); return; } string strPathUrl = m_versionSvc.GetPatchFileUrl(ref req.Version, currVer, reqVersion); int patchFileSize = m_versionSvc.GetPatchFileSizeAndMd5(ref req.Version, currVer, reqVersion, out string md5); // 更新包不存在, 告诉客户端去商店更新apk if (patchFileSize <= 0) { res.Ret = 0; res.NewVersion.SetString(AppVersion.ToStringVersion(currVer)); res.GateUrl.SetString(m_versionSvc.SelectGateUrl(ref req, out forReview)); res.ForReview = forReview; res.NeedUpdateApk = 1; GateService.SendToGate(0, m_app.GetCluster(), gateServerID, sessionID, (int)CSMsgID.VersionRes, ref res); return; } foreach (var item in VersionUpdateCompensateDescMgr.Instance.ItemTable) { long updateVer = AppVersion.ToIntVersion(item.appVersion); TraceLog.Debug("VersionMsgHandler.ProcessVersionReq session {0} updateVer {1} currVer {2}" , sessionID, updateVer, currVer); long endTime = ConfigStringTimeParse.ParseConfigTime(item.endTime); if (updateVer == currVer) { //没过期则有奖励 if (endTime == 0 || endTime > VersionServerUtils.GetTimeSecond()) { res.Chip = item.chip; res.Diamond = item.diamond; res.ItemID = item.itemid; res.ItemCount = item.itemcount; } //更新内容 if (! string.IsNullOrWhiteSpace(item.content)) { res.Content.SetString(Sog.Lang.LanguageUtils.GetLanguageString(item.content, req.Version.Language.GetString())); } break; } } res.Ret = 0; res.NewVersion.SetString( AppVersion.ToStringVersion(currVer)); res.GateUrl.SetString( m_versionSvc.SelectGateUrl(ref req, out forReview)); res.ForReview = forReview; res.DownloadUrl.SetString( strPathUrl); res.PatchFileSize = patchFileSize; res.PatchFileMd5.SetString( md5); TraceLog.Trace("VersionMsgHandler.ProcessVersionReq path url is {0}, gateUrl {1} size {2} md5 {3}" , strPathUrl, res.GateUrl, res.PatchFileSize, res.PatchFileMd5); GateService.SendToGate(0,m_app.GetCluster(), gateServerID, sessionID, (int)CSMsgID.VersionRes, ref res); } private void ProcessServerPacket(uint remoteAppID, StructPacket packet) { switch (packet.MsgID) { case (int) SSMsgID.GetClientVerionReq: OnServerGetClientVersion(remoteAppID, packet); break; default: TraceLog.Error("VersionMsgHandler.ProcessServerPacket MsgID {0} not handle", packet.MsgID); break; } } private void OnServerGetClientVersion(uint remoteAppID, StructPacket packet) { ref SSGetClientVersionReq req = ref packet.GetMessage(); SSGetClientVersionRes res = new SSGetClientVersionRes(); res.Version = req.Version; res.CurrVer = m_versionSvc.GetCurrentVersion(ref req.Version); res.CurrVerStr.SetString(AppVersion.ToStringVersion(res.CurrVer)); VersionServerUtils.GetPacketSender().SendToServerByID(remoteAppID, (int)SSMsgID.GetClientVerionRes, ref res, 0); } public void UpdateClientConnect() { var clientConnData = VersionServerUtils.GetVersionServerData().m_ClientConnectDict; foreach (KeyValuePair pair in clientConnData) { uint gateServerID = pair.Value.uGateServerID; long sessionID = pair.Value.iConnectSessionID; long iConnectTime = pair.Value.iConnectTime; if (AppTime.GetNowSysMs() - iConnectTime >= 10 * 1000) { TraceLog.Debug("VersionMsgHandler.UpdateClientConnect TimeOut Disconnect:{0} ", sessionID); GateService.NotifyGateServerDisconnect(GetApp(), gateServerID, sessionID); m_versionSvc.RemoveClientConnectData(gateServerID, sessionID); break; } } } } }