From 5bf5699a51c7352aeeeec3676eb5526d0c96ec9f Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Sat, 28 Sep 2024 17:34:51 +0300 Subject: [PATCH] add comments --- Lab1/ChatRoom/ChatRoomLogic.cs | 100 ++++++++++++++++++++-- Lab1/ChatRoom/ChatRoomService.cs | 8 +- Lab1/ChatRoom/ChatRoomState.cs | 48 ++++++++++- Lab1/ChatRoomContract/IChatRoomService.cs | 51 +++++++++++ 4 files changed, 199 insertions(+), 8 deletions(-) diff --git a/Lab1/ChatRoom/ChatRoomLogic.cs b/Lab1/ChatRoom/ChatRoomLogic.cs index edf352f..6481d92 100644 --- a/Lab1/ChatRoom/ChatRoomLogic.cs +++ b/Lab1/ChatRoom/ChatRoomLogic.cs @@ -1,21 +1,38 @@ -using Castle.DynamicProxy.Generators.Emitters.SimpleAST; -using NLog; +using NLog; namespace ChatRoom; +/// +/// Chat room service logic +/// public class ChatRoomLogic { + /// + /// Background thread of deleting approved or rejected messages + /// private Thread thread; + /// + /// Chat Room state + /// private ChatRoomState state = new ChatRoomState(); + /// + /// Logger + /// private Logger log = LogManager.GetCurrentClassLogger(); - + /// + /// Chat room logic constructor + /// public ChatRoomLogic() { thread = new Thread(BackgroundTask); thread.Start(); } + /// + /// Generate the next incrementing ID + /// + /// Unique ID int NextId() { int id = state.lastUniqueId; @@ -23,6 +40,11 @@ public class ChatRoomLogic return id; } + /// + /// Register a client + /// + /// Client name + /// Client ID public int RegisterClient(string name) { lock (state.accessLock) @@ -38,6 +60,11 @@ public class ChatRoomLogic } } + /// + /// Find a client by ID, can return NULL if not found + /// + /// Client ID + /// Optional client object Client? FindClientById(int clientId) { foreach (var client in state.clients) @@ -50,6 +77,11 @@ public class ChatRoomLogic return null; } + /// + /// Find message by ID, can return NULL if not found + /// + /// Message ID + /// Optional message object Message? FindMessageById(int messageId) { foreach (var message in state.messages) @@ -61,7 +93,12 @@ public class ChatRoomLogic } return null; } - + + /// + /// Check if client is still blocked, will clear `blockedUntil` if client became unblocked + /// + /// Client object + /// Is client blocked? bool GetAndUpdateBlockedState(Client client) { if (client.blockedUntil != null && DateTime.UtcNow >= client.blockedUntil) @@ -72,6 +109,13 @@ public class ChatRoomLogic return client.blockedUntil != null; } + /// + /// Send a message + /// + /// Client ID + /// Message contents + /// Does this message need to be censored? + /// Was sending the message successful, can fail if client is blocked public bool SendMessage(int clientId, string contents, bool needsToBeCensored) { lock (state.accessLock) @@ -93,7 +137,8 @@ public class ChatRoomLogic clientId = clientId, contents = contents, needsToBeCensored = needsToBeCensored, - status = MessageStatus.WaitingForModerator + status = MessageStatus.WaitingForModerator, + sentAt = DateTime.UtcNow }; state.messages.Add(message); log.Info($"Client '{client.name}' ({client.id}) sent message '{contents}' ({message.id}). Needs to censored: {needsToBeCensored}"); @@ -102,6 +147,10 @@ public class ChatRoomLogic return true; } + /// + /// Get next message which isin't approved or rejected + /// + /// Optional message object public ChatRoomContract.Message? GetNewMessage() { lock (state.accessLock) @@ -123,6 +172,10 @@ public class ChatRoomLogic return null; } + /// + /// Approve a message + /// + /// Message ID public void ApproveMessage(int messageId) { lock (state.accessLock) @@ -143,6 +196,10 @@ public class ChatRoomLogic } } + /// + /// Reject a message + /// + /// Message ID public void RejectMessage(int messageId) { lock (state.accessLock) @@ -177,6 +234,11 @@ public class ChatRoomLogic } } + /// + /// Get number of strikes a client has + /// + /// Client ID + /// Number of strikes public int GetStrikes(int clientId) { lock (state.accessLock) @@ -191,13 +253,39 @@ public class ChatRoomLogic } } + /// + /// Get timestamp until when the client is blocked + /// + /// Client ID + /// Optional datetime object + public DateTime? GetBlockedUntil(int clientId) + { + lock (state.accessLock) + { + var client = FindClientById(clientId); + if (client == null) + { + return null; + } + + return client.blockedUntil; + } + } + + /// + /// Main loop for background thread. Used for deleting approved or rejected messages. + /// public void BackgroundTask() { while (true) { lock (state.accessLock) { - int count = state.messages.RemoveAll(msg => msg.status == MessageStatus.Approved || msg.status == MessageStatus.Rejected); + var now = DateTime.UtcNow; + int count = state.messages.RemoveAll(msg => + (now - msg.sentAt).TotalSeconds > 5 && + (msg.status == MessageStatus.Approved || msg.status == MessageStatus.Rejected) + ); log.Info($"Running periodic cleanup, removed {count} messages"); } diff --git a/Lab1/ChatRoom/ChatRoomService.cs b/Lab1/ChatRoom/ChatRoomService.cs index 0fca3e1..938c303 100644 --- a/Lab1/ChatRoom/ChatRoomService.cs +++ b/Lab1/ChatRoom/ChatRoomService.cs @@ -1,4 +1,5 @@ -namespace ChatRoom; + +namespace ChatRoom; public class ChatRoomService : ChatRoomContract.IChatRoomService { @@ -34,4 +35,9 @@ public class ChatRoomService : ChatRoomContract.IChatRoomService { return logic.SendMessage(clientId, contents, needsToBeCensored); } + + public DateTime? GetBlockedUntil(int clientId) + { + return logic.GetBlockedUntil(clientId); + } } diff --git a/Lab1/ChatRoom/ChatRoomState.cs b/Lab1/ChatRoom/ChatRoomState.cs index fb4d6c6..4e6f3c2 100644 --- a/Lab1/ChatRoom/ChatRoomState.cs +++ b/Lab1/ChatRoom/ChatRoomState.cs @@ -1,14 +1,31 @@ namespace ChatRoom; +/// +/// Client information +/// public class Client { + /// + /// Client ID + /// public int id; + /// + /// Client name, can be the same between multiple clients + /// public string name; + /// + /// Number of strikes + /// public int strikes = 0; - + /// + /// Until when is this client blocked from sending messages + /// public DateTime? blockedUntil = null; } +/// +/// Describes the messages status/stage +/// public enum MessageStatus { WaitingForModerator, @@ -17,13 +34,36 @@ public enum MessageStatus Rejected } +/// +/// Message information +/// public class Message { + /// + /// Message ID + /// public int id; + /// + /// Client ID + /// public int clientId; + /// + /// Message contents + /// public string contents; + /// + /// Does this message need to be censored? + /// public bool needsToBeCensored; + /// + /// Message status/stage + /// public MessageStatus status = MessageStatus.WaitingForModerator; + + /// + /// When was this message sent + /// + public DateTime sentAt; } public class ChatRoomState @@ -38,7 +78,13 @@ public class ChatRoomState /// public int lastUniqueId; + /// + /// List of all registered clients + /// public List clients = new List(); + /// + /// List of messages + /// public List messages = new List(); } diff --git a/Lab1/ChatRoomContract/IChatRoomService.cs b/Lab1/ChatRoomContract/IChatRoomService.cs index 4eeca52..1e57a5b 100644 --- a/Lab1/ChatRoomContract/IChatRoomService.cs +++ b/Lab1/ChatRoomContract/IChatRoomService.cs @@ -1,23 +1,74 @@ namespace ChatRoomContract; +/// +/// Minimal message description +/// public class Message { + /// + /// Message ID + /// public int id; + /// + /// Message contents + /// public string contents; + /// + /// Does this message need to be censored? + /// public bool needsToBeCensored; } +/// +/// Chat room service contract +/// public interface IChatRoomService { + /// + /// Register client with a name + /// + /// Name of client, can be duplicate between clients + /// Client ID int RegisterClient(string name); + /// + /// Get number of strikes a participant has + /// + /// Client ID + /// Number of strikes int GetStrikes(int clientId); + /// + /// Get timestamp until when the client is blocked + /// + /// Client ID + /// Optional datetime object + DateTime? GetBlockedUntil(int clientId); + + /// + /// Send a message, will be given to a moderator to be approved + /// + /// Client ID + /// Message contents + /// Does this message need to be censored? + /// Was sending successful, can fail if user is blocked bool SendMessage(int clientId, string contents, bool needsToBeCensored); + /// + /// Get the next message which hasn't been approved or rejected + /// + /// Message object. Returns null if there is no message Message? GetNewMessage(); + /// + /// Reject a message + /// + /// Message ID void RejectMessage(int messageId); + /// + /// Approve a message + /// + /// Message ID void ApproveMessage(int messageId); }