sharp-chat/SharpChat/ChatContext.cs

201 lines
6.7 KiB
C#
Raw Normal View History

2022-08-30 15:00:58 +00:00
using SharpChat.Events;
using SharpChat.Flashii;
using SharpChat.Packet;
using System;
using System.Collections.Generic;
using System.Net;
2023-02-06 20:14:50 +00:00
using System.Net.Http;
2022-08-30 15:00:58 +00:00
using System.Threading;
namespace SharpChat {
public class ChatContext : IDisposable, IPacketTarget {
public bool IsDisposed { get; private set; }
2023-02-06 20:14:50 +00:00
private readonly HttpClient HttpClient;
2022-08-30 15:00:58 +00:00
public SockChatServer Server { get; }
public Timer BumpTimer { get; }
2023-02-07 14:34:31 +00:00
2022-08-30 15:00:58 +00:00
public BanManager Bans { get; }
2023-02-07 14:34:31 +00:00
public readonly object BansAccess = new();
2022-08-30 15:00:58 +00:00
public ChannelManager Channels { get; }
public UserManager Users { get; }
public ChatEventManager Events { get; }
public string TargetName => @"@broadcast";
2023-02-06 20:14:50 +00:00
public ChatContext(HttpClient httpClient, SockChatServer server) {
HttpClient = httpClient;
2022-08-30 15:00:58 +00:00
Server = server;
2023-02-07 15:01:56 +00:00
Bans = new(httpClient, this);
Users = new(this);
Channels = new(this);
Events = new(this);
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
BumpTimer = new Timer(e => FlashiiBump.SubmitAsync(HttpClient, Users.WithActiveConnections()).Wait(), null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
2022-08-30 15:00:58 +00:00
}
public void Update() {
2023-02-07 14:34:31 +00:00
lock(BansAccess)
Bans.RemoveExpired();
2022-08-30 15:00:58 +00:00
CheckPings();
}
public void BanUser(ChatUser user, DateTimeOffset? until = null, bool banIPs = false, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
2023-02-07 15:01:56 +00:00
if(until.HasValue && until.Value <= DateTimeOffset.UtcNow)
2022-08-30 15:00:58 +00:00
until = null;
2023-02-07 15:01:56 +00:00
if(until.HasValue) {
2022-08-30 15:00:58 +00:00
user.Send(new ForceDisconnectPacket(ForceDisconnectReason.Banned, until.Value));
2023-02-07 14:34:31 +00:00
lock(BansAccess) {
Bans.Add(user, until.Value);
if(banIPs)
foreach(IPAddress ip in user.RemoteAddresses)
Bans.Add(ip, until.Value);
2022-08-30 15:00:58 +00:00
}
} else
user.Send(new ForceDisconnectPacket(ForceDisconnectReason.Kicked));
user.Close();
UserLeave(user.Channel, user, reason);
}
public void HandleJoin(ChatUser user, ChatChannel chan, ChatUserSession sess) {
2023-02-07 15:01:56 +00:00
if(!chan.HasUser(user)) {
2022-08-30 15:00:58 +00:00
chan.Send(new UserConnectPacket(DateTimeOffset.Now, user));
Events.Add(new UserConnectEvent(DateTimeOffset.Now, user, chan));
}
sess.Send(new AuthSuccessPacket(user, chan, sess));
sess.Send(new ContextUsersPacket(chan.GetUsers(new[] { user })));
IEnumerable<IChatEvent> msgs = Events.GetTargetLog(chan);
foreach(IChatEvent msg in msgs)
sess.Send(new ContextMessagePacket(msg));
sess.Send(new ContextChannelsPacket(Channels.OfHierarchy(user.Rank)));
2023-02-07 15:01:56 +00:00
if(!chan.HasUser(user))
2022-08-30 15:00:58 +00:00
chan.UserJoin(user);
2023-02-07 15:01:56 +00:00
if(!Users.Contains(user))
2022-08-30 15:00:58 +00:00
Users.Add(user);
}
public void UserLeave(ChatChannel chan, ChatUser user, UserDisconnectReason reason = UserDisconnectReason.Leave) {
user.Status = ChatUserStatus.Offline;
2023-02-07 15:01:56 +00:00
if(chan == null) {
2022-08-30 15:00:58 +00:00
foreach(ChatChannel channel in user.GetChannels()) {
UserLeave(channel, user, reason);
}
return;
}
2023-02-07 15:01:56 +00:00
if(chan.IsTemporary && chan.Owner == user)
2022-08-30 15:00:58 +00:00
Channels.Remove(chan);
chan.UserLeave(user);
chan.Send(new UserDisconnectPacket(DateTimeOffset.Now, user, reason));
Events.Add(new UserDisconnectEvent(DateTimeOffset.Now, user, chan, reason));
}
public void SwitchChannel(ChatUser user, ChatChannel chan, string password) {
2023-02-07 15:01:56 +00:00
if(user.CurrentChannel == chan) {
2022-08-30 15:00:58 +00:00
//user.Send(true, @"samechan", chan.Name);
user.ForceChannel();
return;
}
2023-02-07 15:01:56 +00:00
if(!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.Owner != user) {
if(chan.Rank > user.Rank) {
2022-08-30 15:00:58 +00:00
user.Send(new LegacyCommandResponse(LCR.CHANNEL_INSUFFICIENT_HIERARCHY, true, chan.Name));
user.ForceChannel();
return;
}
2023-02-07 15:01:56 +00:00
if(chan.Password != password) {
2022-08-30 15:00:58 +00:00
user.Send(new LegacyCommandResponse(LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
user.ForceChannel();
return;
}
}
ForceChannelSwitch(user, chan);
}
public void ForceChannelSwitch(ChatUser user, ChatChannel chan) {
2023-02-07 15:01:56 +00:00
if(!Channels.Contains(chan))
2022-08-30 15:00:58 +00:00
return;
ChatChannel oldChan = user.CurrentChannel;
oldChan.Send(new UserChannelLeavePacket(user));
Events.Add(new UserChannelLeaveEvent(DateTimeOffset.Now, user, oldChan));
chan.Send(new UserChannelJoinPacket(user));
Events.Add(new UserChannelJoinEvent(DateTimeOffset.Now, user, chan));
user.Send(new ContextClearPacket(chan, ContextClearMode.MessagesUsers));
user.Send(new ContextUsersPacket(chan.GetUsers(new[] { user })));
IEnumerable<IChatEvent> msgs = Events.GetTargetLog(chan);
2023-02-07 15:01:56 +00:00
foreach(IChatEvent msg in msgs)
2022-08-30 15:00:58 +00:00
user.Send(new ContextMessagePacket(msg));
user.ForceChannel(chan);
oldChan.UserLeave(user);
chan.UserJoin(user);
2023-02-07 15:01:56 +00:00
if(oldChan.IsTemporary && oldChan.Owner == user)
2022-08-30 15:00:58 +00:00
Channels.Remove(oldChan);
}
public void CheckPings() {
lock(Users)
2023-02-07 15:01:56 +00:00
foreach(ChatUser user in Users.All()) {
2022-08-30 15:00:58 +00:00
IEnumerable<ChatUserSession> timedOut = user.GetDeadSessions();
foreach(ChatUserSession sess in timedOut) {
user.RemoveSession(sess);
sess.Dispose();
Logger.Write($@"Nuked session {sess.Id} from {user.Username} (timeout)");
}
if(!user.HasSessions)
UserLeave(null, user, UserDisconnectReason.TimeOut);
}
}
public void Send(IServerPacket packet) {
2023-02-07 15:01:56 +00:00
foreach(ChatUser user in Users.All())
2022-08-30 15:00:58 +00:00
user.Send(packet);
}
2023-02-06 20:14:50 +00:00
~ChatContext() {
DoDispose();
}
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
public void Dispose() {
DoDispose();
GC.SuppressFinalize(this);
}
2022-08-30 15:00:58 +00:00
2023-02-06 20:14:50 +00:00
private void DoDispose() {
2023-02-07 15:01:56 +00:00
if(IsDisposed)
2022-08-30 15:00:58 +00:00
return;
IsDisposed = true;
BumpTimer?.Dispose();
Events?.Dispose();
Channels?.Dispose();
Users?.Dispose();
Bans?.Dispose();
}
}
}