399 lines
13 KiB
C#
399 lines
13 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
|
||
namespace ChatRoomServer.Main
|
||
{
|
||
using ChatRoomServer.Db;
|
||
using ChatRoomServer.Db.Entities;
|
||
using ChatRoomServer.Main.Entities;
|
||
using ChatRoomServer.Main.Room;
|
||
using FSLib.Logs.Log4Net;
|
||
using FSLib.Network.SuperSocket.Protocols.WebSocket;
|
||
using FSLib.Network.SuperSocket.SocketBase;
|
||
|
||
class ChatSession : WebSocketSession<ChatSession>
|
||
{
|
||
static ILog _log = ChatServer.GetLogger(typeof(ChatSession).Name);
|
||
|
||
DateTime _connecTime = DateTime.Now;
|
||
long _connectId;
|
||
bool _isAdmin;
|
||
|
||
/// <summary>
|
||
/// 路径分割
|
||
/// </summary>
|
||
public string[] PathSegements { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 命令
|
||
/// </summary>
|
||
public string Command { get; private set; }
|
||
|
||
public string UserName { get; private set; }
|
||
|
||
public string NickName { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 获得或设置房间
|
||
/// </summary>
|
||
public RoomContainer RoomContainer { get; set; }
|
||
|
||
/// <summary>
|
||
/// ID
|
||
/// </summary>
|
||
public string Id { get; private set; }
|
||
|
||
bool IsBlocked()
|
||
{
|
||
DateTime? dt = null;
|
||
|
||
if ((AppServer as ChatServer).BlockUsers?.TryGetValue(UserName, out dt) == true)
|
||
{
|
||
IsSessionBlocked = true;
|
||
Block(dt);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Called when [session started].
|
||
/// </summary>
|
||
protected override void OnSessionStarted()
|
||
{
|
||
base.OnSessionStarted();
|
||
|
||
var path = Path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
|
||
if (path.Length >= 4)
|
||
{
|
||
Command = path[0];
|
||
Id = System.Net.WebUtility.UrlDecode(path[1]);
|
||
UserName = System.Net.WebUtility.UrlDecode(path[2]);
|
||
NickName = System.Net.WebUtility.UrlDecode(path[3]);
|
||
}
|
||
PathSegements = path;
|
||
_isAdmin = ChatServer.PresetAdministrators.Contains(UserName);
|
||
|
||
if (IsBlocked())
|
||
return;
|
||
|
||
//更新统计
|
||
var db = new ChatDb();
|
||
BlockUser blockRule = null;
|
||
var user = db.Users.FirstOrDefault(s => s.UserName == UserName);
|
||
if (user == null)
|
||
{
|
||
user = new User()
|
||
{
|
||
UserName = UserName,
|
||
NickName = NickName,
|
||
FirstConnect = DateTime.Now,
|
||
Status = UserStatus.Normal
|
||
};
|
||
db.Users.Add(user);
|
||
}
|
||
user.LastConnect = DateTime.Now;
|
||
var ucl = new UserConnectLog()
|
||
{
|
||
UserName = UserName,
|
||
ConnectTime = DateTime.Now,
|
||
RoomID = Id,
|
||
Ip = RemoteEndPoint.ToString()
|
||
};
|
||
db.UserConnectLogs.Add(ucl);
|
||
db.SaveChanges();
|
||
_connectId = ucl.Id;
|
||
|
||
}
|
||
|
||
public bool IsSessionBlocked { get; private set; }
|
||
|
||
public void Block(DateTime? unblockTime)
|
||
{
|
||
TrySend(new MessageItem(SystemMessageType.OperationBlocked, content: "很抱歉,您的账户已经被封锁,暂时无法在聊天室暂住。封锁解除时间:" + (unblockTime == null ? "无限期" : unblockTime.Value.ToString())));
|
||
Close(CloseReason.TimeOut);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Called when [session closed].
|
||
/// </summary>
|
||
/// <param name="reason">The reason.</param>
|
||
protected override void OnSessionClosed(CloseReason reason)
|
||
{
|
||
base.OnSessionClosed(reason);
|
||
|
||
//更新统计
|
||
if (_connectId > 0)
|
||
{
|
||
var elapsed = (int)(DateTime.Now - _connecTime).TotalSeconds;
|
||
var db = new ChatDb();
|
||
|
||
db.Database.ExecuteSqlCommand("UPDATE Chat_UserConnectLog SET DisconnectTime=GETDATE(), ElapsedTime={1} WHERE Id={0}", _connectId, elapsed);
|
||
db.Database.ExecuteSqlCommand("UPDATE Chat_User SET OnlineTime=OnlineTime+{1} WHERE UserName={0}", UserName, elapsed);
|
||
}
|
||
}
|
||
|
||
public bool TrySend(MessageItem message)
|
||
{
|
||
var buffer = message.ToBuffer();
|
||
var value = TrySend(buffer, 0, buffer.Length);
|
||
|
||
if (!value)
|
||
{
|
||
_log.Warn($"数据发送失败!连接ID={SessionID}");
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
public void ProcessData(byte[] data)
|
||
{
|
||
if (IsBlocked())
|
||
return;
|
||
|
||
MessageItem item;
|
||
try
|
||
{
|
||
item = MessageItem.Decode(data);
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (item.From == null || item.From.UserName.IsNullOrEmpty())
|
||
{
|
||
item.From = new MessageUser(UserName, NickName);
|
||
}
|
||
|
||
if (item.SystemMessage)
|
||
{
|
||
ProcessSystemMessage(item);
|
||
}
|
||
else
|
||
{
|
||
ProcessUserMessage(item);
|
||
}
|
||
}
|
||
|
||
void ProcessSystemMessage(MessageItem item)
|
||
{
|
||
switch (item.SysMsgType)
|
||
{
|
||
case SystemMessageType.UserEnter:
|
||
break;
|
||
case SystemMessageType.UserExit:
|
||
break;
|
||
case SystemMessageType.Disconnect:
|
||
break;
|
||
case SystemMessageType.UpdateStat:
|
||
break;
|
||
case SystemMessageType.SendFailed:
|
||
break;
|
||
case SystemMessageType.UpdateOnlineCount:
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void ProcessUserMessage(MessageItem item)
|
||
{
|
||
switch (item.UserMsgType)
|
||
{
|
||
case UserMessageType.Send:
|
||
|
||
//check username
|
||
if (item.ToUsers != null && item.ToUsers.Length > 0)
|
||
{
|
||
var notOnlineUsers = item.ToUsers.Where(x => !RoomContainer.IsUserInRoom(x.UserName)).ToArray();
|
||
if (!notOnlineUsers.IsEmpty())
|
||
{
|
||
item.Content += $"【系统提示:用户 {notOnlineUsers.Select(s => s.NickName).JoinAsString("、")} 已不在线。】";
|
||
}
|
||
}
|
||
|
||
//log to db
|
||
var db = new ChatDb();
|
||
var msg = new MsgLog()
|
||
{
|
||
AtUser = item.ToUsers?.Select(s => s.UserName).JoinAsString(";"),
|
||
Color = item.Color,
|
||
Image = item.Images?.JoinAsString(";"),
|
||
Content = item.Content,
|
||
Ip = RemoteEndPoint.ToString(),
|
||
RoomId = PathSegements[1],
|
||
SendTime = item.Time,
|
||
UserName = UserName
|
||
};
|
||
db.MsgLogs.Add(msg);
|
||
db.SaveChanges();
|
||
item.Id = msg.Id;
|
||
|
||
//更新统计
|
||
db.Database.ExecuteSqlCommand("UPDATE Chat_User SET LastSend=GETDATE(), FirstSend=ISNULL(FirstSend, GETDATE()), SendTimes=SendTimes+1 WHERE UserName={0}", UserName);
|
||
|
||
OnRequireSendMessage(item, false);
|
||
break;
|
||
case UserMessageType.Receive:
|
||
break;
|
||
case UserMessageType.ReportAbuse:
|
||
ProcessReport(item.Content.ToInt64());
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
async void ProcessReport(long msgid)
|
||
{
|
||
if (msgid <= 0)
|
||
return;
|
||
|
||
var db = new ChatDb();
|
||
//查找当前用户资料
|
||
var currentUser = db.Users.Find(UserName);
|
||
if (currentUser.DisableAbuseReport)
|
||
{
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: false, content: "很抱歉,管理员已暂时关闭了您的举报权限。"));
|
||
return;
|
||
}
|
||
if (currentUser.AbuseReportSuccRate < 0.1)
|
||
{
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: false, content: "很抱歉,您当前举报成功率过低(<0.2),系统暂时不接受您新的举报。已有举报未通过审核时,请等待管理员审核。"));
|
||
return;
|
||
}
|
||
|
||
|
||
//此消息是否已经被举报过了?
|
||
if (db.AbuseReports.Any(s => s.TargetId == msgid && s.ReportUser == UserName))
|
||
{
|
||
//重复举报
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: false, content: "这条消息您已经举报过哦,请不要重复举报消息。"));
|
||
return;
|
||
}
|
||
|
||
var msg = db.MsgLogs.Find(msgid);
|
||
if (msg == null)
|
||
return;
|
||
var dispName = db.Users.Find(msg.UserName)?.NickName ?? "";
|
||
|
||
//是否已经有屏蔽记录了?
|
||
currentUser.AbuseReportCount++;
|
||
|
||
var currentRule = db.GetBlockRuleForUser(msg.UserName).LastOrDefault();
|
||
if (currentRule != null)
|
||
{
|
||
|
||
if (currentRule.UnblockTime != null)
|
||
{
|
||
currentUser.AbuseReportSuccCount++;
|
||
|
||
db.AbuseReports.Add(new AbuseReport()
|
||
{
|
||
ReportTime = DateTime.Now,
|
||
ReportUser = UserName,
|
||
Status = ReportState.AutoProcessed,
|
||
TargetId = msgid,
|
||
TargetUser = msg.UserName
|
||
});
|
||
|
||
//如果是隔期解开的,那么将会延长十五分钟
|
||
var extra = _isAdmin ? 300 : 15;
|
||
currentRule.UnblockTime = currentRule.UnblockTime.Value.AddMinutes(_isAdmin ? 300 : 15);
|
||
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"您已举报成功。由于您的添砖加瓦,用户【{dispName}({msg.UserName})】将会在小黑屋中多享受 {extra} 分钟的幸福时光。(您已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"));
|
||
|
||
OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"{currentUser.NickName} 已经举报成功。由于TA的添砖加瓦,用户【{dispName}({msg.UserName})】将会在小黑屋中多享受 {extra} 分钟的幸福时光。({currentUser.NickName} 已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"), true);
|
||
|
||
db.SaveChanges();
|
||
}
|
||
else
|
||
{
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"无需举报,用户【{dispName}({msg.UserName})】已经暂时不会从小黑屋里粗来了"));
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
//没有处于屏蔽状态,则
|
||
var rlog = new AbuseReport()
|
||
{
|
||
ReportTime = DateTime.Now,
|
||
ReportUser = UserName,
|
||
Status = _isAdmin ? ReportState.AutoProcessed : ReportState.Submited,
|
||
TargetId = msgid,
|
||
TargetUser = msg.UserName
|
||
};
|
||
db.AbuseReports.Add(rlog);
|
||
db.SaveChanges();
|
||
|
||
//自动处理
|
||
//如果是管理员,则自动禁言两个小时
|
||
var blocked = false;
|
||
var currentReportCount = 0;
|
||
DateTime? unblockTime = null;
|
||
if (_isAdmin)
|
||
{
|
||
currentUser.AbuseReportSuccCount++;
|
||
|
||
currentRule = new BlockUser()
|
||
{
|
||
BlockTime = DateTime.Now,
|
||
UserName = msg.UserName,
|
||
UnblockTime = DateTime.Now.AddMinutes(300)
|
||
};
|
||
db.BlockUsers.Add(currentRule);
|
||
unblockTime = currentRule.UnblockTime;
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"您已将用户【{dispName}({msg.UserName})】请到小黑屋里享受幸福至少五个小时。如果有更多人举报,呆的时间将会延长。(您已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"));
|
||
OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"用户【{dispName}({msg.UserName})】已经被管理员 {currentUser.NickName} 请到小黑屋里享受幸福至少五个小时。如果有更多人举报,呆的时间将会延长。({currentUser.NickName} 已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"), true);
|
||
|
||
blocked = true;
|
||
}
|
||
else if ((currentReportCount = db.GetUserAbuseReportCountInTime(msg.UserName, 15)) > 5)
|
||
{
|
||
currentUser.AbuseReportSuccCount++;
|
||
|
||
currentRule = new BlockUser()
|
||
{
|
||
BlockTime = DateTime.Now,
|
||
UserName = msg.UserName,
|
||
UnblockTime = DateTime.Now.AddMinutes(30)
|
||
};
|
||
db.BlockUsers.Add(currentRule);
|
||
unblockTime = currentRule.UnblockTime;
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"您的举报已经触发自动处理规则,用户【{dispName}({msg.UserName})】将被请到小黑屋里享受幸福至少十五分钟。(您已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"));
|
||
OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"【{currentUser.NickName}】 对【{dispName}({msg.UserName})】的举报已经满足自动处理规则,{dispName} 将会被请到小黑屋里享受幸福至少十五分钟。如果有更多人举报,呆的时间将会延长。({currentUser.NickName} 已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"), true);
|
||
|
||
blocked = true;
|
||
}
|
||
else
|
||
{
|
||
TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"举报成功,等待管理员审核。用户【{dispName}({msg.UserName})】在过去的十五分钟时间内已经被举报 {currentReportCount} 次,如果达到五次将会被自动封禁。(您已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"));
|
||
OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"【{currentUser.NickName}】 对【{dispName}({msg.UserName})】的举报已记录。用户【{dispName}({msg.UserName})】在过去的十五分钟时间内已经被举报 {currentReportCount} 次,如果达到五次将会被自动封禁。({currentUser.NickName} 已举报 {currentUser.AbuseReportCount}次,成功 {currentUser.AbuseReportSuccCount}次,成功率 {currentUser.AbuseReportSuccRate:P1})"), true);
|
||
}
|
||
await db.SaveChangesAsync();
|
||
|
||
//即时封锁
|
||
if (blocked)
|
||
{
|
||
//自动标记之前的举报
|
||
await db.MarkProcessedAbuseReportAsync(msg.UserName, 3);
|
||
|
||
(AppServer as ChatServer).AddBlockUser(msg.UserName, unblockTime);
|
||
}
|
||
}
|
||
|
||
public event EventHandler<RequireSendMessageEventArgs> RequireSendMessage;
|
||
|
||
protected virtual void OnRequireSendMessage(MessageItem e, bool excludeSender)
|
||
{
|
||
RequireSendMessage?.Invoke(this, new RequireSendMessageEventArgs(excludeSender, e));
|
||
}
|
||
}
|
||
}
|