Split connection classes.
This commit is contained in:
parent
12e7bd2768
commit
968df2b161
6 changed files with 114 additions and 84 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
37
SharpChatCommon/ConnectionInfo.cs
Normal file
37
SharpChatCommon/ConnectionInfo.cs
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<SockChatConnectionInfo> Connections = new();
|
||||
private readonly HashSet<SockChatConnectionInfo> AuthedConnections = new();
|
||||
private readonly Dictionary<long, HashSet<SockChatConnectionInfo>> UserConnections = new();
|
||||
private readonly HashSet<ConnectionInfo> Connections = new();
|
||||
private readonly HashSet<ConnectionInfo> AuthedConnections = new();
|
||||
private readonly Dictionary<long, HashSet<ConnectionInfo>> 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<SockChatConnectionInfo> body) {
|
||||
foreach(SockChatConnectionInfo conn in Connections)
|
||||
public void WithAll(Action<ConnectionInfo> body) {
|
||||
foreach(ConnectionInfo conn in Connections)
|
||||
body(conn);
|
||||
}
|
||||
|
||||
public void WithAuthed(Action<SockChatConnectionInfo> body) {
|
||||
foreach(SockChatConnectionInfo conn in AuthedConnections)
|
||||
public void WithAuthed(Action<ConnectionInfo> body) {
|
||||
foreach(ConnectionInfo conn in AuthedConnections)
|
||||
body(conn);
|
||||
}
|
||||
|
||||
public SockChatConnectionInfo[] GetTimedOut() {
|
||||
List<SockChatConnectionInfo> conns = new();
|
||||
public ConnectionInfo[] GetTimedOut() {
|
||||
List<ConnectionInfo> 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<SockChatConnectionInfo>();
|
||||
return Array.Empty<ConnectionInfo>();
|
||||
|
||||
return UserConnections[userId].ToArray();
|
||||
}
|
||||
|
||||
public SockChatConnectionInfo[] GetUser(UserInfo userInfo) {
|
||||
public ConnectionInfo[] GetUser(UserInfo userInfo) {
|
||||
return GetUser(userInfo.UserId);
|
||||
}
|
||||
|
||||
public void WithUser(long userId, Action<SockChatConnectionInfo> body) {
|
||||
public void WithUser(long userId, Action<ConnectionInfo> 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<SockChatConnectionInfo> body) {
|
||||
public void WithUser(UserInfo userInfo, Action<ConnectionInfo> body) {
|
||||
WithUser(userInfo.UserId, body);
|
||||
}
|
||||
|
||||
public string[] GetAllRemoteAddresses() {
|
||||
HashSet<string> 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<string> 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<string> 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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue