Updated to .NET 9.0
This commit is contained in:
parent
b026bad176
commit
1c23ffbbe8
61 changed files with 344 additions and 753 deletions
SharpChat
ChatChannel.csChatColour.csChatCommandContext.csChatConnection.csChatContext.csChatPacketHandlerContext.csChatUser.cs
Commands
AFKCommand.csActionCommand.csBanListCommand.csBroadcastCommand.csCreateChannelCommand.csDeleteChannelCommand.csKickBanCommand.csNickCommand.csPardonAddressCommand.csPardonUserCommand.csRankChannelCommand.csShutdownRestartCommand.csWhisperCommand.cs
Config
EventStorage
Events
IServerPacket.csMisuzu
Packet
AuthSuccessPacket.csBanListPacket.csChannelCreatePacket.csChannelDeletePacket.csChannelUpdatePacket.csChatMessageAddPacket.csChatMessageDeletePacket.csContextChannelsPacket.csContextClearPacket.csContextMessagePacket.csContextUsersPacket.csLegacyCommandResponse.csPongPacket.csUserChannelForceJoinPacket.csUserChannelJoinPacket.csUserChannelLeavePacket.csUserConnectPacket.csUserDisconnectPacket.csUserUpdatePacket.cs
PacketHandlers
Program.csSharpChat.csprojSharpChatWebSocketServer.csSockChatServer.cs
|
@ -3,38 +3,22 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public class ChatChannel {
|
public class ChatChannel(
|
||||||
public string Name { get; }
|
string name,
|
||||||
public string Password { get; set; }
|
string password = "",
|
||||||
public bool IsTemporary { get; set; }
|
bool isTemporary = false,
|
||||||
public int Rank { get; set; }
|
int rank = 0,
|
||||||
public long OwnerId { get; set; }
|
long ownerId = 0
|
||||||
|
) {
|
||||||
|
public string Name { get; } = name ?? throw new ArgumentNullException(nameof(name));
|
||||||
|
public string Password { get; set; } = password ?? string.Empty;
|
||||||
|
public bool IsTemporary { get; set; } = isTemporary;
|
||||||
|
public int Rank { get; set; } = rank;
|
||||||
|
public long OwnerId { get; set; } = ownerId;
|
||||||
|
|
||||||
public bool HasPassword
|
public bool HasPassword
|
||||||
=> !string.IsNullOrWhiteSpace(Password);
|
=> !string.IsNullOrWhiteSpace(Password);
|
||||||
|
|
||||||
public ChatChannel(
|
|
||||||
ChatUser owner,
|
|
||||||
string name,
|
|
||||||
string password = null,
|
|
||||||
bool isTemporary = false,
|
|
||||||
int rank = 0
|
|
||||||
) : this(name, password, isTemporary, rank, owner?.UserId ?? 0) {}
|
|
||||||
|
|
||||||
public ChatChannel(
|
|
||||||
string name,
|
|
||||||
string password = null,
|
|
||||||
bool isTemporary = false,
|
|
||||||
int rank = 0,
|
|
||||||
long ownerId = 0
|
|
||||||
) {
|
|
||||||
Name = name;
|
|
||||||
Password = password ?? string.Empty;
|
|
||||||
IsTemporary = isTemporary;
|
|
||||||
Rank = rank;
|
|
||||||
OwnerId = ownerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Pack() {
|
public string Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public struct ChatColour {
|
public readonly struct ChatColour {
|
||||||
public byte Red { get; }
|
public byte Red { get; }
|
||||||
public byte Green { get; }
|
public byte Green { get; }
|
||||||
public byte Blue { get; }
|
public byte Blue { get; }
|
||||||
|
|
|
@ -17,8 +17,7 @@ namespace SharpChat {
|
||||||
ChatConnection connection,
|
ChatConnection connection,
|
||||||
ChatChannel channel
|
ChatChannel channel
|
||||||
) {
|
) {
|
||||||
if(text == null)
|
ArgumentNullException.ThrowIfNull(text);
|
||||||
throw new ArgumentNullException(nameof(text));
|
|
||||||
|
|
||||||
Chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
Chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
User = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
|
@ -27,7 +26,7 @@ namespace SharpChat {
|
||||||
|
|
||||||
string[] parts = text[1..].Split(' ');
|
string[] parts = text[1..].Split(' ');
|
||||||
Name = parts.First().Replace(".", string.Empty);
|
Name = parts.First().Replace(".", string.Empty);
|
||||||
Args = parts.Skip(1).ToArray();
|
Args = [.. parts.Skip(1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatCommandContext(
|
public ChatCommandContext(
|
||||||
|
|
|
@ -37,8 +37,8 @@ namespace SharpChat {
|
||||||
throw new Exception("Unable to parse remote address?????");
|
throw new Exception("Unable to parse remote address?????");
|
||||||
|
|
||||||
if(IPAddress.IsLoopback(addr)
|
if(IPAddress.IsLoopback(addr)
|
||||||
&& sock.ConnectionInfo.Headers.ContainsKey("X-Real-IP")
|
&& sock.ConnectionInfo.Headers.TryGetValue("X-Real-IP", out string addrStr)
|
||||||
&& IPAddress.TryParse(sock.ConnectionInfo.Headers["X-Real-IP"], out IPAddress realAddr))
|
&& IPAddress.TryParse(addrStr, out IPAddress realAddr))
|
||||||
addr = realAddr;
|
addr = realAddr;
|
||||||
|
|
||||||
RemoteAddress = addr;
|
RemoteAddress = addr;
|
||||||
|
|
|
@ -8,22 +8,18 @@ using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public class ChatContext {
|
public class ChatContext(IEventStorage evtStore) {
|
||||||
public record ChannelUserAssoc(long UserId, string ChannelName);
|
public record ChannelUserAssoc(long UserId, string ChannelName);
|
||||||
|
|
||||||
public readonly SemaphoreSlim ContextAccess = new(1, 1);
|
public readonly SemaphoreSlim ContextAccess = new(1, 1);
|
||||||
|
|
||||||
public HashSet<ChatChannel> Channels { get; } = new();
|
public HashSet<ChatChannel> Channels { get; } = [];
|
||||||
public HashSet<ChatConnection> Connections { get; } = new();
|
public HashSet<ChatConnection> Connections { get; } = [];
|
||||||
public HashSet<ChatUser> Users { get; } = new();
|
public HashSet<ChatUser> Users { get; } = [];
|
||||||
public IEventStorage Events { get; }
|
public IEventStorage Events { get; } = evtStore ?? throw new ArgumentNullException(nameof(evtStore));
|
||||||
public HashSet<ChannelUserAssoc> ChannelUsers { get; } = new();
|
public HashSet<ChannelUserAssoc> ChannelUsers { get; } = [];
|
||||||
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = new();
|
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = [];
|
||||||
public Dictionary<long, ChatChannel> UserLastChannel { get; } = new();
|
public Dictionary<long, ChatChannel> UserLastChannel { get; } = [];
|
||||||
|
|
||||||
public ChatContext(IEventStorage evtStore) {
|
|
||||||
Events = evtStore ?? throw new ArgumentNullException(nameof(evtStore));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DispatchEvent(IChatEvent eventInfo) {
|
public void DispatchEvent(IChatEvent eventInfo) {
|
||||||
if(eventInfo is MessageCreateEvent mce) {
|
if(eventInfo is MessageCreateEvent mce) {
|
||||||
|
@ -34,7 +30,7 @@ namespace SharpChat {
|
||||||
// e.g. nook sees @Arysil and Arysil sees @nook
|
// e.g. nook sees @Arysil and Arysil sees @nook
|
||||||
|
|
||||||
// this entire routine is garbage, channels should probably in the db
|
// this entire routine is garbage, channels should probably in the db
|
||||||
if(!mce.ChannelName.StartsWith("@"))
|
if(!mce.ChannelName.StartsWith('@'))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IEnumerable<long> uids = mce.ChannelName[1..].Split('-', 3).Select(u => long.TryParse(u, out long up) ? up : -1);
|
IEnumerable<long> uids = mce.ChannelName[1..].Split('-', 3).Select(u => long.TryParse(u, out long up) ? up : -1);
|
||||||
|
@ -110,21 +106,21 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetUserChannelNames(ChatUser user) {
|
public string[] GetUserChannelNames(ChatUser user) {
|
||||||
return ChannelUsers.Where(cu => cu.UserId == user.UserId).Select(cu => cu.ChannelName).ToArray();
|
return [.. ChannelUsers.Where(cu => cu.UserId == user.UserId).Select(cu => cu.ChannelName)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatChannel[] GetUserChannels(ChatUser user) {
|
public ChatChannel[] GetUserChannels(ChatUser user) {
|
||||||
string[] names = GetUserChannelNames(user);
|
string[] names = GetUserChannelNames(user);
|
||||||
return Channels.Where(c => names.Any(n => c.NameEquals(n))).ToArray();
|
return [.. Channels.Where(c => names.Any(n => c.NameEquals(n)))];
|
||||||
}
|
}
|
||||||
|
|
||||||
public long[] GetChannelUserIds(ChatChannel channel) {
|
public long[] GetChannelUserIds(ChatChannel channel) {
|
||||||
return ChannelUsers.Where(cu => channel.NameEquals(cu.ChannelName)).Select(cu => cu.UserId).ToArray();
|
return [.. ChannelUsers.Where(cu => channel.NameEquals(cu.ChannelName)).Select(cu => cu.UserId)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatUser[] GetChannelUsers(ChatChannel channel) {
|
public ChatUser[] GetChannelUsers(ChatChannel channel) {
|
||||||
long[] ids = GetChannelUserIds(channel);
|
long[] ids = GetChannelUserIds(channel);
|
||||||
return Users.Where(u => ids.Contains(u.UserId)).ToArray();
|
return [.. Users.Where(u => ids.Contains(u.UserId))];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateUser(
|
public void UpdateUser(
|
||||||
|
@ -139,11 +135,10 @@ namespace SharpChat {
|
||||||
bool? isSuper = null,
|
bool? isSuper = null,
|
||||||
bool silent = false
|
bool silent = false
|
||||||
) {
|
) {
|
||||||
if(user == null)
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
throw new ArgumentNullException(nameof(user));
|
|
||||||
|
|
||||||
bool hasChanged = false;
|
bool hasChanged = false;
|
||||||
string previousName = null;
|
string previousName = string.Empty;
|
||||||
|
|
||||||
if(userName != null && !user.UserName.Equals(userName)) {
|
if(userName != null && !user.UserName.Equals(userName)) {
|
||||||
user.UserName = userName;
|
user.UserName = userName;
|
||||||
|
@ -210,11 +205,11 @@ namespace SharpChat {
|
||||||
public void HandleJoin(ChatUser user, ChatChannel chan, ChatConnection conn, int maxMsgLength) {
|
public void HandleJoin(ChatUser user, ChatChannel chan, ChatConnection conn, int maxMsgLength) {
|
||||||
if(!IsInChannel(user, chan)) {
|
if(!IsInChannel(user, chan)) {
|
||||||
SendTo(chan, new UserConnectPacket(DateTimeOffset.Now, user));
|
SendTo(chan, new UserConnectPacket(DateTimeOffset.Now, user));
|
||||||
Events.AddEvent("user:connect", user, chan, flags: StoredEventFlags.Log);
|
Events.AddEvent(SharpId.Next(), "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.Send(new AuthSuccessPacket(user, chan, conn, maxMsgLength));
|
conn.Send(new AuthSuccessPacket(user, chan, maxMsgLength));
|
||||||
conn.Send(new ContextUsersPacket(GetChannelUsers(chan).Except(new[] { user }).OrderByDescending(u => u.Rank)));
|
conn.Send(new ContextUsersPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)));
|
||||||
|
|
||||||
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
|
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
|
||||||
conn.Send(new ContextMessagePacket(msg));
|
conn.Send(new ContextMessagePacket(msg));
|
||||||
|
@ -238,7 +233,7 @@ namespace SharpChat {
|
||||||
ChannelUsers.Remove(new ChannelUserAssoc(user.UserId, chan.Name));
|
ChannelUsers.Remove(new ChannelUserAssoc(user.UserId, chan.Name));
|
||||||
|
|
||||||
SendTo(chan, new UserDisconnectPacket(DateTimeOffset.Now, user, reason));
|
SendTo(chan, new UserDisconnectPacket(DateTimeOffset.Now, user, reason));
|
||||||
Events.AddEvent("user:disconnect", user, chan, new { reason = (int)reason }, StoredEventFlags.Log);
|
Events.AddEvent(SharpId.Next(), "user:disconnect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, new { reason = (int)reason }, StoredEventFlags.Log);
|
||||||
|
|
||||||
if(chan.IsTemporary && chan.IsOwner(user))
|
if(chan.IsTemporary && chan.IsOwner(user))
|
||||||
RemoveChannel(chan);
|
RemoveChannel(chan);
|
||||||
|
@ -275,12 +270,12 @@ namespace SharpChat {
|
||||||
ChatChannel oldChan = UserLastChannel[user.UserId];
|
ChatChannel oldChan = UserLastChannel[user.UserId];
|
||||||
|
|
||||||
SendTo(oldChan, new UserChannelLeavePacket(user));
|
SendTo(oldChan, new UserChannelLeavePacket(user));
|
||||||
Events.AddEvent("chan:leave", user, oldChan, flags: StoredEventFlags.Log);
|
Events.AddEvent(SharpId.Next(), "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||||
SendTo(chan, new UserChannelJoinPacket(user));
|
SendTo(chan, new UserChannelJoinPacket(user));
|
||||||
Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log);
|
Events.AddEvent(SharpId.Next(), "chan:join", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||||
|
|
||||||
SendTo(user, new ContextClearPacket(chan, ContextClearMode.MessagesUsers));
|
SendTo(user, new ContextClearPacket(ContextClearMode.MessagesUsers));
|
||||||
SendTo(user, new ContextUsersPacket(GetChannelUsers(chan).Except(new[] { user }).OrderByDescending(u => u.Rank)));
|
SendTo(user, new ContextUsersPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)));
|
||||||
|
|
||||||
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
|
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
|
||||||
SendTo(user, new ContextMessagePacket(msg));
|
SendTo(user, new ContextMessagePacket(msg));
|
||||||
|
@ -296,8 +291,7 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Send(IServerPacket packet) {
|
public void Send(IServerPacket packet) {
|
||||||
if(packet == null)
|
ArgumentNullException.ThrowIfNull(packet);
|
||||||
throw new ArgumentNullException(nameof(packet));
|
|
||||||
|
|
||||||
foreach(ChatConnection conn in Connections)
|
foreach(ChatConnection conn in Connections)
|
||||||
if(conn.IsAuthed)
|
if(conn.IsAuthed)
|
||||||
|
@ -305,10 +299,8 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendTo(ChatUser user, IServerPacket packet) {
|
public void SendTo(ChatUser user, IServerPacket packet) {
|
||||||
if(user == null)
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
throw new ArgumentNullException(nameof(user));
|
ArgumentNullException.ThrowIfNull(packet);
|
||||||
if(packet == null)
|
|
||||||
throw new ArgumentNullException(nameof(packet));
|
|
||||||
|
|
||||||
foreach(ChatConnection conn in Connections)
|
foreach(ChatConnection conn in Connections)
|
||||||
if(conn.IsAlive && conn.User == user)
|
if(conn.IsAlive && conn.User == user)
|
||||||
|
@ -316,10 +308,8 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendTo(ChatChannel channel, IServerPacket packet) {
|
public void SendTo(ChatChannel channel, IServerPacket packet) {
|
||||||
if(channel == null)
|
ArgumentNullException.ThrowIfNull(channel);
|
||||||
throw new ArgumentNullException(nameof(channel));
|
ArgumentNullException.ThrowIfNull(packet);
|
||||||
if(packet == null)
|
|
||||||
throw new ArgumentNullException(nameof(packet));
|
|
||||||
|
|
||||||
// might be faster to grab the users first and then cascade into that SendTo
|
// might be faster to grab the users first and then cascade into that SendTo
|
||||||
IEnumerable<ChatConnection> conns = Connections.Where(c => c.IsAuthed && IsInChannel(c.User, channel));
|
IEnumerable<ChatConnection> conns = Connections.Where(c => c.IsAuthed && IsInChannel(c.User, channel));
|
||||||
|
@ -328,10 +318,8 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendToUserChannels(ChatUser user, IServerPacket packet) {
|
public void SendToUserChannels(ChatUser user, IServerPacket packet) {
|
||||||
if(user == null)
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
throw new ArgumentNullException(nameof(user));
|
ArgumentNullException.ThrowIfNull(packet);
|
||||||
if(packet == null)
|
|
||||||
throw new ArgumentNullException(nameof(packet));
|
|
||||||
|
|
||||||
IEnumerable<ChatChannel> chans = Channels.Where(c => IsInChannel(user, c));
|
IEnumerable<ChatChannel> chans = Channels.Where(c => IsInChannel(user, c));
|
||||||
IEnumerable<ChatConnection> conns = Connections.Where(conn => conn.IsAuthed && ChannelUsers.Any(cu => cu.UserId == conn.User.UserId && chans.Any(chan => chan.NameEquals(cu.ChannelName))));
|
IEnumerable<ChatConnection> conns = Connections.Where(conn => conn.IsAuthed && ChannelUsers.Any(cu => cu.UserId == conn.User.UserId && chans.Any(chan => chan.NameEquals(cu.ChannelName))));
|
||||||
|
@ -340,12 +328,11 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPAddress[] GetRemoteAddresses(ChatUser user) {
|
public IPAddress[] GetRemoteAddresses(ChatUser user) {
|
||||||
return Connections.Where(c => c.IsAlive && c.User == user).Select(c => c.RemoteAddress).Distinct().ToArray();
|
return [.. Connections.Where(c => c.IsAlive && c.User == user).Select(c => c.RemoteAddress).Distinct()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ForceChannel(ChatUser user, ChatChannel chan = null) {
|
public void ForceChannel(ChatUser user, ChatChannel chan = null) {
|
||||||
if(user == null)
|
ArgumentNullException.ThrowIfNull(user);
|
||||||
throw new ArgumentNullException(nameof(user));
|
|
||||||
|
|
||||||
if(chan == null && !UserLastChannel.TryGetValue(user.UserId, out chan))
|
if(chan == null && !UserLastChannel.TryGetValue(user.UserId, out chan))
|
||||||
throw new ArgumentException("no channel???");
|
throw new ArgumentException("no channel???");
|
||||||
|
@ -354,8 +341,7 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateChannel(ChatChannel channel, bool? temporary = null, int? hierarchy = null, string password = null) {
|
public void UpdateChannel(ChatChannel channel, bool? temporary = null, int? hierarchy = null, string password = null) {
|
||||||
if(channel == null)
|
ArgumentNullException.ThrowIfNull(channel);
|
||||||
throw new ArgumentNullException(nameof(channel));
|
|
||||||
if(!Channels.Contains(channel))
|
if(!Channels.Contains(channel))
|
||||||
throw new ArgumentException("Provided channel is not registered with this manager.", nameof(channel));
|
throw new ArgumentException("Provided channel is not registered with this manager.", nameof(channel));
|
||||||
|
|
||||||
|
@ -375,7 +361,7 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveChannel(ChatChannel channel) {
|
public void RemoveChannel(ChatChannel channel) {
|
||||||
if(channel == null || !Channels.Any())
|
if(channel == null || Channels.Count < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ChatChannel defaultChannel = Channels.FirstOrDefault();
|
ChatChannel defaultChannel = Channels.FirstOrDefault();
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public class ChatPacketHandlerContext {
|
public class ChatPacketHandlerContext(
|
||||||
public string Text { get; }
|
string text,
|
||||||
public ChatContext Chat { get; }
|
ChatContext chat,
|
||||||
public ChatConnection Connection { get; }
|
ChatConnection connection
|
||||||
|
) {
|
||||||
public ChatPacketHandlerContext(
|
public string Text { get; } = text ?? throw new ArgumentNullException(nameof(text));
|
||||||
string text,
|
public ChatContext Chat { get; } = chat ?? throw new ArgumentNullException(nameof(chat));
|
||||||
ChatContext chat,
|
public ChatConnection Connection { get; } = connection ?? throw new ArgumentNullException(nameof(connection));
|
||||||
ChatConnection connection
|
|
||||||
) {
|
|
||||||
Text = text ?? throw new ArgumentNullException(nameof(text));
|
|
||||||
Chat = chat ?? throw new ArgumentNullException(nameof(chat));
|
|
||||||
Connection = connection ?? throw new ArgumentNullException(nameof(connection));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CheckPacketId(string packetId) {
|
public bool CheckPacketId(string packetId) {
|
||||||
return Text == packetId || Text.StartsWith(packetId + '\t');
|
return Text == packetId || Text.StartsWith(packetId + '\t');
|
||||||
|
|
|
@ -4,20 +4,29 @@ using System.Text;
|
||||||
using SharpChat.Commands;
|
using SharpChat.Commands;
|
||||||
|
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public class ChatUser : IEquatable<ChatUser> {
|
public class ChatUser(
|
||||||
|
long userId,
|
||||||
|
string userName,
|
||||||
|
ChatColour colour,
|
||||||
|
int rank,
|
||||||
|
ChatUserPermissions perms,
|
||||||
|
string nickName = "",
|
||||||
|
ChatUserStatus status = ChatUserStatus.Online,
|
||||||
|
string statusText = ""
|
||||||
|
) {
|
||||||
public const int DEFAULT_SIZE = 30;
|
public const int DEFAULT_SIZE = 30;
|
||||||
public const int DEFAULT_MINIMUM_DELAY = 10000;
|
public const int DEFAULT_MINIMUM_DELAY = 10000;
|
||||||
public const int DEFAULT_RISKY_OFFSET = 5;
|
public const int DEFAULT_RISKY_OFFSET = 5;
|
||||||
|
|
||||||
public long UserId { get; }
|
public long UserId { get; } = userId;
|
||||||
public string UserName { get; set; }
|
public string UserName { get; set; } = userName ?? throw new ArgumentNullException(nameof(userName));
|
||||||
public ChatColour Colour { get; set; }
|
public ChatColour Colour { get; set; } = colour;
|
||||||
public int Rank { get; set; }
|
public int Rank { get; set; } = rank;
|
||||||
public ChatUserPermissions Permissions { get; set; }
|
public ChatUserPermissions Permissions { get; set; } = perms;
|
||||||
public bool IsSuper { get; set; }
|
public bool IsSuper { get; set; }
|
||||||
public string NickName { get; set; }
|
public string NickName { get; set; } = nickName ?? string.Empty;
|
||||||
public ChatUserStatus Status { get; set; }
|
public ChatUserStatus Status { get; set; } = status;
|
||||||
public string StatusText { get; set; }
|
public string StatusText { get; set; } = statusText ?? string.Empty;
|
||||||
|
|
||||||
public string LegacyName => string.IsNullOrWhiteSpace(NickName) ? UserName : $"~{NickName}";
|
public string LegacyName => string.IsNullOrWhiteSpace(NickName) ? UserName : $"~{NickName}";
|
||||||
|
|
||||||
|
@ -27,7 +36,7 @@ namespace SharpChat {
|
||||||
|
|
||||||
if(Status == ChatUserStatus.Away) {
|
if(Status == ChatUserStatus.Away) {
|
||||||
string statusText = StatusText.Trim();
|
string statusText = StatusText.Trim();
|
||||||
StringInfo sti = new StringInfo(statusText);
|
StringInfo sti = new(statusText);
|
||||||
if(Encoding.UTF8.GetByteCount(statusText) > AFKCommand.MAX_BYTES
|
if(Encoding.UTF8.GetByteCount(statusText) > AFKCommand.MAX_BYTES
|
||||||
|| sti.LengthInTextElements > AFKCommand.MAX_GRAPHEMES)
|
|| sti.LengthInTextElements > AFKCommand.MAX_GRAPHEMES)
|
||||||
statusText = sti.SubstringByTextElements(0, Math.Min(sti.LengthInTextElements, AFKCommand.MAX_GRAPHEMES)).Trim();
|
statusText = sti.SubstringByTextElements(0, Math.Min(sti.LengthInTextElements, AFKCommand.MAX_GRAPHEMES)).Trim();
|
||||||
|
@ -41,27 +50,6 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatUser(
|
|
||||||
long userId,
|
|
||||||
string userName,
|
|
||||||
ChatColour colour,
|
|
||||||
int rank,
|
|
||||||
ChatUserPermissions perms,
|
|
||||||
string nickName = null,
|
|
||||||
ChatUserStatus status = ChatUserStatus.Online,
|
|
||||||
string statusText = null,
|
|
||||||
bool isSuper = false
|
|
||||||
) {
|
|
||||||
UserId = userId;
|
|
||||||
UserName = userName ?? throw new ArgumentNullException(nameof(userName));
|
|
||||||
Colour = colour;
|
|
||||||
Rank = rank;
|
|
||||||
Permissions = perms;
|
|
||||||
NickName = nickName ?? string.Empty;
|
|
||||||
Status = status;
|
|
||||||
StatusText = statusText ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Can(ChatUserPermissions perm, bool strict = false) {
|
public bool Can(ChatUserPermissions perm, bool strict = false) {
|
||||||
ChatUserPermissions perms = Permissions & perm;
|
ChatUserPermissions perms = Permissions & perm;
|
||||||
return strict ? perms == perm : perms > 0;
|
return strict ? perms == perm : perms > 0;
|
||||||
|
@ -102,14 +90,6 @@ namespace SharpChat {
|
||||||
return UserId.GetHashCode();
|
return UserId.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj) {
|
|
||||||
return Equals(obj as ChatUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(ChatUser other) {
|
|
||||||
return UserId == other?.UserId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetDMChannelName(ChatUser user1, ChatUser user2) {
|
public static string GetDMChannelName(ChatUser user1, ChatUser user2) {
|
||||||
return user1.UserId < user2.UserId
|
return user1.UserId < user2.UserId
|
||||||
? $"@{user1.UserId}-{user2.UserId}"
|
? $"@{user1.UserId}-{user2.UserId}"
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace SharpChat.Commands {
|
||||||
else {
|
else {
|
||||||
statusText = statusText.Trim();
|
statusText = statusText.Trim();
|
||||||
|
|
||||||
StringInfo sti = new StringInfo(statusText);
|
StringInfo sti = new(statusText);
|
||||||
if(Encoding.UTF8.GetByteCount(statusText) > MAX_BYTES
|
if(Encoding.UTF8.GetByteCount(statusText) > MAX_BYTES
|
||||||
|| sti.LengthInTextElements > MAX_GRAPHEMES)
|
|| sti.LengthInTextElements > MAX_GRAPHEMES)
|
||||||
statusText = sti.SubstringByTextElements(0, Math.Min(sti.LengthInTextElements, MAX_GRAPHEMES)).Trim();
|
statusText = sti.SubstringByTextElements(0, Math.Min(sti.LengthInTextElements, MAX_GRAPHEMES)).Trim();
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispatch(ChatCommandContext ctx) {
|
public void Dispatch(ChatCommandContext ctx) {
|
||||||
if(!ctx.Args.Any())
|
if(ctx.Args.Length < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string actionStr = string.Join(' ', ctx.Args);
|
string actionStr = string.Join(' ', ctx.Args);
|
||||||
|
@ -19,8 +19,13 @@ namespace SharpChat.Commands {
|
||||||
|
|
||||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||||
SharpId.Next(),
|
SharpId.Next(),
|
||||||
ctx.Channel,
|
ctx.Channel.Name,
|
||||||
ctx.User,
|
ctx.User.UserId,
|
||||||
|
ctx.User.UserName,
|
||||||
|
ctx.User.Colour,
|
||||||
|
ctx.User.Rank,
|
||||||
|
ctx.User.NickName,
|
||||||
|
ctx.User.Permissions,
|
||||||
DateTimeOffset.Now,
|
DateTimeOffset.Now,
|
||||||
actionStr,
|
actionStr,
|
||||||
false, true, false
|
false, true, false
|
||||||
|
|
|
@ -4,12 +4,8 @@ using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharpChat.Commands {
|
namespace SharpChat.Commands {
|
||||||
public class BanListCommand : IChatCommand {
|
public class BanListCommand(MisuzuClient msz) : IChatCommand {
|
||||||
private readonly MisuzuClient Misuzu;
|
private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
||||||
|
|
||||||
public BanListCommand(MisuzuClient msz) {
|
|
||||||
Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatCommandContext ctx) {
|
public bool IsMatch(ChatCommandContext ctx) {
|
||||||
return ctx.NameEquals("bans")
|
return ctx.NameEquals("bans")
|
||||||
|
|
|
@ -18,7 +18,12 @@ namespace SharpChat.Commands {
|
||||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||||
SharpId.Next(),
|
SharpId.Next(),
|
||||||
string.Empty,
|
string.Empty,
|
||||||
ctx.User,
|
ctx.User.UserId,
|
||||||
|
ctx.User.UserName,
|
||||||
|
ctx.User.Colour,
|
||||||
|
ctx.User.Rank,
|
||||||
|
ctx.User.NickName,
|
||||||
|
ctx.User.Permissions,
|
||||||
DateTimeOffset.Now,
|
DateTimeOffset.Now,
|
||||||
string.Join(' ', ctx.Args),
|
string.Join(' ', ctx.Args),
|
||||||
false, false, true
|
false, false, true
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace SharpChat.Commands {
|
||||||
string firstArg = ctx.Args.First();
|
string firstArg = ctx.Args.First();
|
||||||
|
|
||||||
bool createChanHasHierarchy;
|
bool createChanHasHierarchy;
|
||||||
if(!ctx.Args.Any() || (createChanHasHierarchy = firstArg.All(char.IsDigit) && ctx.Args.Length < 2)) {
|
if(ctx.Args.Length < 1 || (createChanHasHierarchy = firstArg.All(char.IsDigit) && ctx.Args.Length < 2)) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -44,9 +44,10 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatChannel createChan = new(
|
ChatChannel createChan = new(
|
||||||
ctx.User, createChanName,
|
createChanName,
|
||||||
isTemporary: !ctx.User.Can(ChatUserPermissions.SetChannelPermanent),
|
isTemporary: !ctx.User.Can(ChatUserPermissions.SetChannelPermanent),
|
||||||
rank: createChanHierarchy
|
rank: createChanHierarchy,
|
||||||
|
ownerId: ctx.User.UserId
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.Chat.Channels.Add(createChan);
|
ctx.Chat.Channels.Add(createChan);
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace SharpChat.Commands {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispatch(ChatCommandContext ctx) {
|
public void Dispatch(ChatCommandContext ctx) {
|
||||||
if(!ctx.Args.Any() || string.IsNullOrWhiteSpace(ctx.Args.FirstOrDefault())) {
|
if(ctx.Args.Length < 1 || string.IsNullOrWhiteSpace(ctx.Args.FirstOrDefault())) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,8 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharpChat.Commands {
|
namespace SharpChat.Commands {
|
||||||
public class KickBanCommand : IChatCommand {
|
public class KickBanCommand(MisuzuClient msz) : IChatCommand {
|
||||||
private readonly MisuzuClient Misuzu;
|
private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
||||||
|
|
||||||
public KickBanCommand(MisuzuClient msz) {
|
|
||||||
Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatCommandContext ctx) {
|
public bool IsMatch(ChatCommandContext ctx) {
|
||||||
return ctx.NameEquals("kick")
|
return ctx.NameEquals("kick")
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace SharpChat.Commands {
|
||||||
else if(string.IsNullOrEmpty(nickStr))
|
else if(string.IsNullOrEmpty(nickStr))
|
||||||
nickStr = string.Empty;
|
nickStr = string.Empty;
|
||||||
else {
|
else {
|
||||||
StringInfo nsi = new StringInfo(nickStr);
|
StringInfo nsi = new(nickStr);
|
||||||
if(Encoding.UTF8.GetByteCount(nickStr) > MAX_BYTES
|
if(Encoding.UTF8.GetByteCount(nickStr) > MAX_BYTES
|
||||||
|| nsi.LengthInTextElements > MAX_GRAPHEMES)
|
|| nsi.LengthInTextElements > MAX_GRAPHEMES)
|
||||||
nickStr = nsi.SubstringByTextElements(0, Math.Min(nsi.LengthInTextElements, MAX_GRAPHEMES)).Trim();
|
nickStr = nsi.SubstringByTextElements(0, Math.Min(nsi.LengthInTextElements, MAX_GRAPHEMES)).Trim();
|
||||||
|
|
|
@ -6,12 +6,8 @@ using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharpChat.Commands {
|
namespace SharpChat.Commands {
|
||||||
public class PardonAddressCommand : IChatCommand {
|
public class PardonAddressCommand(MisuzuClient msz) : IChatCommand {
|
||||||
private readonly MisuzuClient Misuzu;
|
private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
||||||
|
|
||||||
public PardonAddressCommand(MisuzuClient msz) {
|
|
||||||
Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatCommandContext ctx) {
|
public bool IsMatch(ChatCommandContext ctx) {
|
||||||
return ctx.NameEquals("pardonip")
|
return ctx.NameEquals("pardonip")
|
||||||
|
|
|
@ -5,12 +5,8 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharpChat.Commands {
|
namespace SharpChat.Commands {
|
||||||
public class PardonUserCommand : IChatCommand {
|
public class PardonUserCommand(MisuzuClient msz) : IChatCommand {
|
||||||
private readonly MisuzuClient Misuzu;
|
private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
||||||
|
|
||||||
public PardonUserCommand(MisuzuClient msz) {
|
|
||||||
Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatCommandContext ctx) {
|
public bool IsMatch(ChatCommandContext ctx) {
|
||||||
return ctx.NameEquals("pardon")
|
return ctx.NameEquals("pardon")
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace SharpChat.Commands {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ctx.Args.Any() || !int.TryParse(ctx.Args.First(), out int chanHierarchy) || chanHierarchy > ctx.User.Rank) {
|
if(ctx.Args.Length < 1 || !int.TryParse(ctx.Args.First(), out int chanHierarchy) || chanHierarchy > ctx.User.Rank) {
|
||||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.INSUFFICIENT_HIERARCHY));
|
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.INSUFFICIENT_HIERARCHY));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,9 @@ using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace SharpChat.Commands {
|
namespace SharpChat.Commands {
|
||||||
public class ShutdownRestartCommand : IChatCommand {
|
public class ShutdownRestartCommand(ManualResetEvent waitHandle, Func<bool> shutdownCheck) : IChatCommand {
|
||||||
private readonly ManualResetEvent WaitHandle;
|
private readonly ManualResetEvent WaitHandle = waitHandle ?? throw new ArgumentNullException(nameof(waitHandle));
|
||||||
private readonly Func<bool> ShutdownCheck;
|
private readonly Func<bool> ShutdownCheck = shutdownCheck ?? throw new ArgumentNullException(nameof(shutdownCheck));
|
||||||
|
|
||||||
public ShutdownRestartCommand(ManualResetEvent waitHandle, Func<bool> shutdownCheck) {
|
|
||||||
WaitHandle = waitHandle ?? throw new ArgumentNullException(nameof(waitHandle));
|
|
||||||
ShutdownCheck = shutdownCheck ?? throw new ArgumentNullException(nameof(shutdownCheck));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatCommandContext ctx) {
|
public bool IsMatch(ChatCommandContext ctx) {
|
||||||
return ctx.NameEquals("shutdown")
|
return ctx.NameEquals("shutdown")
|
||||||
|
|
|
@ -30,7 +30,12 @@ namespace SharpChat.Commands {
|
||||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||||
SharpId.Next(),
|
SharpId.Next(),
|
||||||
ChatUser.GetDMChannelName(ctx.User, whisperUser),
|
ChatUser.GetDMChannelName(ctx.User, whisperUser),
|
||||||
ctx.User,
|
ctx.User.UserId,
|
||||||
|
ctx.User.UserName,
|
||||||
|
ctx.User.Colour,
|
||||||
|
ctx.User.Rank,
|
||||||
|
ctx.User.NickName,
|
||||||
|
ctx.User.Permissions,
|
||||||
DateTimeOffset.Now,
|
DateTimeOffset.Now,
|
||||||
string.Join(' ', ctx.Args.Skip(1)),
|
string.Join(' ', ctx.Args.Skip(1)),
|
||||||
true, false, false
|
true, false, false
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace SharpChat.Config {
|
namespace SharpChat.Config {
|
||||||
public class CachedValue<T> {
|
public class CachedValue<T>(IConfig config, string name, TimeSpan lifetime, T fallback) {
|
||||||
private IConfig Config { get; }
|
private IConfig Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
|
||||||
private string Name { get; }
|
private string Name { get; } = name ?? throw new ArgumentNullException(nameof(name));
|
||||||
private TimeSpan Lifetime { get; }
|
|
||||||
private T Fallback { get; }
|
|
||||||
private object ConfigAccess { get; } = new();
|
private object ConfigAccess { get; } = new();
|
||||||
|
|
||||||
private object CurrentValue { get; set; }
|
private object CurrentValue { get; set; }
|
||||||
|
@ -15,9 +13,9 @@ namespace SharpChat.Config {
|
||||||
get {
|
get {
|
||||||
lock(ConfigAccess) { // this lock doesn't really make sense since it doesn't affect other config calls
|
lock(ConfigAccess) { // this lock doesn't really make sense since it doesn't affect other config calls
|
||||||
DateTimeOffset now = DateTimeOffset.Now;
|
DateTimeOffset now = DateTimeOffset.Now;
|
||||||
if((now - LastRead) >= Lifetime) {
|
if((now - LastRead) >= lifetime) {
|
||||||
LastRead = now;
|
LastRead = now;
|
||||||
CurrentValue = Config.ReadValue(Name, Fallback);
|
CurrentValue = Config.ReadValue(Name, fallback);
|
||||||
Logger.Debug($"Read {Name} ({CurrentValue})");
|
Logger.Debug($"Read {Name} ({CurrentValue})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,15 +25,6 @@ namespace SharpChat.Config {
|
||||||
|
|
||||||
public static implicit operator T(CachedValue<T> val) => val.Value;
|
public static implicit operator T(CachedValue<T> val) => val.Value;
|
||||||
|
|
||||||
public CachedValue(IConfig config, string name, TimeSpan lifetime, T fallback) {
|
|
||||||
Config = config ?? throw new ArgumentNullException(nameof(config));
|
|
||||||
Name = name ?? throw new ArgumentNullException(nameof(name));
|
|
||||||
Lifetime = lifetime;
|
|
||||||
Fallback = fallback;
|
|
||||||
if(string.IsNullOrWhiteSpace(name))
|
|
||||||
throw new ArgumentException("Name cannot be empty.", nameof(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Refresh() {
|
public void Refresh() {
|
||||||
LastRead = DateTimeOffset.MinValue;
|
LastRead = DateTimeOffset.MinValue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,6 @@ namespace SharpChat.Config {
|
||||||
public ConfigException(string message, Exception ex) : base(message, ex) { }
|
public ConfigException(string message, Exception ex) : base(message, ex) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConfigLockException : ConfigException {
|
public class ConfigLockException() : ConfigException("Unable to acquire lock for reading configuration.") {}
|
||||||
public ConfigLockException() : base("Unable to acquire lock for reading configuration.") { }
|
public class ConfigTypeException(Exception ex) : ConfigException("Given type does not match the value in the configuration.", ex) {}
|
||||||
}
|
|
||||||
|
|
||||||
public class ConfigTypeException : ConfigException {
|
|
||||||
public ConfigTypeException(Exception ex) : base("Given type does not match the value in the configuration.", ex) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace SharpChat.Config {
|
namespace SharpChat.Config {
|
||||||
public interface IConfig : IDisposable {
|
public interface IConfig : IDisposable {
|
||||||
|
|
|
@ -1,18 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace SharpChat.Config {
|
namespace SharpChat.Config {
|
||||||
public class ScopedConfig : IConfig {
|
public class ScopedConfig(IConfig config, string prefix) : IConfig {
|
||||||
private IConfig Config { get; }
|
private IConfig Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
|
||||||
private string Prefix { get; }
|
private string Prefix { get; } = prefix ?? throw new ArgumentNullException(nameof(prefix));
|
||||||
|
|
||||||
public ScopedConfig(IConfig config, string prefix) {
|
|
||||||
Config = config ?? throw new ArgumentNullException(nameof(config));
|
|
||||||
Prefix = prefix ?? throw new ArgumentNullException(nameof(prefix));
|
|
||||||
if(string.IsNullOrWhiteSpace(prefix))
|
|
||||||
throw new ArgumentException("Prefix must exist.", nameof(prefix));
|
|
||||||
if(Prefix[^1] != ':')
|
|
||||||
Prefix += ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetName(string name) {
|
private string GetName(string name) {
|
||||||
return Prefix + name;
|
return Prefix + name;
|
||||||
|
|
|
@ -13,9 +13,6 @@ namespace SharpChat.Config {
|
||||||
|
|
||||||
private static readonly TimeSpan CACHE_LIFETIME = TimeSpan.FromMinutes(15);
|
private static readonly TimeSpan CACHE_LIFETIME = TimeSpan.FromMinutes(15);
|
||||||
|
|
||||||
public StreamConfig(string fileName)
|
|
||||||
: this(new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite)) { }
|
|
||||||
|
|
||||||
public StreamConfig(Stream stream) {
|
public StreamConfig(Stream stream) {
|
||||||
Stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
Stream = stream ?? throw new ArgumentNullException(nameof(stream));
|
||||||
if(!Stream.CanRead)
|
if(!Stream.CanRead)
|
||||||
|
@ -26,6 +23,10 @@ namespace SharpChat.Config {
|
||||||
Lock = new Mutex();
|
Lock = new Mutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static StreamConfig FromPath(string fileName) {
|
||||||
|
return new StreamConfig(new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Read, FileShare.ReadWrite));
|
||||||
|
}
|
||||||
|
|
||||||
public string ReadValue(string name, string fallback = null) {
|
public string ReadValue(string name, string fallback = null) {
|
||||||
if(!Lock.WaitOne(LOCK_TIMEOUT)) // don't catch this, if this happens something is Very Wrong
|
if(!Lock.WaitOne(LOCK_TIMEOUT)) // don't catch this, if this happens something is Very Wrong
|
||||||
throw new ConfigLockException();
|
throw new ConfigLockException();
|
||||||
|
@ -39,7 +40,7 @@ namespace SharpChat.Config {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
line = line.TrimStart();
|
line = line.TrimStart();
|
||||||
if(line.StartsWith(";") || line.StartsWith("#"))
|
if(line.StartsWith(';') || line.StartsWith('#'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
string[] parts = line.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
|
string[] parts = line.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
@ -85,6 +86,11 @@ namespace SharpChat.Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
public IConfig ScopeTo(string prefix) {
|
public IConfig ScopeTo(string prefix) {
|
||||||
|
if(string.IsNullOrWhiteSpace(prefix))
|
||||||
|
throw new ArgumentException("Prefix must exist.", nameof(prefix));
|
||||||
|
if(prefix[^1] != ':')
|
||||||
|
prefix += ':';
|
||||||
|
|
||||||
return new ScopedConfig(this, prefix);
|
return new ScopedConfig(this, prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,31 +4,18 @@ namespace SharpChat.EventStorage
|
||||||
{
|
{
|
||||||
public interface IEventStorage {
|
public interface IEventStorage {
|
||||||
void AddEvent(
|
void AddEvent(
|
||||||
long id, string type,
|
long id,
|
||||||
object data = null,
|
string type,
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
);
|
|
||||||
void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
string channelName,
|
string channelName,
|
||||||
|
long senderId,
|
||||||
|
string senderName,
|
||||||
|
ChatColour senderColour,
|
||||||
|
int senderRank,
|
||||||
|
string senderNick,
|
||||||
|
ChatUserPermissions senderPerms,
|
||||||
object data = null,
|
object data = null,
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
StoredEventFlags flags = StoredEventFlags.None
|
||||||
);
|
);
|
||||||
void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
long senderId, string senderName, ChatColour senderColour, int senderRank, string senderNick, ChatUserPermissions senderPerms,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
);
|
|
||||||
void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
string channelName,
|
|
||||||
long senderId, string senderName, ChatColour senderColour, int senderRank, string senderNick, ChatUserPermissions senderPerms,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
);
|
|
||||||
|
|
||||||
long AddEvent(string type, ChatUser user, ChatChannel channel, object data = null, StoredEventFlags flags = StoredEventFlags.None);
|
|
||||||
void RemoveEvent(StoredEventInfo evt);
|
void RemoveEvent(StoredEventInfo evt);
|
||||||
StoredEventInfo GetEvent(long seqId);
|
StoredEventInfo GetEvent(long seqId);
|
||||||
IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0);
|
IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0);
|
||||||
|
|
|
@ -1,45 +1,13 @@
|
||||||
using MySqlConnector;
|
using MySqlConnector;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Dynamic;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Channels;
|
|
||||||
|
|
||||||
namespace SharpChat.EventStorage
|
namespace SharpChat.EventStorage
|
||||||
{
|
{
|
||||||
public partial class MariaDBEventStorage : IEventStorage {
|
public partial class MariaDBEventStorage(string connString) : IEventStorage {
|
||||||
private string ConnectionString { get; }
|
private string ConnectionString { get; } = connString ?? throw new ArgumentNullException(nameof(connString));
|
||||||
|
|
||||||
public MariaDBEventStorage(string connString) {
|
|
||||||
ConnectionString = connString ?? throw new ArgumentNullException(nameof(connString));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
) {
|
|
||||||
AddEvent(id, type, null, 0, null, ChatColour.None, 0, null, 0, data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
string channelName,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
) {
|
|
||||||
AddEvent(id, type, channelName, 0, null, ChatColour.None, 0, null, 0, data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
long senderId, string senderName, ChatColour senderColour, int senderRank, string senderNick, ChatUserPermissions senderPerms,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
) {
|
|
||||||
AddEvent(id, type, null, senderId, senderName, senderColour, senderRank, senderNick, senderPerms, data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
public void AddEvent(
|
||||||
long id, string type,
|
long id, string type,
|
||||||
|
@ -48,8 +16,7 @@ namespace SharpChat.EventStorage
|
||||||
object data = null,
|
object data = null,
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
StoredEventFlags flags = StoredEventFlags.None
|
||||||
) {
|
) {
|
||||||
if(type == null)
|
ArgumentNullException.ThrowIfNull(type);
|
||||||
throw new ArgumentNullException(nameof(type));
|
|
||||||
|
|
||||||
RunCommand(
|
RunCommand(
|
||||||
"INSERT INTO `sqc_events` (`event_id`, `event_created`, `event_type`, `event_target`, `event_flags`, `event_data`"
|
"INSERT INTO `sqc_events` (`event_id`, `event_created`, `event_type`, `event_target`, `event_flags`, `event_data`"
|
||||||
|
@ -71,8 +38,7 @@ namespace SharpChat.EventStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
public long AddEvent(string type, ChatUser user, ChatChannel channel, object data = null, StoredEventFlags flags = StoredEventFlags.None) {
|
public long AddEvent(string type, ChatUser user, ChatChannel channel, object data = null, StoredEventFlags flags = StoredEventFlags.None) {
|
||||||
if(type == null)
|
ArgumentNullException.ThrowIfNull(type);
|
||||||
throw new ArgumentNullException(nameof(type));
|
|
||||||
|
|
||||||
long id = SharpId.Next();
|
long id = SharpId.Next();
|
||||||
|
|
||||||
|
@ -137,7 +103,7 @@ namespace SharpChat.EventStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0) {
|
public IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0) {
|
||||||
List<StoredEventInfo> events = new();
|
List<StoredEventInfo> events = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
using MySqlDataReader reader = RunQuery(
|
using MySqlDataReader reader = RunQuery(
|
||||||
|
@ -170,8 +136,7 @@ namespace SharpChat.EventStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveEvent(StoredEventInfo evt) {
|
public void RemoveEvent(StoredEventInfo evt) {
|
||||||
if(evt == null)
|
ArgumentNullException.ThrowIfNull(evt);
|
||||||
throw new ArgumentNullException(nameof(evt));
|
|
||||||
RunCommand(
|
RunCommand(
|
||||||
"UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL",
|
"UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL",
|
||||||
new MySqlParameter("id", evt.Id)
|
new MySqlParameter("id", evt.Id)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace SharpChat.EventStorage
|
namespace SharpChat.EventStorage {
|
||||||
{
|
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum StoredEventFlags
|
public enum StoredEventFlags {
|
||||||
{
|
|
||||||
None = 0,
|
None = 0,
|
||||||
Action = 1,
|
Action = 1,
|
||||||
Broadcast = 1 << 1,
|
Broadcast = 1 << 1,
|
||||||
|
|
|
@ -2,34 +2,23 @@
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace SharpChat.EventStorage {
|
namespace SharpChat.EventStorage {
|
||||||
public class StoredEventInfo {
|
public class StoredEventInfo(
|
||||||
public long Id { get; set; }
|
long id,
|
||||||
public string Type { get; set; }
|
string type,
|
||||||
public ChatUser Sender { get; set; }
|
ChatUser sender,
|
||||||
public DateTimeOffset Created { get; set; }
|
DateTimeOffset created,
|
||||||
public DateTimeOffset? Deleted { get; set; }
|
DateTimeOffset? deleted,
|
||||||
public string ChannelName { get; set; }
|
string channelName,
|
||||||
public StoredEventFlags Flags { get; set; }
|
JsonDocument data,
|
||||||
public JsonDocument Data { get; set; }
|
StoredEventFlags flags
|
||||||
|
) {
|
||||||
public StoredEventInfo(
|
public long Id { get; set; } = id;
|
||||||
long id,
|
public string Type { get; set; } = type;
|
||||||
string type,
|
public ChatUser Sender { get; set; } = sender;
|
||||||
ChatUser sender,
|
public DateTimeOffset Created { get; set; } = created;
|
||||||
DateTimeOffset created,
|
public DateTimeOffset? Deleted { get; set; } = deleted;
|
||||||
DateTimeOffset? deleted,
|
public string ChannelName { get; set; } = channelName;
|
||||||
string channelName,
|
public StoredEventFlags Flags { get; set; } = flags;
|
||||||
JsonDocument data,
|
public JsonDocument Data { get; set; } = data;
|
||||||
StoredEventFlags flags
|
|
||||||
) {
|
|
||||||
Id = id;
|
|
||||||
Type = type;
|
|
||||||
Sender = sender;
|
|
||||||
Created = created;
|
|
||||||
Deleted = deleted;
|
|
||||||
ChannelName = channelName;
|
|
||||||
Data = data;
|
|
||||||
Flags = flags;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,33 +5,7 @@ using System.Text.Json;
|
||||||
|
|
||||||
namespace SharpChat.EventStorage {
|
namespace SharpChat.EventStorage {
|
||||||
public class VirtualEventStorage : IEventStorage {
|
public class VirtualEventStorage : IEventStorage {
|
||||||
private readonly Dictionary<long, StoredEventInfo> Events = new();
|
private readonly Dictionary<long, StoredEventInfo> Events = [];
|
||||||
|
|
||||||
public void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
) {
|
|
||||||
AddEvent(id, type, null, 0, null, ChatColour.None, 0, null, 0, data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
string channelName,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
) {
|
|
||||||
AddEvent(id, type, channelName, 0, null, ChatColour.None, 0, null, 0, data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
|
||||||
long id, string type,
|
|
||||||
long senderId, string senderName, ChatColour senderColour, int senderRank, string senderNick, ChatUserPermissions senderPerms,
|
|
||||||
object data = null,
|
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
|
||||||
) {
|
|
||||||
AddEvent(id, type, null, senderId, senderName, senderColour, senderRank, senderNick, senderPerms, data, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddEvent(
|
public void AddEvent(
|
||||||
long id, string type,
|
long id, string type,
|
||||||
|
@ -40,8 +14,7 @@ namespace SharpChat.EventStorage {
|
||||||
object data = null,
|
object data = null,
|
||||||
StoredEventFlags flags = StoredEventFlags.None
|
StoredEventFlags flags = StoredEventFlags.None
|
||||||
) {
|
) {
|
||||||
if(type == null)
|
ArgumentNullException.ThrowIfNull(type);
|
||||||
throw new ArgumentNullException(nameof(type));
|
|
||||||
|
|
||||||
// VES is meant as an emergency fallback but this is something else
|
// VES is meant as an emergency fallback but this is something else
|
||||||
JsonDocument hack = JsonDocument.Parse(data == null ? "{}" : JsonSerializer.Serialize(data));
|
JsonDocument hack = JsonDocument.Parse(data == null ? "{}" : JsonSerializer.Serialize(data));
|
||||||
|
@ -55,35 +28,12 @@ namespace SharpChat.EventStorage {
|
||||||
), DateTimeOffset.Now, null, channelName, hack, flags));
|
), DateTimeOffset.Now, null, channelName, hack, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
public long AddEvent(string type, ChatUser user, ChatChannel channel, object data = null, StoredEventFlags flags = StoredEventFlags.None) {
|
|
||||||
if(type == null)
|
|
||||||
throw new ArgumentNullException(nameof(type));
|
|
||||||
|
|
||||||
long id = SharpId.Next();
|
|
||||||
|
|
||||||
AddEvent(
|
|
||||||
id, type,
|
|
||||||
channel?.Name,
|
|
||||||
user?.UserId ?? 0,
|
|
||||||
user?.UserName,
|
|
||||||
user?.Colour ?? ChatColour.None,
|
|
||||||
user?.Rank ?? 0,
|
|
||||||
user?.NickName,
|
|
||||||
user?.Permissions ?? 0,
|
|
||||||
data,
|
|
||||||
flags
|
|
||||||
);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StoredEventInfo GetEvent(long seqId) {
|
public StoredEventInfo GetEvent(long seqId) {
|
||||||
return Events.TryGetValue(seqId, out StoredEventInfo evt) ? evt : null;
|
return Events.TryGetValue(seqId, out StoredEventInfo evt) ? evt : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveEvent(StoredEventInfo evt) {
|
public void RemoveEvent(StoredEventInfo evt) {
|
||||||
if(evt == null)
|
ArgumentNullException.ThrowIfNull(evt);
|
||||||
throw new ArgumentNullException(nameof(evt));
|
|
||||||
Events.Remove(evt.Id);
|
Events.Remove(evt.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +46,7 @@ namespace SharpChat.EventStorage {
|
||||||
start = 0;
|
start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return subset.Skip(start).Take(amount).ToArray();
|
return [.. subset.Skip(start).Take(amount)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,3 @@
|
||||||
using System;
|
namespace SharpChat.Events {
|
||||||
using System.Collections.Generic;
|
public interface IChatEvent {}
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace SharpChat.Events {
|
|
||||||
public interface IChatEvent {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,95 +1,34 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace SharpChat.Events {
|
namespace SharpChat.Events {
|
||||||
public class MessageCreateEvent : IChatEvent {
|
public class MessageCreateEvent(
|
||||||
public long MessageId { get; }
|
long msgId,
|
||||||
public string ChannelName { get; }
|
string channelName,
|
||||||
public long SenderId { get; }
|
long senderId,
|
||||||
public string SenderName { get; }
|
string senderName,
|
||||||
public ChatColour SenderColour { get; }
|
ChatColour senderColour,
|
||||||
public int SenderRank { get; }
|
int senderRank,
|
||||||
public string SenderNickName { get; }
|
string senderNickName,
|
||||||
public ChatUserPermissions SenderPerms { get; }
|
ChatUserPermissions senderPerms,
|
||||||
public DateTimeOffset MessageCreated { get; }
|
DateTimeOffset msgCreated,
|
||||||
|
string msgText,
|
||||||
|
bool isPrivate,
|
||||||
|
bool isAction,
|
||||||
|
bool isBroadcast
|
||||||
|
) : IChatEvent {
|
||||||
|
public long MessageId { get; } = msgId;
|
||||||
|
public string ChannelName { get; } = channelName;
|
||||||
|
public long SenderId { get; } = senderId;
|
||||||
|
public string SenderName { get; } = senderName;
|
||||||
|
public ChatColour SenderColour { get; } = senderColour;
|
||||||
|
public int SenderRank { get; } = senderRank;
|
||||||
|
public string SenderNickName { get; } = senderNickName;
|
||||||
|
public ChatUserPermissions SenderPerms { get; } = senderPerms;
|
||||||
|
public DateTimeOffset MessageCreated { get; } = msgCreated;
|
||||||
public string MessageChannel { get; }
|
public string MessageChannel { get; }
|
||||||
public string MessageText { get; }
|
public string MessageText { get; } = msgText;
|
||||||
public bool IsPrivate { get; }
|
public bool IsPrivate { get; } = isPrivate;
|
||||||
public bool IsAction { get; }
|
public bool IsAction { get; } = isAction;
|
||||||
public bool IsBroadcast { get; }
|
public bool IsBroadcast { get; } = isBroadcast;
|
||||||
|
|
||||||
public MessageCreateEvent(
|
|
||||||
long msgId,
|
|
||||||
string channelName,
|
|
||||||
long senderId,
|
|
||||||
string senderName,
|
|
||||||
ChatColour senderColour,
|
|
||||||
int senderRank,
|
|
||||||
string senderNickName,
|
|
||||||
ChatUserPermissions senderPerms,
|
|
||||||
DateTimeOffset msgCreated,
|
|
||||||
string msgText,
|
|
||||||
bool isPrivate,
|
|
||||||
bool isAction,
|
|
||||||
bool isBroadcast
|
|
||||||
) {
|
|
||||||
MessageId = msgId;
|
|
||||||
ChannelName = channelName;
|
|
||||||
SenderId = senderId;
|
|
||||||
SenderName = senderName;
|
|
||||||
SenderColour = senderColour;
|
|
||||||
SenderRank = senderRank;
|
|
||||||
SenderNickName = senderNickName;
|
|
||||||
SenderPerms = senderPerms;
|
|
||||||
MessageCreated = msgCreated;
|
|
||||||
MessageText = msgText;
|
|
||||||
IsPrivate = isPrivate;
|
|
||||||
IsAction = isAction;
|
|
||||||
IsBroadcast = isBroadcast;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MessageCreateEvent(
|
|
||||||
long msgId,
|
|
||||||
string channelName,
|
|
||||||
ChatUser sender,
|
|
||||||
DateTimeOffset msgCreated,
|
|
||||||
string msgText,
|
|
||||||
bool isPrivate,
|
|
||||||
bool isAction,
|
|
||||||
bool isBroadcast
|
|
||||||
) : this(
|
|
||||||
msgId,
|
|
||||||
channelName,
|
|
||||||
sender?.UserId ?? -1,
|
|
||||||
sender?.UserName ?? null,
|
|
||||||
sender?.Colour ?? ChatColour.None,
|
|
||||||
sender?.Rank ?? 0,
|
|
||||||
sender?.NickName ?? null,
|
|
||||||
sender?.Permissions ?? 0,
|
|
||||||
msgCreated,
|
|
||||||
msgText,
|
|
||||||
isPrivate,
|
|
||||||
isAction,
|
|
||||||
isBroadcast
|
|
||||||
) { }
|
|
||||||
|
|
||||||
public MessageCreateEvent(
|
|
||||||
long msgId,
|
|
||||||
ChatChannel channel,
|
|
||||||
ChatUser sender,
|
|
||||||
DateTimeOffset msgCreated,
|
|
||||||
string msgText,
|
|
||||||
bool isPrivate,
|
|
||||||
bool isAction,
|
|
||||||
bool isBroadcast
|
|
||||||
) : this(
|
|
||||||
msgId,
|
|
||||||
channel?.Name ?? null,
|
|
||||||
sender,
|
|
||||||
msgCreated,
|
|
||||||
msgText,
|
|
||||||
isPrivate,
|
|
||||||
isAction,
|
|
||||||
isBroadcast
|
|
||||||
) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,9 @@ namespace SharpChat {
|
||||||
IEnumerable<string> Pack();
|
IEnumerable<string> Pack();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ServerPacket : IServerPacket {
|
public abstract class ServerPacket(long sequenceId = 0) : IServerPacket {
|
||||||
public long SequenceId { get; }
|
// Allow sequence id to be manually set for potential message repeats
|
||||||
|
public long SequenceId { get; } = sequenceId > 0 ? sequenceId : SharpId.Next();
|
||||||
public ServerPacket(long sequenceId = 0) {
|
|
||||||
// Allow sequence id to be manually set for potential message repeats
|
|
||||||
SequenceId = sequenceId > 0 ? sequenceId : SharpId.Next();
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract IEnumerable<string> Pack();
|
public abstract IEnumerable<string> Pack();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,5 @@ namespace SharpChat.Misuzu {
|
||||||
|
|
||||||
[JsonPropertyName("perms")]
|
[JsonPropertyName("perms")]
|
||||||
public ChatUserPermissions Permissions { get; set; }
|
public ChatUserPermissions Permissions { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("super")]
|
|
||||||
public bool IsSuper { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,7 @@ namespace SharpChat.Misuzu {
|
||||||
private CachedValue<string> SecretKey { get; }
|
private CachedValue<string> SecretKey { get; }
|
||||||
|
|
||||||
public MisuzuClient(HttpClient httpClient, IConfig config) {
|
public MisuzuClient(HttpClient httpClient, IConfig config) {
|
||||||
if(config == null)
|
ArgumentNullException.ThrowIfNull(config);
|
||||||
throw new ArgumentNullException(nameof(config));
|
|
||||||
HttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
HttpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||||
|
|
||||||
BaseURL = config.ReadCached("url", DEFAULT_BASE_URL);
|
BaseURL = config.ReadCached("url", DEFAULT_BASE_URL);
|
||||||
|
@ -77,8 +76,7 @@ namespace SharpChat.Misuzu {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task BumpUsersOnlineAsync(IEnumerable<(string userId, string ipAddr)> list) {
|
public async Task BumpUsersOnlineAsync(IEnumerable<(string userId, string ipAddr)> list) {
|
||||||
if(list == null)
|
ArgumentNullException.ThrowIfNull(list);
|
||||||
throw new ArgumentNullException(nameof(list));
|
|
||||||
if(!list.Any())
|
if(!list.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -160,8 +158,7 @@ namespace SharpChat.Misuzu {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RevokeBanAsync(MisuzuBanInfo banInfo, BanRevokeKind kind) {
|
public async Task<bool> RevokeBanAsync(MisuzuBanInfo banInfo, BanRevokeKind kind) {
|
||||||
if(banInfo == null)
|
ArgumentNullException.ThrowIfNull(banInfo);
|
||||||
throw new ArgumentNullException(nameof(banInfo));
|
|
||||||
|
|
||||||
string type = kind switch {
|
string type = kind switch {
|
||||||
BanRevokeKind.UserId => "user",
|
BanRevokeKind.UserId => "user",
|
||||||
|
|
|
@ -3,23 +3,13 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class AuthSuccessPacket : ServerPacket {
|
public class AuthSuccessPacket(
|
||||||
public ChatUser User { get; private set; }
|
ChatUser user,
|
||||||
public ChatChannel Channel { get; private set; }
|
ChatChannel channel,
|
||||||
public ChatConnection Connection { get; private set; }
|
int maxMsgLength
|
||||||
public int MaxMessageLength { get; private set; }
|
) : ServerPacket {
|
||||||
|
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
public AuthSuccessPacket(
|
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||||
ChatUser user,
|
|
||||||
ChatChannel channel,
|
|
||||||
ChatConnection connection,
|
|
||||||
int maxMsgLength
|
|
||||||
) {
|
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
|
||||||
Channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
|
||||||
Connection = connection ?? throw new ArgumentNullException(nameof(connection));
|
|
||||||
MaxMessageLength = maxMsgLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
@ -30,9 +20,9 @@ namespace SharpChat.Packet {
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Channel.Name);
|
sb.Append(Channel.Name);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(MaxMessageLength);
|
sb.Append(maxMsgLength);
|
||||||
|
|
||||||
return new[] { sb.ToString() };
|
yield return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class BanListPacket : ServerPacket {
|
public class BanListPacket(IEnumerable<MisuzuBanInfo> bans) : ServerPacket {
|
||||||
public IEnumerable<MisuzuBanInfo> Bans { get; private set; }
|
public IEnumerable<MisuzuBanInfo> Bans { get; private set; } = bans ?? throw new ArgumentNullException(nameof(bans));
|
||||||
|
|
||||||
public BanListPacket(IEnumerable<MisuzuBanInfo> bans) {
|
|
||||||
Bans = bans ?? throw new ArgumentNullException(nameof(bans));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
@ -32,7 +28,7 @@ namespace SharpChat.Packet {
|
||||||
sb.Append(SequenceId);
|
sb.Append(SequenceId);
|
||||||
sb.Append("\t10010");
|
sb.Append("\t10010");
|
||||||
|
|
||||||
return new[] { sb.ToString() };
|
yield return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ChannelCreatePacket : ServerPacket {
|
public class ChannelCreatePacket(ChatChannel channel) : ServerPacket {
|
||||||
public ChatChannel Channel { get; private set; }
|
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||||
|
|
||||||
public ChannelCreatePacket(ChatChannel channel) {
|
|
||||||
Channel = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -3,12 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ChannelDeletePacket : ServerPacket {
|
public class ChannelDeletePacket(ChatChannel channel) : ServerPacket {
|
||||||
public ChatChannel Channel { get; private set; }
|
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||||
|
|
||||||
public ChannelDeletePacket(ChatChannel channel) {
|
|
||||||
Channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ChannelUpdatePacket : ServerPacket {
|
public class ChannelUpdatePacket(string previousName, ChatChannel channel) : ServerPacket {
|
||||||
public string PreviousName { get; private set; }
|
public string PreviousName { get; private set; } = previousName ?? throw new ArgumentNullException(nameof(previousName));
|
||||||
public ChatChannel Channel { get; private set; }
|
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||||
|
|
||||||
public ChannelUpdatePacket(string previousName, ChatChannel channel) {
|
|
||||||
PreviousName = previousName;
|
|
||||||
Channel = channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -1,46 +1,17 @@
|
||||||
using SharpChat.EventStorage;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ChatMessageAddPacket : ServerPacket {
|
public class ChatMessageAddPacket(
|
||||||
public DateTimeOffset Created { get; }
|
long msgId,
|
||||||
public long UserId { get; }
|
DateTimeOffset created,
|
||||||
public string Text { get; }
|
long userId,
|
||||||
public bool IsAction { get; }
|
string text,
|
||||||
public bool IsPrivate { get; }
|
bool isAction,
|
||||||
|
bool isPrivate
|
||||||
public ChatMessageAddPacket(
|
) : ServerPacket(msgId) {
|
||||||
long msgId,
|
public string Text { get; } = text ?? throw new ArgumentNullException(nameof(text));
|
||||||
DateTimeOffset created,
|
|
||||||
long userId,
|
|
||||||
string text,
|
|
||||||
bool isAction,
|
|
||||||
bool isPrivate
|
|
||||||
) : base(msgId) {
|
|
||||||
Created = created;
|
|
||||||
UserId = userId < 0 ? -1 : userId;
|
|
||||||
Text = text;
|
|
||||||
IsAction = isAction;
|
|
||||||
IsPrivate = isPrivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ChatMessageAddPacket FromStoredEvent(StoredEventInfo sei) {
|
|
||||||
if(sei == null)
|
|
||||||
throw new ArgumentNullException(nameof(sei));
|
|
||||||
if(sei.Type is not "msg:add" and not "SharpChat.Events.ChatMessage")
|
|
||||||
throw new ArgumentException("Wrong event type.", nameof(sei));
|
|
||||||
|
|
||||||
return new ChatMessageAddPacket(
|
|
||||||
sei.Id,
|
|
||||||
sei.Created,
|
|
||||||
sei.Sender?.UserId ?? -1,
|
|
||||||
string.Empty, // todo: this
|
|
||||||
(sei.Flags & StoredEventFlags.Action) > 0,
|
|
||||||
(sei.Flags & StoredEventFlags.Private) > 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
@ -48,13 +19,13 @@ namespace SharpChat.Packet {
|
||||||
sb.Append('2');
|
sb.Append('2');
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
||||||
sb.Append(Created.ToUnixTimeSeconds());
|
sb.Append(created.ToUnixTimeSeconds());
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
||||||
sb.Append(UserId);
|
sb.Append(userId);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
||||||
if(IsAction)
|
if(isAction)
|
||||||
sb.Append("<i>");
|
sb.Append("<i>");
|
||||||
|
|
||||||
sb.Append(
|
sb.Append(
|
||||||
|
@ -64,16 +35,16 @@ namespace SharpChat.Packet {
|
||||||
.Replace("\t", " ")
|
.Replace("\t", " ")
|
||||||
);
|
);
|
||||||
|
|
||||||
if(IsAction)
|
if(isAction)
|
||||||
sb.Append("</i>");
|
sb.Append("</i>");
|
||||||
|
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(SequenceId);
|
sb.Append(SequenceId);
|
||||||
sb.AppendFormat(
|
sb.AppendFormat(
|
||||||
"\t1{0}0{1}{2}",
|
"\t1{0}0{1}{2}",
|
||||||
IsAction ? '1' : '0',
|
isAction ? '1' : '0',
|
||||||
IsAction ? '0' : '1',
|
isAction ? '0' : '1',
|
||||||
IsPrivate ? '1' : '0'
|
isPrivate ? '1' : '0'
|
||||||
);
|
);
|
||||||
|
|
||||||
yield return sb.ToString();
|
yield return sb.ToString();
|
||||||
|
|
|
@ -2,19 +2,13 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ChatMessageDeletePacket : ServerPacket {
|
public class ChatMessageDeletePacket(long eventId) : ServerPacket {
|
||||||
public long EventId { get; private set; }
|
|
||||||
|
|
||||||
public ChatMessageDeletePacket(long eventId) {
|
|
||||||
EventId = eventId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
sb.Append('6');
|
sb.Append('6');
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(EventId);
|
sb.Append(eventId);
|
||||||
|
|
||||||
yield return sb.ToString();
|
yield return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ContextChannelsPacket : ServerPacket {
|
public class ContextChannelsPacket(IEnumerable<ChatChannel> channels) : ServerPacket {
|
||||||
public IEnumerable<ChatChannel> Channels { get; private set; }
|
public IEnumerable<ChatChannel> Channels { get; private set; } = channels?.Where(c => c != null) ?? throw new ArgumentNullException(nameof(channels));
|
||||||
|
|
||||||
public ContextChannelsPacket(IEnumerable<ChatChannel> channels) {
|
|
||||||
Channels = channels?.Where(c => c != null) ?? throw new ArgumentNullException(nameof(channels));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -10,24 +10,13 @@ namespace SharpChat.Packet {
|
||||||
MessagesUsersChannels = 4,
|
MessagesUsersChannels = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ContextClearPacket : ServerPacket {
|
public class ContextClearPacket(ContextClearMode mode) : ServerPacket {
|
||||||
public ChatChannel Channel { get; private set; }
|
|
||||||
public ContextClearMode Mode { get; private set; }
|
|
||||||
|
|
||||||
public bool IsGlobal
|
|
||||||
=> Channel == null;
|
|
||||||
|
|
||||||
public ContextClearPacket(ChatChannel channel, ContextClearMode mode) {
|
|
||||||
Channel = channel;
|
|
||||||
Mode = mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
sb.Append('8');
|
sb.Append('8');
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append((int)Mode);
|
sb.Append((int)mode);
|
||||||
|
|
||||||
yield return sb.ToString();
|
yield return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,8 @@ using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet
|
namespace SharpChat.Packet
|
||||||
{
|
{
|
||||||
public class ContextMessagePacket : ServerPacket {
|
public class ContextMessagePacket(StoredEventInfo evt, bool notify = false) : ServerPacket {
|
||||||
public StoredEventInfo Event { get; private set; }
|
public StoredEventInfo Event { get; private set; } = evt ?? throw new ArgumentNullException(nameof(evt));
|
||||||
public bool Notify { get; private set; }
|
|
||||||
|
|
||||||
public ContextMessagePacket(StoredEventInfo evt, bool notify = false) {
|
|
||||||
Event = evt ?? throw new ArgumentNullException(nameof(evt));
|
|
||||||
Notify = notify;
|
|
||||||
}
|
|
||||||
|
|
||||||
private const string V1_CHATBOT = "-1\tChatBot\tinherit\t\t";
|
private const string V1_CHATBOT = "-1\tChatBot\tinherit\t\t";
|
||||||
|
|
||||||
|
@ -106,7 +100,7 @@ namespace SharpChat.Packet
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Event.Id < 1 ? SequenceId : Event.Id);
|
sb.Append(Event.Id < 1 ? SequenceId : Event.Id);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Notify ? '1' : '0');
|
sb.Append(notify ? '1' : '0');
|
||||||
sb.AppendFormat(
|
sb.AppendFormat(
|
||||||
"\t1{0}0{1}{2}",
|
"\t1{0}0{1}{2}",
|
||||||
isAction ? '1' : '0',
|
isAction ? '1' : '0',
|
||||||
|
|
|
@ -4,12 +4,8 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class ContextUsersPacket : ServerPacket {
|
public class ContextUsersPacket(IEnumerable<ChatUser> users) : ServerPacket {
|
||||||
public IEnumerable<ChatUser> Users { get; private set; }
|
public IEnumerable<ChatUser> Users { get; private set; } = users?.Where(u => u != null) ?? throw new ArgumentNullException(nameof(users));
|
||||||
|
|
||||||
public ContextUsersPacket(IEnumerable<ChatUser> users) {
|
|
||||||
Users = users?.Where(u => u != null) ?? throw new ArgumentNullException(nameof(users));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -1,23 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class LegacyCommandResponse : ServerPacket {
|
public class LegacyCommandResponse(
|
||||||
public bool IsError { get; private set; }
|
string stringId,
|
||||||
public string StringId { get; private set; }
|
bool isError = true,
|
||||||
public IEnumerable<object> Arguments { get; private set; }
|
params object[] args
|
||||||
|
) : ServerPacket {
|
||||||
public LegacyCommandResponse(
|
public string StringId { get; private set; } = stringId ?? throw new ArgumentNullException(nameof(stringId));
|
||||||
string stringId,
|
|
||||||
bool isError = true,
|
|
||||||
params object[] args
|
|
||||||
) {
|
|
||||||
IsError = isError;
|
|
||||||
StringId = stringId;
|
|
||||||
Arguments = args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
@ -36,12 +27,12 @@ namespace SharpChat.Packet {
|
||||||
sb.Append("\t-1\t");
|
sb.Append("\t-1\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Append(IsError ? '1' : '0');
|
sb.Append(isError ? '1' : '0');
|
||||||
sb.Append('\f');
|
sb.Append('\f');
|
||||||
sb.Append(StringId == LCR.WELCOME ? LCR.BROADCAST : StringId);
|
sb.Append(StringId == LCR.WELCOME ? LCR.BROADCAST : StringId);
|
||||||
|
|
||||||
if(Arguments?.Any() == true)
|
if(args.Length > 0)
|
||||||
foreach(object arg in Arguments) {
|
foreach(object arg in args) {
|
||||||
sb.Append('\f');
|
sb.Append('\f');
|
||||||
sb.Append(arg);
|
sb.Append(arg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class PongPacket : ServerPacket {
|
public class PongPacket : ServerPacket {
|
||||||
|
|
|
@ -3,12 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class UserChannelForceJoinPacket : ServerPacket {
|
public class UserChannelForceJoinPacket(ChatChannel channel) : ServerPacket {
|
||||||
public ChatChannel Channel { get; private set; }
|
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||||
|
|
||||||
public UserChannelForceJoinPacket(ChatChannel channel) {
|
|
||||||
Channel = channel ?? throw new ArgumentNullException(nameof(channel));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -3,12 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class UserChannelJoinPacket : ServerPacket {
|
public class UserChannelJoinPacket(ChatUser user) : ServerPacket {
|
||||||
public ChatUser User { get; private set; }
|
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
|
|
||||||
public UserChannelJoinPacket(ChatUser user) {
|
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
@ -21,7 +17,7 @@ namespace SharpChat.Packet {
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(SequenceId);
|
sb.Append(SequenceId);
|
||||||
|
|
||||||
return new[] { sb.ToString() };
|
yield return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,8 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class UserChannelLeavePacket : ServerPacket {
|
public class UserChannelLeavePacket(ChatUser user) : ServerPacket {
|
||||||
public ChatUser User { get; private set; }
|
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
|
|
||||||
public UserChannelLeavePacket(ChatUser user) {
|
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
|
@ -3,21 +3,15 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class UserConnectPacket : ServerPacket {
|
public class UserConnectPacket(DateTimeOffset joined, ChatUser user) : ServerPacket {
|
||||||
public DateTimeOffset Joined { get; private set; }
|
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
public ChatUser User { get; private set; }
|
|
||||||
|
|
||||||
public UserConnectPacket(DateTimeOffset joined, ChatUser user) {
|
|
||||||
Joined = joined;
|
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
sb.Append('1');
|
sb.Append('1');
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Joined.ToUnixTimeSeconds());
|
sb.Append(joined.ToUnixTimeSeconds());
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(User.Pack());
|
sb.Append(User.Pack());
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
|
@ -10,16 +10,8 @@ namespace SharpChat.Packet {
|
||||||
Flood,
|
Flood,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserDisconnectPacket : ServerPacket {
|
public class UserDisconnectPacket(DateTimeOffset disconnected, ChatUser user, UserDisconnectReason reason) : ServerPacket {
|
||||||
public DateTimeOffset Disconnected { get; private set; }
|
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
public ChatUser User { get; private set; }
|
|
||||||
public UserDisconnectReason Reason { get; private set; }
|
|
||||||
|
|
||||||
public UserDisconnectPacket(DateTimeOffset disconnected, ChatUser user, UserDisconnectReason reason) {
|
|
||||||
Disconnected = disconnected;
|
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
|
||||||
Reason = reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
@ -31,7 +23,7 @@ namespace SharpChat.Packet {
|
||||||
sb.Append(User.LegacyNameWithStatus);
|
sb.Append(User.LegacyNameWithStatus);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
||||||
switch(Reason) {
|
switch(reason) {
|
||||||
case UserDisconnectReason.Leave:
|
case UserDisconnectReason.Leave:
|
||||||
default:
|
default:
|
||||||
sb.Append("leave");
|
sb.Append("leave");
|
||||||
|
@ -48,11 +40,11 @@ namespace SharpChat.Packet {
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(Disconnected.ToUnixTimeSeconds());
|
sb.Append(disconnected.ToUnixTimeSeconds());
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(SequenceId);
|
sb.Append(SequenceId);
|
||||||
|
|
||||||
return new[] { sb.ToString() };
|
yield return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,20 @@ using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.Packet {
|
namespace SharpChat.Packet {
|
||||||
public class UserUpdatePacket : ServerPacket {
|
public class UserUpdatePacket(ChatUser user, string previousName = "") : ServerPacket {
|
||||||
public ChatUser User { get; private set; }
|
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||||
public string PreviousName { get; private set; }
|
|
||||||
|
|
||||||
public UserUpdatePacket(ChatUser user, string previousName = null) {
|
|
||||||
User = user ?? throw new ArgumentNullException(nameof(user));
|
|
||||||
PreviousName = previousName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IEnumerable<string> Pack() {
|
public override IEnumerable<string> Pack() {
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
|
|
||||||
bool isSilent = string.IsNullOrEmpty(PreviousName);
|
bool isSilent = string.IsNullOrEmpty(previousName);
|
||||||
|
|
||||||
if(!isSilent) {
|
if(!isSilent) {
|
||||||
sb.Append('2');
|
sb.Append('2');
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
|
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
|
||||||
sb.Append("\t-1\t0\fnick\f");
|
sb.Append("\t-1\t0\fnick\f");
|
||||||
sb.Append(PreviousName);
|
sb.Append(previousName);
|
||||||
sb.Append('\f');
|
sb.Append('\f');
|
||||||
sb.Append(User.LegacyNameWithStatus);
|
sb.Append(User.LegacyNameWithStatus);
|
||||||
sb.Append('\t');
|
sb.Append('\t');
|
||||||
|
|
|
@ -8,23 +8,16 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharpChat.PacketHandlers {
|
namespace SharpChat.PacketHandlers {
|
||||||
public class AuthHandler : IChatPacketHandler {
|
public class AuthHandler(
|
||||||
private readonly MisuzuClient Misuzu;
|
MisuzuClient msz,
|
||||||
private readonly ChatChannel DefaultChannel;
|
ChatChannel defaultChannel,
|
||||||
private readonly CachedValue<int> MaxMessageLength;
|
CachedValue<int> maxMsgLength,
|
||||||
private readonly CachedValue<int> MaxConnections;
|
CachedValue<int> maxConns
|
||||||
|
) : IChatPacketHandler {
|
||||||
public AuthHandler(
|
private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
||||||
MisuzuClient msz,
|
private readonly ChatChannel DefaultChannel = defaultChannel ?? throw new ArgumentNullException(nameof(defaultChannel));
|
||||||
ChatChannel defaultChannel,
|
private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
|
||||||
CachedValue<int> maxMsgLength,
|
private readonly CachedValue<int> MaxConnections = maxConns ?? throw new ArgumentNullException(nameof(maxConns));
|
||||||
CachedValue<int> maxConns
|
|
||||||
) {
|
|
||||||
Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
|
||||||
DefaultChannel = defaultChannel ?? throw new ArgumentNullException(nameof(defaultChannel));
|
|
||||||
MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
|
|
||||||
MaxConnections = maxConns ?? throw new ArgumentNullException(nameof(maxConns));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatPacketHandlerContext ctx) {
|
public bool IsMatch(ChatPacketHandlerContext ctx) {
|
||||||
return ctx.CheckPacketId("1");
|
return ctx.CheckPacketId("1");
|
||||||
|
@ -108,8 +101,7 @@ namespace SharpChat.PacketHandlers {
|
||||||
fai.UserName,
|
fai.UserName,
|
||||||
fai.Colour,
|
fai.Colour,
|
||||||
fai.Rank,
|
fai.Rank,
|
||||||
fai.Permissions,
|
fai.Permissions
|
||||||
isSuper: fai.IsSuper
|
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
ctx.Chat.UpdateUser(
|
ctx.Chat.UpdateUser(
|
||||||
|
@ -117,8 +109,7 @@ namespace SharpChat.PacketHandlers {
|
||||||
userName: fai.UserName,
|
userName: fai.UserName,
|
||||||
colour: fai.Colour,
|
colour: fai.Colour,
|
||||||
rank: fai.Rank,
|
rank: fai.Rank,
|
||||||
perms: fai.Permissions,
|
perms: fai.Permissions
|
||||||
isSuper: fai.IsSuper
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Enforce a maximum amount of connections per user
|
// Enforce a maximum amount of connections per user
|
||||||
|
|
|
@ -5,16 +5,12 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharpChat.PacketHandlers {
|
namespace SharpChat.PacketHandlers {
|
||||||
public class PingHandler : IChatPacketHandler {
|
public class PingHandler(MisuzuClient msz) : IChatPacketHandler {
|
||||||
private readonly MisuzuClient Misuzu;
|
private readonly MisuzuClient Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
||||||
|
|
||||||
private readonly TimeSpan BumpInterval = TimeSpan.FromMinutes(1);
|
private readonly TimeSpan BumpInterval = TimeSpan.FromMinutes(1);
|
||||||
private DateTimeOffset LastBump = DateTimeOffset.MinValue;
|
private DateTimeOffset LastBump = DateTimeOffset.MinValue;
|
||||||
|
|
||||||
public PingHandler(MisuzuClient msz) {
|
|
||||||
Misuzu = msz ?? throw new ArgumentNullException(nameof(msz));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMatch(ChatPacketHandlerContext ctx) {
|
public bool IsMatch(ChatPacketHandlerContext ctx) {
|
||||||
return ctx.CheckPacketId("0");
|
return ctx.CheckPacketId("0");
|
||||||
}
|
}
|
||||||
|
@ -31,12 +27,11 @@ namespace SharpChat.PacketHandlers {
|
||||||
ctx.Chat.ContextAccess.Wait();
|
ctx.Chat.ContextAccess.Wait();
|
||||||
try {
|
try {
|
||||||
if(LastBump < DateTimeOffset.UtcNow - BumpInterval) {
|
if(LastBump < DateTimeOffset.UtcNow - BumpInterval) {
|
||||||
(string, string)[] bumpList = ctx.Chat.Users
|
(string, string)[] bumpList = [.. ctx.Chat.Users
|
||||||
.Where(u => u.Status == ChatUserStatus.Online && ctx.Chat.Connections.Any(c => c.User == u))
|
.Where(u => u.Status == ChatUserStatus.Online && ctx.Chat.Connections.Any(c => c.User == u))
|
||||||
.Select(u => (u.UserId.ToString(), ctx.Chat.GetRemoteAddresses(u).FirstOrDefault()?.ToString() ?? string.Empty))
|
.Select(u => (u.UserId.ToString(), ctx.Chat.GetRemoteAddresses(u).FirstOrDefault()?.ToString() ?? string.Empty))];
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if(bumpList.Any())
|
if(bumpList.Length > 0)
|
||||||
Task.Run(async () => {
|
Task.Run(async () => {
|
||||||
await Misuzu.BumpUsersOnlineAsync(bumpList);
|
await Misuzu.BumpUsersOnlineAsync(bumpList);
|
||||||
}).Wait();
|
}).Wait();
|
||||||
|
|
|
@ -1,24 +1,16 @@
|
||||||
using SharpChat.Commands;
|
using SharpChat.Config;
|
||||||
using SharpChat.Config;
|
|
||||||
using SharpChat.Events;
|
using SharpChat.Events;
|
||||||
using SharpChat.EventStorage;
|
|
||||||
using SharpChat.Packet;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace SharpChat.PacketHandlers
|
namespace SharpChat.PacketHandlers {
|
||||||
{
|
public class SendMessageHandler(CachedValue<int> maxMsgLength) : IChatPacketHandler {
|
||||||
public class SendMessageHandler : IChatPacketHandler {
|
private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
|
||||||
private readonly CachedValue<int> MaxMessageLength;
|
|
||||||
|
|
||||||
private List<IChatCommand> Commands { get; } = new();
|
private List<IChatCommand> Commands { get; } = [];
|
||||||
|
|
||||||
public SendMessageHandler(CachedValue<int> maxMsgLength) {
|
|
||||||
MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddCommand(IChatCommand command) {
|
public void AddCommand(IChatCommand command) {
|
||||||
Commands.Add(command ?? throw new ArgumentNullException(nameof(command)));
|
Commands.Add(command ?? throw new ArgumentNullException(nameof(command)));
|
||||||
|
@ -57,7 +49,7 @@ namespace SharpChat.PacketHandlers
|
||||||
ctx.Chat.UpdateUser(user, status: ChatUserStatus.Online);
|
ctx.Chat.UpdateUser(user, status: ChatUserStatus.Online);
|
||||||
|
|
||||||
int maxMsgLength = MaxMessageLength;
|
int maxMsgLength = MaxMessageLength;
|
||||||
StringInfo messageTextInfo = new StringInfo(messageText);
|
StringInfo messageTextInfo = new(messageText);
|
||||||
if(Encoding.UTF8.GetByteCount(messageText) > (maxMsgLength * 10)
|
if(Encoding.UTF8.GetByteCount(messageText) > (maxMsgLength * 10)
|
||||||
|| messageTextInfo.LengthInTextElements > maxMsgLength)
|
|| messageTextInfo.LengthInTextElements > maxMsgLength)
|
||||||
messageText = messageTextInfo.SubstringByTextElements(0, Math.Min(messageTextInfo.LengthInTextElements, maxMsgLength));
|
messageText = messageTextInfo.SubstringByTextElements(0, Math.Min(messageTextInfo.LengthInTextElements, maxMsgLength));
|
||||||
|
@ -68,7 +60,7 @@ namespace SharpChat.PacketHandlers
|
||||||
Logger.Write($"<{ctx.Connection.Id} {user.UserName}> {messageText}");
|
Logger.Write($"<{ctx.Connection.Id} {user.UserName}> {messageText}");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(messageText.StartsWith("/")) {
|
if(messageText.StartsWith('/')) {
|
||||||
ChatCommandContext context = new(messageText, ctx.Chat, user, ctx.Connection, channel);
|
ChatCommandContext context = new(messageText, ctx.Chat, user, ctx.Connection, channel);
|
||||||
|
|
||||||
IChatCommand command = null;
|
IChatCommand command = null;
|
||||||
|
@ -87,8 +79,13 @@ namespace SharpChat.PacketHandlers
|
||||||
|
|
||||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||||
SharpId.Next(),
|
SharpId.Next(),
|
||||||
channel,
|
channel.Name,
|
||||||
user,
|
user.UserId,
|
||||||
|
user.UserName,
|
||||||
|
user.Colour,
|
||||||
|
user.Rank,
|
||||||
|
user.NickName,
|
||||||
|
user.Permissions,
|
||||||
DateTimeOffset.Now,
|
DateTimeOffset.Now,
|
||||||
messageText,
|
messageText,
|
||||||
false, false, false
|
false, false, false
|
||||||
|
|
|
@ -45,7 +45,7 @@ namespace SharpChat {
|
||||||
if(!File.Exists(configFile) && configFile == CONFIG)
|
if(!File.Exists(configFile) && configFile == CONFIG)
|
||||||
ConvertConfiguration();
|
ConvertConfiguration();
|
||||||
|
|
||||||
using IConfig config = new StreamConfig(configFile);
|
using StreamConfig config = StreamConfig.FromPath(configFile);
|
||||||
|
|
||||||
if(hasCancelled) return;
|
if(hasCancelled) return;
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ namespace SharpChat {
|
||||||
|
|
||||||
|
|
||||||
const string mdb_config = @"mariadb.txt";
|
const string mdb_config = @"mariadb.txt";
|
||||||
string[] mdbCfg = File.Exists(mdb_config) ? File.ReadAllLines(mdb_config) : Array.Empty<string>();
|
string[] mdbCfg = File.Exists(mdb_config) ? File.ReadAllLines(mdb_config) : [];
|
||||||
|
|
||||||
sw.WriteLine();
|
sw.WriteLine();
|
||||||
sw.WriteLine("# MariaDB configuration");
|
sw.WriteLine("# MariaDB configuration");
|
||||||
|
|
|
@ -2,12 +2,20 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<NoWarn>1701;1702</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Fleck" Version="1.2.0" />
|
<PackageReference Include="Fleck" Version="1.2.0" />
|
||||||
<PackageReference Include="MySqlConnector" Version="2.2.5" />
|
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
ListenerSocket = new SocketWrapper(socket);
|
ListenerSocket = new SocketWrapper(socket);
|
||||||
SupportedSubProtocols = Array.Empty<string>();
|
SupportedSubProtocols = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISocket ListenerSocket { get; set; }
|
public ISocket ListenerSocket { get; set; }
|
||||||
|
|
|
@ -30,12 +30,14 @@ namespace SharpChat {
|
||||||
private readonly CachedValue<int> FloodKickLength;
|
private readonly CachedValue<int> FloodKickLength;
|
||||||
private readonly CachedValue<int> FloodKickExemptRank;
|
private readonly CachedValue<int> FloodKickExemptRank;
|
||||||
|
|
||||||
private readonly List<IChatPacketHandler> GuestHandlers = new();
|
private readonly List<IChatPacketHandler> GuestHandlers = [];
|
||||||
private readonly List<IChatPacketHandler> AuthedHandlers = new();
|
private readonly List<IChatPacketHandler> AuthedHandlers = [];
|
||||||
private readonly SendMessageHandler SendMessageHandler;
|
private readonly SendMessageHandler SendMessageHandler;
|
||||||
|
|
||||||
private bool IsShuttingDown = false;
|
private bool IsShuttingDown = false;
|
||||||
|
|
||||||
|
private static readonly string[] DEFAULT_CHANNELS = ["lounge"];
|
||||||
|
|
||||||
private ChatChannel DefaultChannel { get; set; }
|
private ChatChannel DefaultChannel { get; set; }
|
||||||
|
|
||||||
public SockChatServer(HttpClient httpClient, MisuzuClient msz, IEventStorage evtStore, IConfig config) {
|
public SockChatServer(HttpClient httpClient, MisuzuClient msz, IEventStorage evtStore, IConfig config) {
|
||||||
|
@ -51,7 +53,7 @@ namespace SharpChat {
|
||||||
|
|
||||||
Context = new ChatContext(evtStore);
|
Context = new ChatContext(evtStore);
|
||||||
|
|
||||||
string[] channelNames = config.ReadValue("channels", new[] { "lounge" });
|
string[] channelNames = config.ReadValue("channels", DEFAULT_CHANNELS);
|
||||||
|
|
||||||
foreach(string channelName in channelNames) {
|
foreach(string channelName in channelNames) {
|
||||||
IConfig channelCfg = config.ScopeTo($"channels:{channelName}");
|
IConfig channelCfg = config.ScopeTo($"channels:{channelName}");
|
||||||
|
@ -72,12 +74,12 @@ namespace SharpChat {
|
||||||
|
|
||||||
GuestHandlers.Add(new AuthHandler(Misuzu, DefaultChannel, MaxMessageLength, MaxConnections));
|
GuestHandlers.Add(new AuthHandler(Misuzu, DefaultChannel, MaxMessageLength, MaxConnections));
|
||||||
|
|
||||||
AuthedHandlers.AddRange(new IChatPacketHandler[] {
|
AuthedHandlers.AddRange([
|
||||||
new PingHandler(Misuzu),
|
new PingHandler(Misuzu),
|
||||||
SendMessageHandler = new SendMessageHandler(MaxMessageLength),
|
SendMessageHandler = new SendMessageHandler(MaxMessageLength),
|
||||||
});
|
]);
|
||||||
|
|
||||||
SendMessageHandler.AddCommands(new IChatCommand[] {
|
SendMessageHandler.AddCommands([
|
||||||
new AFKCommand(),
|
new AFKCommand(),
|
||||||
new NickCommand(),
|
new NickCommand(),
|
||||||
new WhisperCommand(),
|
new WhisperCommand(),
|
||||||
|
@ -95,7 +97,7 @@ namespace SharpChat {
|
||||||
new PardonAddressCommand(msz),
|
new PardonAddressCommand(msz),
|
||||||
new BanListCommand(msz),
|
new BanListCommand(msz),
|
||||||
new RemoteAddressCommand(),
|
new RemoteAddressCommand(),
|
||||||
});
|
]);
|
||||||
|
|
||||||
ushort port = config.SafeReadValue("port", DEFAULT_PORT);
|
ushort port = config.SafeReadValue("port", DEFAULT_PORT);
|
||||||
Server = new SharpChatWebSocketServer($"ws://0.0.0.0:{port}");
|
Server = new SharpChatWebSocketServer($"ws://0.0.0.0:{port}");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue