208 lines
5.2 KiB
C#
208 lines
5.2 KiB
C#
using Castle.DynamicProxy.Generators.Emitters.SimpleAST;
|
|
using NLog;
|
|
|
|
namespace ChatRoom;
|
|
|
|
public class ChatRoomLogic
|
|
{
|
|
private Thread thread;
|
|
private ChatRoomState state = new ChatRoomState();
|
|
private Logger log = LogManager.GetCurrentClassLogger();
|
|
|
|
|
|
public ChatRoomLogic()
|
|
{
|
|
thread = new Thread(BackgroundTask);
|
|
thread.Start();
|
|
}
|
|
|
|
int NextId()
|
|
{
|
|
int id = state.lastUniqueId;
|
|
state.lastUniqueId++;
|
|
return id;
|
|
}
|
|
|
|
public int RegisterClient(string name)
|
|
{
|
|
lock (state.accessLock)
|
|
{
|
|
int clientId = NextId();
|
|
state.clients.Add(new Client
|
|
{
|
|
id = clientId,
|
|
name = name
|
|
});
|
|
log.Info($"Registered with client '{name}' with id {clientId}");
|
|
return clientId;
|
|
}
|
|
}
|
|
|
|
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()
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
}
|