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.
584 lines
20 KiB
584 lines
20 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Net.Http;
|
|
using System.Security.Cryptography;
|
|
using System.Threading;
|
|
using System.Collections.Concurrent;
|
|
|
|
using Sog;
|
|
using ProtoCSStruct;
|
|
using LitJson;
|
|
using System.Text.Json;
|
|
using static System.Net.Mime.MediaTypeNames;
|
|
|
|
namespace Chat
|
|
{
|
|
|
|
public class HeroSentimentSvc
|
|
{
|
|
public static string m_baseUrl;
|
|
public static int gameId;
|
|
public static string secretKey;
|
|
|
|
private static MD5 m_md5;
|
|
|
|
public static Object m_locker = new Object();
|
|
public static Object m_Banlocker = new Object();
|
|
|
|
public static JsonData m_ChatList;
|
|
|
|
public static JsonData m_BanLogList;
|
|
|
|
// 实时检测
|
|
public static string validateUrl = "/v2/api/content/validate";
|
|
// 上报聊天数据
|
|
public static string reportUrl = "/v2/api/message/receive";
|
|
// 上报封禁数据
|
|
public static string banLogUrl = "/v2/api/log/receive";
|
|
|
|
private static ConcurrentQueue<(PlayerOnChat, CSChatReq)> m_chatMsgWaitQueue = new ConcurrentQueue<(PlayerOnChat, CSChatReq)>();
|
|
private static ConcurrentQueue<SSCheckDirtyStringReq> m_checkMsgReqQueue = new ConcurrentQueue<SSCheckDirtyStringReq>();
|
|
|
|
private static bool m_isStart = false;
|
|
|
|
private static int m_threadCount = 3;
|
|
|
|
private static Thread[] m_threads = null;
|
|
|
|
private static long lastReportTime = 0;
|
|
|
|
private static long lastReportBanLogTime = 0;
|
|
|
|
public static void Init()
|
|
{
|
|
m_md5 = MD5.Create();
|
|
|
|
m_baseUrl = ChatServerUtils.GetServerConfig().sentimentUrl;
|
|
gameId = ChatServerUtils.GetServerConfig().sentimentGameId;
|
|
secretKey = ChatServerUtils.GetServerConfig().sentimentSecretKey;
|
|
m_ChatList = new JsonData();
|
|
m_ChatList.SetJsonType(JsonType.Array);
|
|
m_BanLogList = new JsonData();
|
|
m_BanLogList.SetJsonType(JsonType.Array);
|
|
|
|
if (ChatServerUtils.GetServerConfig().isUseHeroSentiment == 1)
|
|
{
|
|
Start();
|
|
}
|
|
}
|
|
|
|
private static string GetSign(string timeStamp)
|
|
{
|
|
if (m_md5 == null)
|
|
{
|
|
m_md5 = MD5.Create();
|
|
}
|
|
|
|
string singStr = secretKey + timeStamp;
|
|
byte[] strbyte = Encoding.UTF8.GetBytes(singStr);
|
|
byte[] md5Hash = m_md5.ComputeHash(strbyte);
|
|
string md5Str = BitConverter.ToString(md5Hash).Replace("-", "").ToLower();
|
|
|
|
return md5Str;
|
|
|
|
}
|
|
|
|
public static void OnHandleChatRealtimeValidate(PlayerOnChat player, ref CSChatReq req)
|
|
{
|
|
//将消息加入队列
|
|
m_chatMsgWaitQueue.Enqueue((player, req));
|
|
|
|
try
|
|
{
|
|
AddChatToList(player, ref req);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error("OnHandleChatRealtimeValidate.AddChatToList - error: ", e.Message);
|
|
}
|
|
}
|
|
|
|
public static void OnHandleDirtyChatCheck(ref SSCheckDirtyStringReq req)
|
|
{
|
|
m_checkMsgReqQueue.Enqueue(req);
|
|
}
|
|
|
|
private static void Start()
|
|
{
|
|
if (!m_isStart)
|
|
{
|
|
m_isStart = true;
|
|
m_threads = new Thread[m_threadCount];
|
|
for (int i = 0; i < m_threadCount; i++)
|
|
{
|
|
m_threads[i] = new Thread(WorkThreadFun);
|
|
//设置成后台线程,如果不是后台线程,线程不是主动关闭,则会一直运行,那怕进程主线程退出也没用
|
|
m_threads[i].IsBackground = true;
|
|
m_threads[i].Start();
|
|
}
|
|
|
|
var reportThread = new Thread(ThreadReport);
|
|
//设置成后台线程,如果不是后台线程,线程不是主动关闭,则会一直运行,那怕进程主线程退出也没用
|
|
reportThread.IsBackground = true;
|
|
reportThread.Start();
|
|
|
|
var reportBanLogThread = new Thread(ThreadReportBanLog);
|
|
//设置成后台线程,如果不是后台线程,线程不是主动关闭,则会一直运行,那怕进程主线程退出也没用
|
|
reportBanLogThread.IsBackground = true;
|
|
reportBanLogThread.Start();
|
|
}
|
|
}
|
|
|
|
private static void WorkThreadFun()
|
|
{
|
|
while (m_isStart)
|
|
{
|
|
bool haveData = false;
|
|
try
|
|
{
|
|
if (false == m_checkMsgReqQueue.IsEmpty && m_checkMsgReqQueue.TryDequeue(out var checkReq))
|
|
{
|
|
haveData = true;
|
|
HandleDirtyStringCheck(ref checkReq);
|
|
}
|
|
|
|
if (false == m_chatMsgWaitQueue.IsEmpty && m_chatMsgWaitQueue.TryDequeue(out var record))
|
|
{
|
|
haveData = true;
|
|
HandleChatRealtimeValidate(record.Item1, ref record.Item2);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
TraceLog.Exception(ex);
|
|
}
|
|
|
|
if (!haveData)
|
|
{
|
|
Thread.Sleep(10);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 脏词检查
|
|
/// </summary>
|
|
/// <param name="packet"></param>
|
|
public static void HandleDirtyStringCheck(ref SSCheckDirtyStringReq req)
|
|
{
|
|
if (ChatServerUtils.GetServerConfig().useWechatCheck)
|
|
{
|
|
bool pass = WechatCheckSvc.CheckDirtyName(req.Content.GetString());
|
|
SSCheckDirtyStringRes res = new SSCheckDirtyStringRes();
|
|
res.Result = pass ? 0 : 1;
|
|
res.Uid = req.Uid;
|
|
res.CheckSeq = req.CheckSeq;
|
|
res.ServerId = req.ServerId;
|
|
if (res.Result >= 0)
|
|
{
|
|
res.NewContent.SetString(req.Content.GetString());
|
|
}
|
|
ChatServerUtils.GetPacketSender().SendToServerByID(res.ServerId, (int)SSGameMsgID.CheckDirtyStringRes, ref res, res.Uid);
|
|
}
|
|
else
|
|
{
|
|
string newContent = GetDirtyStringResult(req.Content.GetString(), out int checkResult);
|
|
SSCheckDirtyStringRes res = new SSCheckDirtyStringRes();
|
|
res.Result = checkResult;
|
|
res.Uid = req.Uid;
|
|
res.CheckSeq = req.CheckSeq;
|
|
res.ServerId = req.ServerId;
|
|
if (res.Result >= 0)
|
|
{
|
|
res.NewContent.SetString(newContent);
|
|
}
|
|
ChatServerUtils.GetPacketSender().SendToServerByID(res.ServerId, (int)SSGameMsgID.CheckDirtyStringRes, ref res, res.Uid);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 实时监测聊天
|
|
/// </summary>
|
|
/// <param name="packet"></param>
|
|
public static void HandleChatRealtimeValidate(PlayerOnChat player, ref CSChatReq req)
|
|
{
|
|
string newContent = GetDirtyStringResult(req.Message.GetString(), out int checkResult);
|
|
if (checkResult == 0)
|
|
{
|
|
ChatSvc.SendToChatMsg(player, ref req);
|
|
}
|
|
else if (checkResult == 1)
|
|
{
|
|
//有错误不让发
|
|
//req.Message.SetString(newContent);
|
|
//ChatSvc.SendToChatMsg(player, ref req);
|
|
CSChatRes res = new CSChatRes();
|
|
res.Ret = (int)CSErrCode.IncludeIllegalWord;
|
|
PlayerPacketSender.SendToPlayer(player, (int)CSGameMsgID.ChatRes, ref res);
|
|
TraceLog.Trace("HeroSentimentSvc.HandleChatRealtimeValidate send world player:{0} mess:{1} ret:{2}", player.UserID, req.Message.GetString(), checkResult);
|
|
}
|
|
else
|
|
{
|
|
CSChatRes res = new CSChatRes();
|
|
res.Ret = (int)CSErrCode.SysFailure;
|
|
PlayerPacketSender.SendToPlayer(player, (int)CSGameMsgID.ChatRes, ref res);
|
|
TraceLog.Error("HeroSentimentSvc.HandleChatRealtimeValidate error ret {0}", checkResult);
|
|
}
|
|
}
|
|
|
|
public static string GetDirtyStringResult(string oldStr, out int checkResult)
|
|
{
|
|
string str = "";
|
|
try
|
|
{
|
|
str = DealDirtyString(oldStr, out checkResult);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
checkResult = -1;
|
|
str = "";
|
|
TraceLog.Exception(ex);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
private static string DealDirtyString(string oldStr, out int checkResult)
|
|
{
|
|
string replace_content = "";
|
|
if (oldStr.Length == 0)
|
|
{
|
|
checkResult = 0;
|
|
return replace_content;
|
|
}
|
|
|
|
if (m_baseUrl == "" || m_baseUrl == null)
|
|
{
|
|
checkResult = -1;
|
|
TraceLog.Error("HeroSentimentSvc.DealDirtyString error baseUrl");
|
|
return replace_content;
|
|
}
|
|
|
|
var heardParams = new List<KeyValuePair<string, string>>();
|
|
string timeStamp = ChatServerUtils.GetTimeStamp(DateTime.Now).ToString();
|
|
|
|
heardParams.Add(new KeyValuePair<string, string>("gameId", Convert.ToString(gameId)));
|
|
heardParams.Add(new KeyValuePair<string, string>("sign", GetSign(timeStamp)));
|
|
heardParams.Add(new KeyValuePair<string, string>("timeStamp", timeStamp));
|
|
|
|
var contentParams = new Dictionary<string, string>();
|
|
contentParams["content"] = oldStr;
|
|
|
|
var content = new StringContent(
|
|
JsonSerializer.Serialize(contentParams),
|
|
Encoding.UTF8,
|
|
Application.Json);
|
|
|
|
string postUrl = m_baseUrl + validateUrl;
|
|
|
|
string ret = HttpUtils.HttpPost(postUrl, content, heardParams, out bool exception);
|
|
if (ret == null)
|
|
{
|
|
checkResult = -1;
|
|
TraceLog.Error("HeroSentimentSvc.DealDirtyString error HttpPost ret");
|
|
return replace_content;
|
|
}
|
|
|
|
JsonData jsonData = JsonMapper.ToObject(ret);
|
|
JsonData codeData = jsonData["code"];
|
|
|
|
int code = codeData != null ? (int)codeData : -1;
|
|
if (code != 0)
|
|
{
|
|
checkResult = -1;
|
|
TraceLog.Error("HeroSentimentSvc.DealDirtyString error code {0}", code);
|
|
return replace_content;
|
|
}
|
|
|
|
JsonData data = jsonData["data"];
|
|
checkResult = Convert.ToInt16(data["result"].ToString());
|
|
replace_content = data["replace_content"].ToString();
|
|
TraceLog.Trace("HeroSentimentSvc.DealDirtyString checkResult {0} str {1} ret {2} ", ret, oldStr, checkResult);
|
|
return replace_content;
|
|
}
|
|
|
|
public static void ThreadReport()
|
|
{
|
|
while (m_isStart)
|
|
{
|
|
long nowSecond = ChatServerUtils.GetTimeSecond();
|
|
if (m_ChatList.Count >= 50 || (nowSecond - lastReportTime) >= 5)
|
|
{
|
|
lastReportTime = nowSecond;
|
|
try
|
|
{
|
|
OnReportChatData();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error("WorkThreadFun.OnReportChatData.error: ", e.Message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Thread.Sleep(10);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void AddChatToList(PlayerOnChat player, ref CSChatReq chatReq)
|
|
{
|
|
var chatMsg = new JsonData();
|
|
|
|
chatMsg["role_id"] = chatReq.Uid.ToString();
|
|
chatMsg["server_id"] = (int)player.RealmID;
|
|
chatMsg["role_name"] = player.Nick;
|
|
chatMsg["type"] = (int)chatReq.ChatChannelType;
|
|
chatMsg["message"] = chatReq.Message.GetString();
|
|
chatMsg["vip_level"] = player.roleBase.VipLevel;
|
|
chatMsg["level"] = player.roleBase.Level;
|
|
var extend_items = new JsonData();
|
|
extend_items["test"] = "testValue";
|
|
chatMsg["extend_items"] = extend_items;
|
|
|
|
lock (m_locker)
|
|
{
|
|
m_ChatList.Add(chatMsg);
|
|
}
|
|
}
|
|
|
|
private static void OnReportChatData()
|
|
{
|
|
if (m_ChatList.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
JsonData reportData = new JsonData();
|
|
string reportDataStr;
|
|
lock (m_locker)
|
|
{
|
|
reportData["chat_items"] = m_ChatList;
|
|
reportDataStr = reportData.ToJson();
|
|
m_ChatList.Clear();
|
|
}
|
|
|
|
var heardParams = new List<KeyValuePair<string, string>>();
|
|
string timeStamp = ChatServerUtils.GetTimeStamp(DateTime.Now).ToString();
|
|
|
|
heardParams.Add(new KeyValuePair<string, string>("gameId", Convert.ToString(gameId)));
|
|
heardParams.Add(new KeyValuePair<string, string>("sign", GetSign(timeStamp)));
|
|
heardParams.Add(new KeyValuePair<string, string>("timeStamp", timeStamp));
|
|
|
|
|
|
//var contentParams = new Dictionary<string, JsonData>();
|
|
//contentParams["chat_items"] = reportData;
|
|
|
|
var content = new StringContent(
|
|
reportDataStr,
|
|
Encoding.UTF8,
|
|
Application.Json);
|
|
|
|
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
|
|
|
string postUrl = m_baseUrl + reportUrl;
|
|
string ret = HttpUtils.HttpPost(postUrl, content, heardParams, out bool exception);
|
|
if (ret == null)
|
|
{
|
|
TraceLog.Error("HeroSentimentSvc.OnReportChatData HttpGet return null query failed");
|
|
return;
|
|
}
|
|
|
|
JsonData jsonData = JsonMapper.ToObject(ret);
|
|
JsonData codeData = jsonData["code"];
|
|
|
|
int code = codeData != null ? (int)codeData : -1;
|
|
string msg = jsonData["msg"].ToString();
|
|
|
|
TraceLog.Trace("HeroSentimentSvc.OnReportChatData ret {0} code {1} msg {2}", ret, code, msg);
|
|
|
|
if (code != 0)
|
|
{
|
|
TraceLog.Error("HeroSentimentSvc.OnReportChatData: ret code : {0} msg :{1}", code, msg);
|
|
return;
|
|
}
|
|
}
|
|
|
|
public static void ThreadReportBanLog()
|
|
{
|
|
while (m_isStart)
|
|
{
|
|
long nowSecond = ChatServerUtils.GetTimeSecond();
|
|
if (m_BanLogList.Count >= 10 || (nowSecond - lastReportBanLogTime) >= 5)
|
|
{
|
|
lastReportBanLogTime = nowSecond;
|
|
try
|
|
{
|
|
OnReportBanLogData();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error("ThreadReportBanLog.OnReportBanLogData.error: ", e.Message);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Thread.Sleep(10);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void OnHandleChatBan(long uid, PlayerOnChat player, ref CSGagChatNotify req)
|
|
{
|
|
try
|
|
{
|
|
AddChatBanLogToList(uid, player, ref req);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error("OnHandleChatBan.AddChatBanLogToList - error: ", e.Message);
|
|
}
|
|
}
|
|
|
|
private static void AddChatBanLogToList(long uid, PlayerOnChat player, ref CSGagChatNotify req)
|
|
{
|
|
var chatMsg = new JsonData();
|
|
|
|
TraceLog.Trace("OnHandleChatBan.AddChatBanLogToList uid {0} GagEndTime {1} EnableType {2} EnableStr {3}", uid, req.GagEndTime, req.EnableType, req.EnableStr);
|
|
|
|
if (player == null) //TODO 没有上报区服和名字
|
|
{
|
|
chatMsg["server_id"] = 0;
|
|
chatMsg["role_id"] = uid.ToString();
|
|
chatMsg["role_name"] = "";
|
|
}
|
|
else
|
|
{
|
|
chatMsg["server_id"] = (int)player.RealmID;
|
|
chatMsg["role_id"] = player.UserID.ToString();
|
|
chatMsg["role_name"] = player.Nick;
|
|
}
|
|
|
|
chatMsg["ban_type"] = 2; //禁言
|
|
|
|
if (!string.IsNullOrEmpty(req.EnableStr.ToString()))
|
|
chatMsg["ban_reason"] = req.EnableStr.ToString();
|
|
else
|
|
chatMsg["ban_reason"] = req.EnableType.ToString();
|
|
|
|
chatMsg["ban_begin_time"] = ChatServerUtils.GetTimeSecond();
|
|
chatMsg["ban_end_time"] = req.GagEndTime;
|
|
|
|
lock (m_Banlocker)
|
|
{
|
|
m_BanLogList.Add(chatMsg);
|
|
}
|
|
}
|
|
|
|
public static void OnHandleSetFreezeTime(long uid, PlayerOnChat player, ref SSGMSetFreezeTimeRes req)
|
|
{
|
|
try
|
|
{
|
|
AddSetFreezeTimeBanLogToList(uid, player, ref req);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error("OnHandleChatBan.AddSetFreezeTimeBanLogToList - error: ", e.Message);
|
|
}
|
|
}
|
|
|
|
private static void AddSetFreezeTimeBanLogToList(long uid, PlayerOnChat player, ref SSGMSetFreezeTimeRes req)
|
|
{
|
|
var chatMsg = new JsonData();
|
|
|
|
TraceLog.Trace("OnHandleChatBan.AddSetFreezeTimeBanLogToList uid {0} FreezeTime {1} FreezeReason {2} FreezeReasonStr {3}", uid, req.FreezeTime, req.FreezeReason, req.FreezeReasonStr);
|
|
|
|
if (player == null) //TODO 没有上报区服和名字
|
|
{
|
|
chatMsg["server_id"] = 0;
|
|
chatMsg["role_id"] = uid.ToString();
|
|
chatMsg["role_name"] = "";
|
|
}
|
|
else
|
|
{
|
|
chatMsg["server_id"] = (int)player.RealmID;
|
|
chatMsg["role_id"] = player.UserID.ToString();
|
|
chatMsg["role_name"] = player.Nick;
|
|
}
|
|
|
|
chatMsg["ban_type"] = 1; //封号
|
|
|
|
if (!string.IsNullOrEmpty(req.FreezeReasonStr.ToString()))
|
|
chatMsg["ban_reason"] = req.FreezeReasonStr.ToString();
|
|
else
|
|
chatMsg["ban_reason"] = req.FreezeReason.ToString();
|
|
|
|
chatMsg["ban_begin_time"] = ChatServerUtils.GetTimeSecond();
|
|
chatMsg["ban_end_time"] = req.FreezeTime;
|
|
|
|
lock (m_Banlocker)
|
|
{
|
|
m_BanLogList.Add(chatMsg);
|
|
}
|
|
}
|
|
|
|
private static void OnReportBanLogData()
|
|
{
|
|
if (m_BanLogList.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
JsonData reportData = new JsonData();
|
|
string reportDataStr;
|
|
lock (m_Banlocker)
|
|
{
|
|
reportData["log_items"] = m_BanLogList;
|
|
reportDataStr = reportData.ToJson();
|
|
m_BanLogList.Clear();
|
|
}
|
|
|
|
var heardParams = new List<KeyValuePair<string, string>>();
|
|
string timeStamp = ChatServerUtils.GetTimeStamp(DateTime.Now).ToString();
|
|
|
|
heardParams.Add(new KeyValuePair<string, string>("gameId", Convert.ToString(gameId)));
|
|
heardParams.Add(new KeyValuePair<string, string>("sign", GetSign(timeStamp)));
|
|
heardParams.Add(new KeyValuePair<string, string>("timeStamp", timeStamp));
|
|
|
|
var content = new StringContent(
|
|
reportDataStr,
|
|
Encoding.UTF8,
|
|
Application.Json);
|
|
|
|
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
|
|
|
|
string postUrl = m_baseUrl + banLogUrl;
|
|
string ret = HttpUtils.HttpPost(postUrl, content, heardParams, out bool exception);
|
|
if (ret == null)
|
|
{
|
|
TraceLog.Error("HeroSentimentSvc.OnReportBanLogData HttpGet return null query failed");
|
|
return;
|
|
}
|
|
|
|
JsonData jsonData = JsonMapper.ToObject(ret);
|
|
JsonData codeData = jsonData["code"];
|
|
|
|
int code = codeData != null ? (int)codeData : -1;
|
|
string msg = jsonData["msg"].ToString();
|
|
|
|
TraceLog.Trace("HeroSentimentSvc.OnReportBanLogData ret {0} code {1} msg {2}", ret, code, msg);
|
|
|
|
if (code != 0)
|
|
{
|
|
TraceLog.Error("HeroSentimentSvc.OnReportBanLogData: ret code : {0} msg :{1}", code, msg);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|