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 FSLib.Logs.Log4Net; using FSLib.Network.SuperSocket.Protocols.WebSocket; using FSLib.Network.SuperSocket.SocketBase; class ChatSession : WebSocketSession { static ILog _log = ChatServer.GetLogger(typeof(ChatSession).Name); DateTime _connecTime = DateTime.Now; long _connectId; bool _isAdmin; /// /// 路径分割 /// public string[] PathSegements { get; private set; } /// /// 命令 /// public string Command { get; private set; } public string UserName { get; private set; } public string NickName { get; private set; } /// /// ID /// public string Id { get; private set; } bool IsBlocked() { DateTime? dt = null; if ((AppServer as ChatServer).BlockUsers?.TryGetValue(UserName, out dt) == true) { Block(dt); return true; } return false; } /// /// Called when [session started]. /// 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; //已经封锁? if (user.Status == UserStatus.Blocked) { Block(blockRule.UnblockTime); } } public void Block(DateTime? unblockTime) { TrySend(new MessageItem(SystemMessageType.OperationBlocked, content: "很抱歉,您的账户已经被封锁,暂时无法在聊天室暂住。封锁解除时间:" + (unblockTime == null ? "无限期" : unblockTime.Value.ToString()))); Close(CloseReason.TimeOut); } /// /// Called when [session closed]. /// /// The reason. 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: //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 = DateTime.Now, 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; } } void ProcessReport(long msgid) { if (msgid <= 0) return; var db = new ChatDb(); var msg = db.MsgLogs.Find(msgid); if (msg == null) return; //此消息是否已经被举报过了? if (db.AbuseReports.Any(s => s.TargetId == msgid && s.ReportUser == UserName)) { //重复举报 TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: false, content: "这条消息您已经举报过哦。")); return; } //是否已经有屏蔽记录了? var currentRule = db.GetBlockRuleForUser(msg.UserName).LastOrDefault(); if (currentRule != null) { if (currentRule.UnblockTime != null) { 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: $"已经举报成功。由于您的添砖加瓦,用户【{msg.UserName}】将会在小黑屋中多享受 {extra} 分钟的幸福时光 ♪(´ε`)")); OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"已经举报成功。由于您的添砖加瓦,用户【{msg.UserName}】将会在小黑屋中多享受 {extra} 分钟的幸福时光 ♪(´ε`)"), true); db.SaveChanges(); } else { TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"无需举报,用户【{msg.UserName}】已经暂时不会从小黑屋里粗来了")); OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"无需举报,用户【{msg.UserName}】已经暂时不会从小黑屋里粗来了"), true); } 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) { 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: $"您已将用户【{msg.UserName}】请到小黑屋里享受幸福至少五个小时。如果有更多人举报,呆的时间将会延长。")); OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"用户【{msg.UserName}】已经被管理员请到小黑屋里享受幸福至少五个小时。如果有更多人举报,呆的时间将会延长。"), true); blocked = true; } else if ((currentReportCount = db.GetUserAbuseReportCountInTime(msg.UserName, 15)) > 5) { 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: $"您已将用户【{msg.UserName}】请到小黑屋里享受幸福至少十五分钟。")); OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"用户【{msg.UserName}】已经被管理员请到小黑屋里享受幸福至少十五分钟。如果有更多人举报,呆的时间将会延长。"), true); blocked = true; } else { TrySend(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"举报成功,等待管理员审核。用户【{msg.UserName}】在过去的十五分钟时间内已经被举报 {currentReportCount} 次,如果达到五次将会被自动封禁。")); OnRequireSendMessage(new MessageItem(SystemMessageType.ReportAbuseResult, success: true, content: $"用户【{msg.UserName}】在过去的十五分钟时间内已经被举报 {currentReportCount} 次,如果达到五次将会被自动封禁。"), true); } db.SaveChanges(); //即时封锁 if (blocked) { (AppServer as ChatServer).AddBlockUser(msg.UserName, unblockTime); } } public event EventHandler RequireSendMessage; protected virtual void OnRequireSendMessage(MessageItem e, bool excludeSender) { RequireSendMessage?.Invoke(this, new RequireSendMessageEventArgs(excludeSender, e)); } } }