From 968df2b1612d47dfa49e32ce3e9445a39447ea61 Mon Sep 17 00:00:00 2001 From: flashwave Date: Tue, 21 May 2024 20:08:23 +0000 Subject: [PATCH] Split connection classes. --- .../Commands/SockChatClientCommandContext.cs | 4 +- SharpChat.SockChat/SockChatConnectionInfo.cs | 61 ++++++------------- SharpChat.SockChat/SockChatContext.cs | 31 +++++++--- SharpChat.SockChat/SockChatServer.cs | 13 ++-- SharpChatCommon/ConnectionInfo.cs | 37 +++++++++++ .../ConnectionsContext.cs | 52 ++++++++-------- 6 files changed, 114 insertions(+), 84 deletions(-) create mode 100644 SharpChatCommon/ConnectionInfo.cs rename SharpChat.SockChat/SockChatConnectionsContext.cs => SharpChatCommon/ConnectionsContext.cs (69%) diff --git a/SharpChat.SockChat/Commands/SockChatClientCommandContext.cs b/SharpChat.SockChat/Commands/SockChatClientCommandContext.cs index cc28a8f..905236c 100644 --- a/SharpChat.SockChat/Commands/SockChatClientCommandContext.cs +++ b/SharpChat.SockChat/Commands/SockChatClientCommandContext.cs @@ -7,14 +7,14 @@ namespace SharpChat.SockChat.Commands { public string[] Args { get; } public SockChatContext Chat { get; } public UserInfo User { get; } - public SockChatConnectionInfo Connection { get; } + public ConnectionInfo Connection { get; } public ChannelInfo Channel { get; } public SockChatClientCommandContext( string text, SockChatContext chat, UserInfo user, - SockChatConnectionInfo connection, + ConnectionInfo connection, ChannelInfo channel ) { Chat = chat; diff --git a/SharpChat.SockChat/SockChatConnectionInfo.cs b/SharpChat.SockChat/SockChatConnectionInfo.cs index 25fafcd..0c24490 100644 --- a/SharpChat.SockChat/SockChatConnectionInfo.cs +++ b/SharpChat.SockChat/SockChatConnectionInfo.cs @@ -1,45 +1,33 @@ using Fleck; using SharpChat.SockChat.PacketsS2C; -using System; using System.Net; namespace SharpChat.SockChat { - public class SockChatConnectionInfo { + public class SockChatConnectionInfo : ConnectionInfo { public IWebSocketConnection Socket { get; } - public DateTimeOffset LastPing { get; private set; } - public long UserId { get; private set; } = 0; - - public string RemoteAddress { get; } - public ushort RemotePort { get; } - public string RemoteEndPoint { get; } - - public SockChatConnectionInfo(IWebSocketConnection sock) { - Socket = sock; - - BumpPing(); - - IPAddress remoteAddr = IPAddress.Parse(sock.ConnectionInfo.ClientIpAddress); - - if(IPAddress.IsLoopback(remoteAddr) - && sock.ConnectionInfo.Headers.ContainsKey("X-Real-IP") - && IPAddress.TryParse(sock.ConnectionInfo.Headers["X-Real-IP"], out IPAddress? realAddr)) - remoteAddr = realAddr; - - RemoteAddress = remoteAddr.ToString(); - RemotePort = (ushort)sock.ConnectionInfo.ClientPort; - RemoteEndPoint = string.Format( - RemoteAddress.Contains(':') ? "[{0}]:{1}" : "{0}:{1}", - RemoteAddress, RemotePort - ); + public SockChatConnectionInfo( + IWebSocketConnection socket, + IPAddress remoteAddr, + ushort remotePort + ) : base(remoteAddr, remotePort) { + Socket = socket; } - // please call this through ConnectionsContext - public void SetUserId(long userId) { - if(UserId > 0) - throw new InvalidOperationException("This connection is already associated with a user."); + public static SockChatConnectionInfo Create(IWebSocketConnection socket) { + IPAddress remoteAddr = IPAddress.Parse(socket.ConnectionInfo.ClientIpAddress); - UserId = userId; + if(IPAddress.IsLoopback(remoteAddr) + && socket.ConnectionInfo.Headers.ContainsKey("X-Real-IP") + && IPAddress.TryParse(socket.ConnectionInfo.Headers["X-Real-IP"], out IPAddress? realAddr)) + remoteAddr = realAddr; + + return new SockChatConnectionInfo(socket, remoteAddr, (ushort)socket.ConnectionInfo.ClientPort); + } + + public void Send(string packet) { + if(Socket.IsAvailable) + Socket.Send(packet).Wait(); } public void Send(SockChatS2CPacket packet) { @@ -48,15 +36,6 @@ namespace SharpChat.SockChat { Send(data); } - public void Send(string packet) { - if(Socket.IsAvailable) - Socket.Send(packet).Wait(); - } - - public void BumpPing() { - LastPing = DateTimeOffset.UtcNow; - } - public void Close(int code) { Socket.Close(code); } diff --git a/SharpChat.SockChat/SockChatContext.cs b/SharpChat.SockChat/SockChatContext.cs index 01b6a7b..1163edc 100644 --- a/SharpChat.SockChat/SockChatContext.cs +++ b/SharpChat.SockChat/SockChatContext.cs @@ -12,7 +12,7 @@ namespace SharpChat { public readonly SemaphoreSlim ContextAccess = new(1, 1); public ChannelsContext Channels { get; } = new(); - public SockChatConnectionsContext Connections { get; } = new(); + public ConnectionsContext Connections { get; } = new(); public UsersContext Users { get; } = new(); public IEventStorage Events { get; } public ChannelsUsersContext ChannelsUsers { get; } = new(); @@ -79,10 +79,11 @@ namespace SharpChat { } public void Update() { - SockChatConnectionInfo[] timedOut = Connections.GetTimedOut(); - foreach(SockChatConnectionInfo conn in timedOut) { + ConnectionInfo[] timedOut = Connections.GetTimedOut(); + foreach(ConnectionInfo conn in timedOut) { Connections.Remove(conn); - conn.Close(1002); + if(conn is SockChatConnectionInfo scConn) + scConn.Close(1002); Logger.Write($"<{conn.RemoteEndPoint}> Nuked timed out connection from user #{conn.UserId}."); } @@ -190,10 +191,11 @@ namespace SharpChat { } else SendTo(user, new ForceDisconnectS2CPacket()); - SockChatConnectionInfo[] conns = Connections.GetUser(user); - foreach(SockChatConnectionInfo conn in conns) { + ConnectionInfo[] conns = Connections.GetUser(user); + foreach(ConnectionInfo conn in conns) { Connections.Remove(conn); - conn.Close(1000); + if(conn is SockChatConnectionInfo scConn) + scConn.Close(1000); Logger.Write($"<{conn.RemoteEndPoint}> Nuked connection from banned user #{conn.UserId}."); } @@ -374,12 +376,18 @@ namespace SharpChat { public void Send(SockChatS2CPacket packet) { string data = packet.Pack(); - Connections.WithAuthed(conn => conn.Send(data)); + Connections.WithAuthed(conn => { + if(conn is SockChatConnectionInfo scConn) + scConn.Send(data); + }); } public void SendTo(UserInfo user, SockChatS2CPacket packet) { string data = packet.Pack(); - Connections.WithUser(user, conn => conn.Send(data)); + Connections.WithUser(user, conn => { + if(conn is SockChatConnectionInfo scConn) + scConn.Send(data); + }); } public void SendTo(ChannelInfo channel, SockChatS2CPacket packet) { @@ -389,7 +397,10 @@ namespace SharpChat { public void SendTo(ChannelInfo channel, string packet) { long[] userIds = ChannelsUsers.GetChannelUserIds(channel); foreach(long userId in userIds) - Connections.WithUser(userId, conn => conn.Send(packet)); + Connections.WithUser(userId, conn => { + if(conn is SockChatConnectionInfo scConn) + scConn.Send(packet); + }); } public void SendToUserChannels(UserInfo user, SockChatS2CPacket packet) { diff --git a/SharpChat.SockChat/SockChatServer.cs b/SharpChat.SockChat/SockChatServer.cs index 0aa2f79..05f5da3 100644 --- a/SharpChat.SockChat/SockChatServer.cs +++ b/SharpChat.SockChat/SockChatServer.cs @@ -124,7 +124,7 @@ namespace SharpChat.SockChat { return; } - SockChatConnectionInfo conn = new(sock); + SockChatConnectionInfo conn = SockChatConnectionInfo.Create(sock); Context.Connections.Add(conn); sock.OnOpen = () => OnOpen(conn); @@ -136,17 +136,17 @@ namespace SharpChat.SockChat { Logger.Write("Listening..."); } - private void OnOpen(SockChatConnectionInfo conn) { + private void OnOpen(ConnectionInfo conn) { Logger.Write($"Connection opened from {conn.RemoteEndPoint}"); Context.SafeUpdate(); } - private void OnError(SockChatConnectionInfo conn, Exception ex) { + private void OnError(ConnectionInfo conn, Exception ex) { Logger.Write($"<{conn.RemoteEndPoint}> {ex}"); Context.SafeUpdate(); } - private void OnClose(SockChatConnectionInfo conn) { + private void OnClose(ConnectionInfo conn) { Logger.Write($"Connection closed from {conn.RemoteEndPoint}"); Context.ContextAccess.Wait(); @@ -243,7 +243,10 @@ namespace SharpChat.SockChat { IsDisposed = true; IsShuttingDown = true; - Context.Connections.WithAll(conn => conn.Close(IsRestarting ? 1012 : 1001)); + Context.Connections.WithAll(conn => { + if(conn is SockChatConnectionInfo scConn) + scConn.Close(IsRestarting ? 1012 : 1001); + }); Server?.Dispose(); HttpClient?.Dispose(); diff --git a/SharpChatCommon/ConnectionInfo.cs b/SharpChatCommon/ConnectionInfo.cs new file mode 100644 index 0000000..4cfe889 --- /dev/null +++ b/SharpChatCommon/ConnectionInfo.cs @@ -0,0 +1,37 @@ +using System; +using System.Net; + +namespace SharpChat.SockChat { + public abstract class ConnectionInfo { + public DateTimeOffset LastPing { get; private set; } + + public long UserId { get; private set; } = 0; + + public string RemoteAddress { get; } + public ushort RemotePort { get; } + public string RemoteEndPoint { get; } + + public ConnectionInfo(IPAddress remoteAddr, ushort remotePort) { + BumpPing(); + + RemoteAddress = remoteAddr.ToString(); + RemotePort = remotePort; + RemoteEndPoint = string.Format( + RemoteAddress.Contains(':') ? "[{0}]:{1}" : "{0}:{1}", + RemoteAddress, RemotePort + ); + } + + // please call this through ConnectionsContext + public void SetUserId(long userId) { + if(UserId > 0) + throw new InvalidOperationException("This connection is already associated with a user."); + + UserId = userId; + } + + public void BumpPing() { + LastPing = DateTimeOffset.UtcNow; + } + } +} diff --git a/SharpChat.SockChat/SockChatConnectionsContext.cs b/SharpChatCommon/ConnectionsContext.cs similarity index 69% rename from SharpChat.SockChat/SockChatConnectionsContext.cs rename to SharpChatCommon/ConnectionsContext.cs index 82f6b12..0d18770 100644 --- a/SharpChat.SockChat/SockChatConnectionsContext.cs +++ b/SharpChatCommon/ConnectionsContext.cs @@ -3,30 +3,30 @@ using System.Collections.Generic; using System.Linq; namespace SharpChat.SockChat { - public class SockChatConnectionsContext { + public class ConnectionsContext { public static readonly TimeSpan TimeOut = TimeSpan.FromMinutes(5); - private readonly HashSet Connections = new(); - private readonly HashSet AuthedConnections = new(); - private readonly Dictionary> UserConnections = new(); + private readonly HashSet Connections = new(); + private readonly HashSet AuthedConnections = new(); + private readonly Dictionary> UserConnections = new(); - public SockChatConnectionInfo[] All => Connections.ToArray(); - public SockChatConnectionInfo[] Authed => AuthedConnections.ToArray(); + public ConnectionInfo[] All => Connections.ToArray(); + public ConnectionInfo[] Authed => AuthedConnections.ToArray(); - public void WithAll(Action body) { - foreach(SockChatConnectionInfo conn in Connections) + public void WithAll(Action body) { + foreach(ConnectionInfo conn in Connections) body(conn); } - public void WithAuthed(Action body) { - foreach(SockChatConnectionInfo conn in AuthedConnections) + public void WithAuthed(Action body) { + foreach(ConnectionInfo conn in AuthedConnections) body(conn); } - public SockChatConnectionInfo[] GetTimedOut() { - List conns = new(); + public ConnectionInfo[] GetTimedOut() { + List conns = new(); - foreach(SockChatConnectionInfo conn in Connections) + foreach(ConnectionInfo conn in Connections) if(DateTimeOffset.UtcNow - conn.LastPing > TimeOut) conns.Add(conn); @@ -49,33 +49,33 @@ namespace SharpChat.SockChat { return HasUser(userInfo.UserId); } - public SockChatConnectionInfo[] GetUser(long userId) { + public ConnectionInfo[] GetUser(long userId) { if(!UserConnections.ContainsKey(userId)) - return Array.Empty(); + return Array.Empty(); return UserConnections[userId].ToArray(); } - public SockChatConnectionInfo[] GetUser(UserInfo userInfo) { + public ConnectionInfo[] GetUser(UserInfo userInfo) { return GetUser(userInfo.UserId); } - public void WithUser(long userId, Action body) { + public void WithUser(long userId, Action body) { if(!UserConnections.ContainsKey(userId)) return; - foreach(SockChatConnectionInfo conn in UserConnections[userId]) + foreach(ConnectionInfo conn in UserConnections[userId]) body(conn); } - public void WithUser(UserInfo userInfo, Action body) { + public void WithUser(UserInfo userInfo, Action body) { WithUser(userInfo.UserId, body); } public string[] GetAllRemoteAddresses() { HashSet addrs = new(); - foreach(SockChatConnectionInfo conn in Connections) + foreach(ConnectionInfo conn in Connections) addrs.Add(conn.RemoteAddress); return addrs.ToArray(); @@ -84,7 +84,7 @@ namespace SharpChat.SockChat { public string[] GetAuthedRemoteAddresses() { HashSet addrs = new(); - foreach(SockChatConnectionInfo conn in AuthedConnections) + foreach(ConnectionInfo conn in AuthedConnections) addrs.Add(conn.RemoteAddress); return addrs.ToArray(); @@ -96,7 +96,7 @@ namespace SharpChat.SockChat { HashSet addrs = new(); - foreach(SockChatConnectionInfo conn in UserConnections[userId]) + foreach(ConnectionInfo conn in UserConnections[userId]) addrs.Add(conn.RemoteAddress); return addrs.ToArray(); @@ -106,7 +106,7 @@ namespace SharpChat.SockChat { return GetUserRemoteAddresses(userInfo.UserId); } - public void Add(SockChatConnectionInfo conn) { + public void Add(ConnectionInfo conn) { if(Connections.Contains(conn)) return; @@ -122,7 +122,7 @@ namespace SharpChat.SockChat { } } - public void Remove(SockChatConnectionInfo conn) { + public void Remove(ConnectionInfo conn) { if(Connections.Contains(conn)) Connections.Remove(conn); @@ -137,7 +137,7 @@ namespace SharpChat.SockChat { } } - public void SetUser(SockChatConnectionInfo conn, long userId) { + public void SetUser(ConnectionInfo conn, long userId) { if(!Connections.Contains(conn)) return; @@ -169,7 +169,7 @@ namespace SharpChat.SockChat { } } - public void SetUser(SockChatConnectionInfo conn, UserInfo userInfo) { + public void SetUser(ConnectionInfo conn, UserInfo userInfo) { SetUser(conn, userInfo.UserId); } }