diff --git a/ChatRoomServer.Db/ChatDb.cs b/ChatRoomServer.Db/ChatDb.cs index bafff4e..8ef04d7 100644 --- a/ChatRoomServer.Db/ChatDb.cs +++ b/ChatRoomServer.Db/ChatDb.cs @@ -63,5 +63,36 @@ namespace ChatRoomServer.Db public virtual DbSet UserConnectLogs { get; set; } public virtual DbSet BlockUsers { get; set; } + + /// + /// 异步获得指定用户的屏蔽列表 + /// + /// + /// + public Task GetBlockRuleForUserAsync(string username) + { + return BlockUsers.SqlQuery("exec usp_BlockUser_GetUserBlockRule {0}", username).ToArrayAsync(); + } + + /// + /// 异步获得指定用户的屏蔽列表 + /// + /// + /// + public BlockUser[] GetBlockRuleForUser(string username) + { + return BlockUsers.SqlQuery("exec usp_BlockUser_GetUserBlockRule {0}", username).ToArray(); + } + + /// + /// 查询指定用户在单位时间内被举报的人数 + /// + /// + /// + /// + public int GetUserAbuseReportCountInTime(string username, int minutes) + { + return Database.SqlQuery("exec usp_BlockUser_GetUserReportCount {0}, {1}", username, minutes).First(); + } } } diff --git a/ChatRoomServer.Main/ChatRoomServer.Main.csproj b/ChatRoomServer.Main/ChatRoomServer.Main.csproj index 9c607e5..f3fb904 100644 --- a/ChatRoomServer.Main/ChatRoomServer.Main.csproj +++ b/ChatRoomServer.Main/ChatRoomServer.Main.csproj @@ -79,6 +79,7 @@ + diff --git a/ChatRoomServer.Main/ChatServer.cs b/ChatRoomServer.Main/ChatServer.cs index d127656..50adc91 100644 --- a/ChatRoomServer.Main/ChatServer.cs +++ b/ChatRoomServer.Main/ChatServer.cs @@ -9,6 +9,8 @@ namespace ChatRoomServer.Main using System.Collections.Concurrent; using System.Net; using System.Timers; + using ChatRoomServer.Db; + using ChatRoomServer.Db.Entities; using ChatRoomServer.Main.Room; using FSLib.Logs.Log4Net; using FSLib.Network.Http; @@ -20,7 +22,7 @@ namespace ChatRoomServer.Main { static ILog _log; static readonly object _lockObject = new object(); - internal static HashSet PresetAdministrators = (System.Configuration.ConfigurationManager.AppSettings["chat:admin"] ?? "").Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries).ToHashSet(StringComparer.OrdinalIgnoreCase); + internal static HashSet PresetAdministrators = (System.Configuration.ConfigurationManager.AppSettings["chat:admin"] ?? "").Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries).ToHashSet(StringComparer.OrdinalIgnoreCase); static ChatServer() { @@ -31,6 +33,69 @@ namespace ChatRoomServer.Main ConcurrentDictionary _containers = new ConcurrentDictionary(); ConcurrentDictionary _roomContainers = new ConcurrentDictionary(); + #region block users + + Timer _blockUserReloadTimer; + Dictionary _blockUsers = new Dictionary(StringComparer.OrdinalIgnoreCase); + readonly object _blockUserLockObject = new object(); + + public Dictionary BlockUsers + { + get { return _blockUsers; } + } + + void ReloadBlockUsers() + { + var db = new ChatDb(); + var blockUsers = db.Database.SqlQuery("exec usp_BlockUser_GetList").ToArray(); + + lock (_blockUserLockObject) + { + _blockUsers.Clear(); + + blockUsers.ForEach(s => + { + if (!_blockUsers.ContainsKey(s.UserName)) + _blockUsers.Add(s.UserName, s.UnblockTime); + else + { + var item = _blockUsers[s.UserName]; + if (item != null && (s.UnblockTime == null || s.UnblockTime > item.Value)) + { + _blockUsers[s.UserName] = s.UnblockTime; + } + } + }); + } + + //处理连接 + GetAllSessions().ForEach(s => + { + if (_blockUsers.ContainsKey(s.UserName)) + s.Block(_blockUsers[s.UserName]); + }); + } + + public void AddBlockUser(string username, DateTime? unblockTime) + { + lock (_blockUserLockObject) + { + if (!_blockUsers.ContainsKey(username)) + _blockUsers.Add(username, unblockTime); + else + { + var item = _blockUsers[username]; + if (item != null && (unblockTime == null || unblockTime > item.Value)) + { + _blockUsers[username] = unblockTime; + } + } + + } + } + + #endregion + internal static ILog GetLogger(string name) { return LogManager.GetLogger("Server", name); @@ -48,6 +113,15 @@ namespace ChatRoomServer.Main SessionClosed += ChatServer_SessionClosed; InitOnlineCountSync(); + + //黑名单 + _blockUserReloadTimer = new Timer(1000 * 60 * 5) { AutoReset = false }; + _blockUserReloadTimer.Elapsed += (s, e) => + { + ReloadBlockUsers(); + _blockUserReloadTimer.Start(); + }; + ReloadBlockUsers(); } #region 在线人数上报 @@ -63,19 +137,18 @@ namespace ChatRoomServer.Main UploadOnlineCount(); _syncOnlineCountTimer.Start(); }; + UploadOnlineCount(); + _syncOnlineCountTimer.Start(); } void UploadOnlineCount() { var datas = _roomContainers.ToArray(); - var data = new + var data = datas.Select(s => new { - data = JsonConvert.SerializeObject(datas.Select(s => new - { - id = s.Key, - count = s.Value.SessionCount - }).ToArray()) - }; + id = s.Key, + count = s.Value.SessionCount + }).ToArray(); var client = new HttpClient(); string url; @@ -84,7 +157,7 @@ namespace ChatRoomServer.Main #else url = "http://127.0.0.1/api/room/updateOnlineCount"; #endif - var ctx = client.Create(HttpMethod.Post, url, data: data).Send(); + var ctx = client.Create(HttpMethod.Post, url, data: data, payloadType: RequestPayloadType.Json).Send(); if (ctx.IsValid()) { diff --git a/ChatRoomServer.Main/ChatSession.cs b/ChatRoomServer.Main/ChatSession.cs index e97a2b8..db5fbf7 100644 --- a/ChatRoomServer.Main/ChatSession.cs +++ b/ChatRoomServer.Main/ChatSession.cs @@ -40,6 +40,19 @@ namespace ChatRoomServer.Main /// 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]. /// @@ -58,6 +71,9 @@ namespace ChatRoomServer.Main PathSegements = path; _isAdmin = ChatServer.PresetAdministrators.Contains(UserName); + if (IsBlocked()) + return; + //更新统计 var db = new ChatDb(); BlockUser blockRule = null; @@ -74,14 +90,6 @@ namespace ChatRoomServer.Main db.Users.Add(user); } user.LastConnect = DateTime.Now; - if (user.Status == UserStatus.Blocked) - { - //查询封锁记录 - blockRule = db.BlockUsers.FirstOrDefault(s => s.UserName == UserName && s.UnblockTime == null || s.UnblockTime > DateTime.Now); - if (blockRule == null) - user.Status = UserStatus.Normal; - } - //当前连接记录 var ucl = new UserConnectLog() { UserName = UserName, @@ -95,11 +103,16 @@ namespace ChatRoomServer.Main //已经封锁? if (user.Status == UserStatus.Blocked) { - TrySend(new MessageItem(SystemMessageType.OperationBlocked, content: "很抱歉,您的账户已经被封锁,暂时无法在聊天室暂住。封锁解除时间:" + (blockRule.UnblockTime == null ? "无限期" : blockRule.UnblockTime.Value.ToString()))); - Close(CloseReason.TimeOut); + 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]. /// @@ -134,6 +147,9 @@ namespace ChatRoomServer.Main public void ProcessData(byte[] data) { + if (IsBlocked()) + return; + MessageItem item; try { @@ -185,7 +201,27 @@ namespace ChatRoomServer.Main switch (item.UserMsgType) { case UserMessageType.Send: - OnRequireSendMessage(item); + //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; @@ -207,11 +243,52 @@ namespace ChatRoomServer.Main 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 = ReportState.Submited, + Status = _isAdmin ? ReportState.AutoProcessed : ReportState.Submited, TargetId = msgid, TargetUser = msg.UserName }; @@ -219,34 +296,59 @@ namespace ChatRoomServer.Main 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; + public event EventHandler RequireSendMessage; - protected virtual void OnRequireSendMessage(MessageItem e) + protected virtual void OnRequireSendMessage(MessageItem e, bool excludeSender) { - //log to db - var db = new ChatDb(); - var msg = new MsgLog() - { - AtUser = e.ToUsers?.Select(s => s.UserName).JoinAsString(";"), - Color = e.Color, - Image = e.Images?.JoinAsString(";"), - Content = e.Content, - Ip = RemoteEndPoint.ToString(), - RoomId = PathSegements[1], - SendTime = DateTime.Now, - UserName = UserName - }; - db.MsgLogs.Add(msg); - db.SaveChanges(); - e.Id = msg.Id; - - //更新统计 - db.Database.ExecuteSqlCommand("UPDATE Chat_User SET LastSend=GETDATE(), FirstSend=ISNULL(FirstSend, GETDATE()), SendTimes=SendTimes+1 WHERE UserName={0}", UserName); - - RequireSendMessage?.Invoke(this, e); + RequireSendMessage?.Invoke(this, new RequireSendMessageEventArgs(excludeSender, e)); } } } diff --git a/ChatRoomServer.Main/RequireSendMessageEventArgs.cs b/ChatRoomServer.Main/RequireSendMessageEventArgs.cs new file mode 100644 index 0000000..7ef38f4 --- /dev/null +++ b/ChatRoomServer.Main/RequireSendMessageEventArgs.cs @@ -0,0 +1,19 @@ +namespace ChatRoomServer.Main +{ + using System; + using ChatRoomServer.Main.Entities; + + class RequireSendMessageEventArgs : EventArgs + { + public MessageItem MessageItem { get; private set; } + + public bool ExcludeSender { get; private set; } + + + public RequireSendMessageEventArgs(bool excludeSender, MessageItem messageItem) + { + ExcludeSender = excludeSender; + MessageItem = messageItem; + } + } +} \ No newline at end of file diff --git a/ChatRoomServer.Main/Room/RoomContainer.cs b/ChatRoomServer.Main/Room/RoomContainer.cs index 0866d37..2f18ae7 100644 --- a/ChatRoomServer.Main/Room/RoomContainer.cs +++ b/ChatRoomServer.Main/Room/RoomContainer.cs @@ -43,12 +43,13 @@ namespace ChatRoomServer.Main.Room session.RequireSendMessage += Session_RequireSendMessage; } - private void Session_RequireSendMessage(object sender, MessageItem e) + private void Session_RequireSendMessage(object sender, RequireSendMessageEventArgs e) { var enumerator = _contexts.GetEnumerator(); while (enumerator.MoveNext()) { - enumerator.Current.Key.TrySend(e); + if (!e.ExcludeSender || sender != enumerator.Current.Key) + enumerator.Current.Key.TrySend(e.MessageItem); } } diff --git a/ChatRoomServer.Www/Areas/Api/Controllers/RoomController.cs b/ChatRoomServer.Www/Areas/Api/Controllers/RoomController.cs index df1e67c..d0d552c 100644 --- a/ChatRoomServer.Www/Areas/Api/Controllers/RoomController.cs +++ b/ChatRoomServer.Www/Areas/Api/Controllers/RoomController.cs @@ -9,16 +9,17 @@ namespace ChatRoomServer.Www.Areas.Api.Controllers { using System.Data.Entity; using System.Threading.Tasks; - using System.Web.Mvc; using ChatRoomServer.Db; + using ChatRoomServer.Db.Entities; + using ChatRoomServer.Www.Areas.Api.Models; using Newtonsoft.Json; - [System.Web.Http.RoutePrefix("api/room")] + [RoutePrefix("api/room")] public class RoomController : ApiController { [AllowAnonymous] - [System.Web.Http.Route("list"), System.Web.Http.HttpGet, OutputCache(Duration = 600)] - public async Task GetAnnouncements() + [Route("list"), HttpGet] + public async Task GetRoomss() { var db = new ChatDb(); var items = await db.Rooms.AsNoTracking().ToArrayAsync(); @@ -38,26 +39,36 @@ namespace ChatRoomServer.Www.Areas.Api.Controllers return result; } + + [AllowAnonymous] [Route("updateOnlineCount")] [HttpPost] - public async Task UpdateOnlineCount(string data) + public async Task UpdateOnlineCount([FromBody]List idata) { - //limit to local - if (!RequestContext.IsLocal) - return "Invalid operation."; - var db = new ChatDb(); var rooms = await db.Rooms.ToDictionaryAsync(s => s.ID); - var idata = JsonConvert.DeserializeAnonymousType(data, System.FishLib.CollectionUtility.CreateAnymousTypeList(new { id = "", count = 0 })); foreach (var x1 in idata) { - var room = rooms.GetValue(x1.id); + var room = rooms.GetValue(x1.Id); if (room != null) - room.OnlineCount = x1.count; + { + room.OnlineCount = x1.Count; + + db.OnlineHistories.Add(new OnlineHistory() + { + Time = DateTime.Now, + RoomID = x1.Id, + OnlineCount = x1.Count + }); + } + } + //log to history + await db.SaveChangesAsync(); return "Operation succeed"; } + } } diff --git a/ChatRoomServer.Www/Areas/Api/Models/OnlineCountModel.cs b/ChatRoomServer.Www/Areas/Api/Models/OnlineCountModel.cs new file mode 100644 index 0000000..7d05d3c --- /dev/null +++ b/ChatRoomServer.Www/Areas/Api/Models/OnlineCountModel.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ChatRoomServer.Www.Areas.Api.Models +{ + public class OnlineCountModel + { + public string Id { get; set; } + + public int Count { get; set; } + } +} diff --git a/ChatRoomServer.Www/ChatRoomServer.Www.csproj b/ChatRoomServer.Www/ChatRoomServer.Www.csproj index 89a39f7..585ed5b 100644 --- a/ChatRoomServer.Www/ChatRoomServer.Www.csproj +++ b/ChatRoomServer.Www/ChatRoomServer.Www.csproj @@ -144,6 +144,7 @@ + @@ -167,7 +168,6 @@ - diff --git a/Web12306/js/platform/messageCoder.js b/Web12306/js/platform/messageCoder.js index febd422..bd196d9 100644 --- a/Web12306/js/platform/messageCoder.js +++ b/Web12306/js/platform/messageCoder.js @@ -203,7 +203,6 @@ item.toUsers.push(readMessageUser()); } } - console.log(item); return item; }; }); diff --git a/Web12306/js/ui/chat/actionCommand.js b/Web12306/js/ui/chat/actionCommand.js index bdf3cd8..3dd35fd 100644 --- a/Web12306/js/ui/chat/actionCommand.js +++ b/Web12306/js/ui/chat/actionCommand.js @@ -5,6 +5,7 @@ exports.SYS_SENDFAILED = 5; exports.SYS_UPDATEONLINECOUNT = 6; exports.SYS_OPERATIONBLOCKED = 7; + exports.SYS_REPORTABUSERESULT = 9; exports.USER_SENDMSG = 1; exports.USER_RECEIVEMSG = 2; diff --git a/Web12306/js/ui/chat/roomsession.js b/Web12306/js/ui/chat/roomsession.js index 7ca9709..be457b4 100644 --- a/Web12306/js/ui/chat/roomsession.js +++ b/Web12306/js/ui/chat/roomsession.js @@ -202,8 +202,11 @@ } } else if (msg.sysMsgType === cmds.SYS_SENDFAILED) { } else if (msg.sysMsgType === cmds.SYS_OPERATIONBLOCKED) { + mp.showMessagePopup("error", msg.content); } else if (msg.sysMsgType === cmds.SYS_UPDATEONLINECOUNT) { that.appendMessageItem(roomSysMessage({ stateIcon: "fa-info-circle", state: "system", msg: "您已离开房间,当前房间在线 " + room.onlinecount + " 人。" })); + } else if (msg.sysMsgType === cmds.SYS_REPORTABUSERESULT) { + that.appendMessageItem(roomSysMessage({ stateIcon: "fa-info-circle", state: "system", msg: msg.content })); } }; this.processUserMessage = function (msg) { @@ -439,36 +442,25 @@ var a = $(this); var item = a.closest(".chat-item"); var chatid = parseInt(item[0].dataset.chatid); - var authorlink = item.find(".chat-item-at:eq(0)"); - var username = authorlink[0].dataset.un; + var authorlink = item.find(".chat-item-at:eq(0)")[0]; + var username = authorlink.dataset.un; if (username === '*') { mp.showMessagePopup("error", "亲,不可以举报我们伟大的管理员哦 ♪(´ε`)"); return; } - if (!confirm("确定要举报 " + (username.innerText) + " 吗?")) + if (!confirm("确定要举报 " + (authorlink.innerText) + " 吗?")) return; var data = { - sysMsgType: cmds.USER_REPORTABUSE, - content: chatid, + systemMessage: false, + userMsgType: cmds.USER_REPORTABUSE, + content: chatid + "", time: new Date() }; - var dlg = new mp.MessagePopup("loading", "举报受理中,请稍候..."); - dlg.show(); - $.post("http://12306.liebao.cn/index.php?r=Api/AbuseReport", { ar_data: JSON.stringify(reportData) }, "json").done(function (json) { - if (json.resCode !== 0) { - dlg.setState("error", "未能成功举报:" + json.message); - } else { - dlg.setState("ok", "举报已受理,感谢您的合作。"); - } - }).fail(function () { - dlg.setState("error", "未能成功举报,请稍后重试。"); - }).always(function () { - dlg.delayClose(); - }); + port.postMessage("chatRoomSendMsg", coder.encode(data)); }); $(document).on("click", "a.chat-frame-reconnect", function () { $(".chat-item").remove();