You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
15 KiB

1 month ago
/*
Sog
2016 by zouwei
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Org.BouncyCastle.Ocsp;
using ProtoCSStruct;
using Sog;
namespace Chat
{
public static class ChatCacheOp
{
private static int ChannalCacheMax = 100; //单频道消息缓存数量限制
private static int SaveFileCdSec = 300; //存盘cd 单位秒
private static int SaveMaxDay = 14; //起服只读X天以内数据
public static void InitChatCacheConfig(ChatServerConfig serverConfig)
{
if (serverConfig == null)
{
TraceLog.Error("ChatCacheOp.InitChatCacheConfig error");
return;
}
ChannalCacheMax = serverConfig.ChannalCacheMax;
SaveFileCdSec = Math.Max(300, serverConfig.SaveFileCdSec); //不要低于5分钟
SaveMaxDay = serverConfig.SaveMaxDay;
}
public static string GetSaveFilePath()
{
return "./ChannalChatCacheData_" + ChatServerUtils.GetApp().ServerID.ToString() + ".fdb";
}
public static void WriteChatCacheStat()
{
ref var chatCache = ref ChatServerUtils.GetChatServerData().m_chatCacheInfo;
TraceLog.Stat("ChatCacheStruct total {0} used {1} rate {2}%"
, chatCache.m_cacheStrutChatReq.GetTotalCount()
, chatCache.m_cacheStrutChatReq.GetUsedCount()
, chatCache.m_cacheStrutChatReq.GetUsedPercent());
}
public static void ChatCacheTick(long nowSec)
{
ref var chatCache = ref ChatServerUtils.GetChatServerData().m_chatCacheInfo;
long saveCdSec = SaveFileCdSec;
//停服时5s
if (ChatServerUtils.GetApp().IsStopping)
{
saveCdSec = 5;
}
if (chatCache.m_lastSaveTime + saveCdSec < nowSec)
{
SaveCacheToFile();
chatCache.m_lastSaveTime = nowSec;
WriteChatCacheStat();
}
}
public static int AddChatCache(ref CSChatRes res, ChatChannelType type = ChatChannelType.None)
{
long channelId = ChatServerData.GetChatChannelId(res.ChatChannelType, res.ChannelParam);
ref var chatCache = ref ChatServerUtils.GetChatServerData().m_chatCacheInfo;
chatCache.m_needSave = true;
if (channelId <= 0)
{
TraceLog.Error("ChatCacheOp.AddChatCache channelId {0} ChatChannelType {1} ChannelParam:{2}", channelId, res.ChatChannelType, res.ChannelParam);
return -1;
}
if (chatCache.m_channalCacheMap.ContainsKey(channelId))
{
//看有没有到单Id上限
var list = chatCache.m_channalCacheMap[channelId];
if (list.Count < ChannalCacheMax)
{
ref ChatCacheDataStruct cache = ref chatCache.m_cacheStrutChatReq.Malloc();
if (!cache.IsNull())
{
cache.cacheData.CopyFrom(ref res);
list.AddLast(cache.GetObjectID());
return 0;
}
}
//需要顶掉老的缓存
if (list.Count > 0)
{
//取最早的覆盖数据后放到末尾
int index = list.First.Value;
list.RemoveFirst();
ref ChatCacheDataStruct cache = ref chatCache.m_cacheStrutChatReq.GetByIndex(index);
if (!cache.IsNull())
{
cache.cacheData.CopyFrom(ref res);
list.AddLast(index);
return 0;
}
else
{
//下标有问题
TraceLog.Error("ChatCacheOp.AddChatCache not find index:{0}", index);
return -1;
}
}
TraceLog.Error("ChatCacheOp.AddChatCache list count error {0} {1}", channelId, list.Count);
return -1;
}
else
{
ref ChatCacheDataStruct cache = ref chatCache.m_cacheStrutChatReq.Malloc();
if (!cache.IsNull())
{
cache.cacheData.CopyFrom(ref res);
LinkedList<int> linkList = new LinkedList<int>();
linkList.AddLast(cache.GetObjectID());
chatCache.m_channalCacheMap.Add(channelId, linkList);
return 0;
}
else
{
//空间不够
TraceLog.Error("ChatCacheOp.AddChatCache not space");
return -1;
}
}
}
//获取对应id的缓存数据
public static void OnGetChannelCacheData(PlayerOnChat player, ChatChannelType channel, long channelParam, long seq)
{
long channelId = ChatServerData.GetChatChannelId(channel, channelParam);
ref var chatCache = ref ChatServerUtils.GetChatServerData().m_chatCacheInfo;
CSChannelCacheDataRes channelChatCache = new CSChannelCacheDataRes()
{
ChatChannelType = channel,
ChannelParam = channelParam,
};
Dictionary<long, long> dicChatBlack = ChatSvc.GetPlayerDicChatBlack(player);
TraceLog.Trace("ChatCacheOp.OnGetChannelCacheData player {0} channel {1} {2} seq {3} dicChatBlackCount {4}",
player.UserID, channel, channelParam, seq, dicChatBlack.Count);
if (chatCache.m_channalCacheMap.ContainsKey(channelId))
{
if (chatCache.m_channalCacheMap[channelId].Count > 0)
{
var list = chatCache.m_channalCacheMap[channelId];
var node = list.Last;
while (node != null)
{
ref var cache = ref chatCache.m_cacheStrutChatReq.GetByIndex(node.Value);
if (!cache.IsNull()
&& cache.cacheData.ChatSeq > seq
&& channelChatCache.ChatCache.Count < channelChatCache.ChatCache.GetMaxCount())
{
long chatBlackTime = 0;
if (dicChatBlack.TryGetValue(cache.cacheData.Uid, out chatBlackTime)) //找聊天缓存的话,聊天屏蔽黑名单中的,并且是屏蔽时间之后的,才进行过滤
{
if (chatBlackTime > cache.cacheData.SendTime)
{
channelChatCache.ChatCache.Add(ref cache.cacheData);
if (channelChatCache.ChatCache.Count >= channelChatCache.ChatCache.GetMaxCount())
{
break;
}
}
else
{
TraceLog.Trace("ChatCacheOp.OnGetChannelCacheData filter user {0} chatBlackUid {1} chatBlackTime {2} SendTime {3}", player.UserID, cache.cacheData.Uid, chatBlackTime, cache.cacheData.SendTime);
}
}
else
{
channelChatCache.ChatCache.Add(ref cache.cacheData);
if (channelChatCache.ChatCache.Count >= channelChatCache.ChatCache.GetMaxCount())
{
break;
}
}
}
node = node.Previous;
}
}
}
PlayerPacketSender.SendToPlayer(player, (int)CSGameMsgID.ChannelCacheDataRes, ref channelChatCache);
TraceLog.Trace("ChatCacheOp.OnGetChannelCacheData player {0} channel {1} {2} seq {3} realcount {4}",
player.UserID, channel, channelParam, seq, channelChatCache.ChatCache.Count);
}
//占居内存大的话不适用
/*public static void SaveChatCache(bool forceSave = false)
{
ref var chatCache = ref ChatServerUtils.GetChatServerData().m_chatCacheInfo;
if ((!chatCache.m_needSave) && (!forceSave))
{
return;
}
int needSaveNum = chatCache.m_cacheStrutChatReq.GetUsedCount();
TraceLog.Trace("ChatCache.SaveChatCache save file {0} begin time {1} needSave {2}", saveFile, AppTime.GetNowSysMs(), needSaveNum);
ChannelChatCacheData needSaveData = new ChannelChatCacheData();
foreach (var idQueueKv in chatCache.m_channalCacheMap)
{
foreach (int index in idQueueKv.Value)
{
ref var dataOne = ref chatCache.m_cacheStrutChatReq.GetByIndex(index);
if (!dataOne.IsNull())
{
needSaveData.ChatList.Add(ref dataOne.cacheData);
}
}
}
int iRet = Sog.IO.FileDBSave.SaveToFile(ref needSaveData, saveFile);
if (iRet != 0)
{
TraceLog.Error("ChatCache.SaveChatCache save file {0} error, ret {1}", saveFile, iRet);
}
if (needSaveData.ChatList.Count != needSaveNum)
{
TraceLog.Error("ChatCache.SaveChatCache save less need:{0} have:{1}", needSaveNum, needSaveData.ChatList.Count);
}
TraceLog.Trace("ChatCache.SaveChatCache save file {0} success time {1}", saveFile, AppTime.GetNowSysMs());
}*/
/*public static void LoadChatCache()
{
TraceLog.Trace("ChatCache.LoadChatCache load file:{0} begin time:{0}", saveFile, AppTime.GetNowSysMs());
ChannelChatCacheData data = new ChannelChatCacheData();
if (File.Exists(saveFile) == false)
{
TraceLog.Debug("ChatCache.LoadChatCache file not exist {0}", saveFile);
return;
}
bool success = Sog.IO.FileDBSave.ReadFromFile(ref data, saveFile);
if ( !success)
{
TraceLog.Error("ChatCache.LoadChatCache failed! file:{0}", saveFile);
return;
}
for(int i = 0; i < data.ChatList.Count; ++i)
{
ref var chatRes = ref data.ChatList[i];
AddChatCache(ref chatRes);
ChatServerUtils.GetChatServerData().SetChannalChatSeq(chatRes.ChatSeq, chatRes.ChatChannelType, chatRes.ChannelParam);
}
TraceLog.Trace("ChatCache.LoadChatCache load file:{0} success time:{0}", saveFile, AppTime.GetNowSysMs());
SaveChatCache(true);
}*/
public static void SaveCacheToFile()
{
ref var chatCache = ref ChatServerUtils.GetChatServerData().m_chatCacheInfo;
if (chatCache.m_needSave == false)
{
return;
}
int haveSave = 0;
string saveFile = GetSaveFilePath();
TraceLog.Trace("ChatCacheOp.SaveCacheToFile save file {0} begin time {1}", saveFile, AppTime.GetNowSysMs());
try
{
FileStream fileStream = File.OpenWrite(saveFile);
//清空文件
fileStream.SetLength(0);
BinaryWriter sw = new BinaryWriter(fileStream);
foreach (var item in chatCache.m_channalCacheMap)
{
foreach (int index in item.Value)
{
ref var dataOne = ref chatCache.m_cacheStrutChatReq.GetByIndex(index);
if (!dataOne.IsNull())
{
int size = dataOne.cacheData.CalculateSize();
byte[] dataByte = new byte[size];
CodedOutputStream ouput = new CodedOutputStream(dataByte);
dataOne.cacheData.WriteTo(ouput);
sw.Write(size); //写入长度
sw.Write(dataByte); //写入数据
sw.Flush();
++haveSave;
}
}
}
sw.Dispose();
fileStream.Dispose();
chatCache.m_needSave = false;
}
catch (Exception ex)
{
TraceLog.Error("ChatCacheOp.SaveCacheToFile write file failed! {0}", saveFile);
TraceLog.Exception(ex);
return;
}
TraceLog.Trace("ChatCacheOp.SaveCacheToFile save file {0} num {1} success time {2}", saveFile, haveSave, AppTime.GetNowSysMs());
}
public static bool LoadCacheFromFile()
{
string saveFile = GetSaveFilePath();
TraceLog.Trace("ChatCacheOp.LoadCacheFromFile load file {0} begin time {1}", saveFile, AppTime.GetNowSysMs());
var chatServerData = ChatServerUtils.GetChatServerData();
ref var chatCache = ref chatServerData.m_chatCacheInfo;
if (File.Exists(saveFile) == false)
{
TraceLog.Trace("ChatCacheOp.LoadCacheFromFile file not exist {0}", saveFile);
return true;
}
long nowSec = ChatServerUtils.GetTimeSecond();
long needSaveTime = nowSec - SaveMaxDay * 24 * 3600;
try
{
FileStream fileStream = File.OpenRead(saveFile);
BinaryReader sw = new BinaryReader(fileStream);
long lenth = fileStream.Length;
long pos = 0;
while (pos < lenth)
{
int size = sw.ReadInt32(); //读长度
byte[] data = sw.ReadBytes(size); //读数据
pos += (sizeof(Int32) + size);
if (pos <= lenth)
{
CodedInputStream input = new CodedInputStream(data);
CSChatRes chatRes = new CSChatRes();
chatRes.ReadFrom(input);
//XX天以前的消息就不存了
if (chatRes.SendTime > needSaveTime)
{
AddChatCache(ref chatRes);
chatServerData.SetChannalChatSeq(chatRes.ChatSeq, chatRes.ChatChannelType, chatRes.ChannelParam);
}
}
}
sw.Dispose();
fileStream.Dispose();
}
catch (Exception ex)
{
TraceLog.Error("ChatCacheOp.LoadCacheFromFile parse message failed! {0}", saveFile);
TraceLog.Exception(ex);
return false;
}
TraceLog.Trace("ChatCacheOp.LoadCacheFromFile load file {0} success time {1}", saveFile, AppTime.GetNowSysMs());
return true;
}
}
}