Compare commits
No commits in common. "02e35eac48c2b412a914ed26df9f391ecda5ceb7" and "dee39d988d0e8ea1d1c31c2797f9dc065000dfe2" have entirely different histories.
02e35eac48
...
dee39d988d
@ -1,35 +1,26 @@
|
|||||||
using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
|
using NLog;
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace ChatRoom;
|
namespace ChatRoom;
|
||||||
|
|
||||||
public class ChatRoomLogic
|
public class ChatRoomLogic
|
||||||
{
|
{
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
private ChatRoomState state = new ChatRoomState();
|
private ChatRoomState state = new ChatRoomState();
|
||||||
private Logger log = LogManager.GetCurrentClassLogger();
|
private Logger log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
|
||||||
public ChatRoomLogic()
|
public ChatRoomLogic()
|
||||||
{
|
{
|
||||||
thread = new Thread(BackgroundTask);
|
thread = new Thread(BackgroundTask);
|
||||||
thread.Start();
|
thread.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
int NextId()
|
|
||||||
{
|
|
||||||
int id = state.lastUniqueId;
|
|
||||||
state.lastUniqueId++;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RegisterClient(string name)
|
public int RegisterClient(string name)
|
||||||
{
|
{
|
||||||
lock (state.accessLock)
|
lock (state.accessLock)
|
||||||
{
|
{
|
||||||
int clientId = NextId();
|
int clientId = state.lastUniqueId;
|
||||||
state.clients.Add(new Client
|
state.clients.Add(new Client{
|
||||||
{
|
|
||||||
id = clientId,
|
id = clientId,
|
||||||
name = name
|
name = name
|
||||||
});
|
});
|
||||||
@ -38,170 +29,11 @@ public class ChatRoomLogic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Client? FindClientById(int clientId)
|
|
||||||
{
|
|
||||||
foreach (var client in state.clients)
|
|
||||||
{
|
|
||||||
if (client.id == clientId)
|
|
||||||
{
|
|
||||||
return client;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Message? FindMessageById(int messageId)
|
|
||||||
{
|
|
||||||
foreach (var message in state.messages)
|
|
||||||
{
|
|
||||||
if (message.id == messageId)
|
|
||||||
{
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetAndUpdateBlockedState(Client client)
|
|
||||||
{
|
|
||||||
if (client.blockedUntil != null && DateTime.UtcNow >= client.blockedUntil)
|
|
||||||
{
|
|
||||||
client.blockedUntil = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.blockedUntil != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SendMessage(int clientId, string contents, bool needsToBeCensored)
|
|
||||||
{
|
|
||||||
lock (state.accessLock)
|
|
||||||
{
|
|
||||||
var client = FindClientById(clientId);
|
|
||||||
if (client == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GetAndUpdateBlockedState(client))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var message = new Message
|
|
||||||
{
|
|
||||||
id = NextId(),
|
|
||||||
clientId = clientId,
|
|
||||||
contents = contents,
|
|
||||||
needsToBeCensored = needsToBeCensored,
|
|
||||||
status = MessageStatus.WaitingForModerator
|
|
||||||
};
|
|
||||||
state.messages.Add(message);
|
|
||||||
log.Info($"Client '{client.name}' ({client.id}) sent message '{contents}' ({message.id}). Needs to censored: {needsToBeCensored}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChatRoomContract.Message? GetNewMessage()
|
|
||||||
{
|
|
||||||
lock (state.accessLock)
|
|
||||||
{
|
|
||||||
foreach (var message in state.messages)
|
|
||||||
{
|
|
||||||
if (message.status != MessageStatus.WaitingForModerator) continue;
|
|
||||||
|
|
||||||
log.Info($"Message '{message.id}' given to moderator");
|
|
||||||
message.status = MessageStatus.GivenToModerator;
|
|
||||||
return new ChatRoomContract.Message{
|
|
||||||
id = message.id,
|
|
||||||
contents = message.contents,
|
|
||||||
needsToBeCensored = message.needsToBeCensored
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ApproveMessage(int messageId)
|
|
||||||
{
|
|
||||||
lock (state.accessLock)
|
|
||||||
{
|
|
||||||
var message = FindMessageById(messageId);
|
|
||||||
if (message == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.status != MessageStatus.GivenToModerator)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.status = MessageStatus.Approved;
|
|
||||||
log.Info($"Message {message.id} was approved");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RejectMessage(int messageId)
|
|
||||||
{
|
|
||||||
lock (state.accessLock)
|
|
||||||
{
|
|
||||||
var message = FindMessageById(messageId);
|
|
||||||
if (message == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message.status != MessageStatus.GivenToModerator)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
message.status = MessageStatus.Rejected;
|
|
||||||
log.Info($"Message {message.id} was rejected");
|
|
||||||
|
|
||||||
var client = FindClientById(message.clientId);
|
|
||||||
if (client != null && !GetAndUpdateBlockedState(client))
|
|
||||||
{
|
|
||||||
client.strikes++;
|
|
||||||
|
|
||||||
var rnd = new Random();
|
|
||||||
if (client.strikes > rnd.Next(0, 10))
|
|
||||||
{
|
|
||||||
log.Info($"Client '{client.name}' ({client.id}) was blocked for {client.strikes}s");
|
|
||||||
client.blockedUntil = DateTime.UtcNow.AddSeconds(client.strikes);
|
|
||||||
client.strikes = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetStrikes(int clientId)
|
|
||||||
{
|
|
||||||
lock (state.accessLock)
|
|
||||||
{
|
|
||||||
var client = FindClientById(clientId);
|
|
||||||
if (client == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.strikes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void BackgroundTask()
|
public void BackgroundTask()
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
lock (state.accessLock)
|
|
||||||
{
|
|
||||||
int count = state.messages.RemoveAll(msg => msg.status == MessageStatus.Approved || msg.status == MessageStatus.Rejected);
|
|
||||||
log.Info($"Running periodic cleanup, removed {count} messages");
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(10 * 1000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
namespace ChatRoom;
|
namespace ChatRoom;
|
||||||
|
|
||||||
public class ChatRoomService : ChatRoomContract.IChatRoomService
|
using ChatRoomContract;
|
||||||
|
|
||||||
|
public class ChatRoomService : IChatRoomService
|
||||||
{
|
{
|
||||||
//NOTE: instance-per-request service would need logic to be static or injected from a singleton instance
|
//NOTE: instance-per-request service would need logic to be static or injected from a singleton instance
|
||||||
private readonly ChatRoomLogic logic = new ChatRoomLogic();
|
private readonly ChatRoomLogic logic = new ChatRoomLogic();
|
||||||
@ -12,26 +14,26 @@ public class ChatRoomService : ChatRoomContract.IChatRoomService
|
|||||||
|
|
||||||
public void ApproveMessage(int messageId)
|
public void ApproveMessage(int messageId)
|
||||||
{
|
{
|
||||||
logic.ApproveMessage(messageId);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatRoomContract.Message? GetNewMessage()
|
public Message? GetNewMessage()
|
||||||
{
|
{
|
||||||
return logic.GetNewMessage();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetStrikes(int clientId)
|
public int GetStrikes(int clientId)
|
||||||
{
|
{
|
||||||
return logic.GetStrikes(clientId);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RejectMessage(int messageId)
|
public void RejectMessage(int messageId)
|
||||||
{
|
{
|
||||||
logic.RejectMessage(messageId);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SendMessage(int clientId, string contents, bool needsToBeCensored)
|
public bool SendMessage(int clientId, string contents)
|
||||||
{
|
{
|
||||||
return logic.SendMessage(clientId, contents, needsToBeCensored);
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,25 +5,6 @@ public class Client
|
|||||||
public int id;
|
public int id;
|
||||||
public string name;
|
public string name;
|
||||||
public int strikes = 0;
|
public int strikes = 0;
|
||||||
|
|
||||||
public DateTime? blockedUntil = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum MessageStatus
|
|
||||||
{
|
|
||||||
WaitingForModerator,
|
|
||||||
GivenToModerator,
|
|
||||||
Approved,
|
|
||||||
Rejected
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Message
|
|
||||||
{
|
|
||||||
public int id;
|
|
||||||
public int clientId;
|
|
||||||
public string contents;
|
|
||||||
public bool needsToBeCensored;
|
|
||||||
public MessageStatus status = MessageStatus.WaitingForModerator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ChatRoomState
|
public class ChatRoomState
|
||||||
@ -39,6 +20,4 @@ public class ChatRoomState
|
|||||||
public int lastUniqueId;
|
public int lastUniqueId;
|
||||||
|
|
||||||
public List<Client> clients = new List<Client>();
|
public List<Client> clients = new List<Client>();
|
||||||
|
|
||||||
public List<Message> messages = new List<Message>();
|
|
||||||
}
|
}
|
||||||
|
@ -66,8 +66,6 @@ public class Server
|
|||||||
/// <param name="args">Command line arguments.</param>
|
/// <param name="args">Command line arguments.</param>
|
||||||
private void StartServer(string[] args)
|
private void StartServer(string[] args)
|
||||||
{
|
{
|
||||||
Console.Title = "Chat Room";
|
|
||||||
|
|
||||||
///create web app builder
|
///create web app builder
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
public class Message
|
public class Message
|
||||||
{
|
{
|
||||||
public int id;
|
int id;
|
||||||
public string contents;
|
public string contents;
|
||||||
public bool needsToBeCensored;
|
public bool needsToBeCensored;
|
||||||
}
|
}
|
||||||
@ -13,7 +13,7 @@ public interface IChatRoomService
|
|||||||
|
|
||||||
int GetStrikes(int clientId);
|
int GetStrikes(int clientId);
|
||||||
|
|
||||||
bool SendMessage(int clientId, string contents, bool needsToBeCensored);
|
bool SendMessage(int clientId, string contents);
|
||||||
|
|
||||||
Message? GetNewMessage();
|
Message? GetNewMessage();
|
||||||
|
|
||||||
|
@ -60,23 +60,7 @@ internal class Moderator
|
|||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var message = chatRoom.GetNewMessage();
|
|
||||||
if (message != null)
|
|
||||||
{
|
|
||||||
log.Info($"Checking message ({message.id}): {message.contents}");
|
|
||||||
Thread.Sleep(500);
|
|
||||||
|
|
||||||
if (message.needsToBeCensored)
|
|
||||||
{
|
|
||||||
chatRoom.RejectMessage(message.id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
chatRoom.ApproveMessage(message.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(1 * 1000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Bogus" Version="35.6.1" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
<PackageReference Include="NLog" Version="5.3.4" />
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
<PackageReference Include="SimpleRpc" Version="1.0.0-beta1" />
|
<PackageReference Include="SimpleRpc" Version="1.0.0-beta1" />
|
||||||
|
@ -5,12 +5,25 @@ using SimpleRpc.Transports.Http.Client;
|
|||||||
using SimpleRpc.Serialization.Hyperion;
|
using SimpleRpc.Serialization.Hyperion;
|
||||||
using SimpleRpc.Transports;
|
using SimpleRpc.Transports;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Bogus;
|
|
||||||
|
|
||||||
namespace Participant;
|
namespace Participant;
|
||||||
|
|
||||||
internal class Participant
|
internal class Participant
|
||||||
{
|
{
|
||||||
|
private readonly List<string> FIRSTNAMES =
|
||||||
|
new List<string> {
|
||||||
|
"John", "Peter", "Jack", "Steve"
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A set of surnames to choose from.
|
||||||
|
/// </summary>
|
||||||
|
private readonly List<string> LASTNAMES =
|
||||||
|
new List<String> {
|
||||||
|
"Johnson", "Peterson", "Jackson", "Steveson"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logger for this class.
|
/// Logger for this class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -36,27 +49,17 @@ internal class Participant
|
|||||||
|
|
||||||
private void RunConnection(IChatRoomService chatRoom)
|
private void RunConnection(IChatRoomService chatRoom)
|
||||||
{
|
{
|
||||||
var faker = new Faker("en");
|
|
||||||
var rnd = new Random();
|
var rnd = new Random();
|
||||||
|
|
||||||
var name = faker.Name.FullName();
|
var name = FIRSTNAMES[rnd.Next(FIRSTNAMES.Count)] + " " + LASTNAMES[rnd.Next(LASTNAMES.Count)];
|
||||||
|
|
||||||
int clientId = chatRoom.RegisterClient(name);
|
int clientId = chatRoom.RegisterClient(name);
|
||||||
log.Info($"Registered with client id {clientId}");
|
log.Info($"Registered with client id {clientId}");
|
||||||
|
|
||||||
|
Console.Title = $"Participant | {name} | {clientId}";
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int strikes = chatRoom.GetStrikes(clientId);
|
|
||||||
Console.Title = $"Participant | {name} | {clientId} | {strikes} Strikes";
|
|
||||||
|
|
||||||
var message = string.Join(" ", faker.Lorem.Words(5));
|
|
||||||
bool needsToBeCensored = rnd.Next(0, 100) > 50;
|
|
||||||
if (chatRoom.SendMessage(clientId, message, needsToBeCensored)) {
|
|
||||||
log.Info("Sent message");
|
|
||||||
} else {
|
|
||||||
log.Info("Failed to send message, blocked");
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread.Sleep(2 * 1000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Bogus" Version="35.6.1" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
<PackageReference Include="NLog" Version="5.3.4" />
|
<PackageReference Include="NLog" Version="5.3.4" />
|
||||||
<PackageReference Include="SimpleRpc" Version="1.0.0-beta1" />
|
<PackageReference Include="SimpleRpc" Version="1.0.0-beta1" />
|
||||||
|
Loading…
Reference in New Issue
Block a user