Switched to file namespace declarations.

This commit is contained in:
flash 2025-04-26 23:15:54 +00:00
parent 6593929827
commit 34e4e9b1a9
Signed by: flash
GPG key ID: 2C9C2C574D47FE3E
93 changed files with 3470 additions and 3471 deletions
.editorconfig
SharpChat.Flashii
SharpChat.SockChat
SharpChat
SharpChatCommon

View file

@ -15,7 +15,7 @@ csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:suggestion csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_braces = true:silent csharp_prefer_braces = true:silent
csharp_style_namespace_declarations = block_scoped:silent csharp_style_namespace_declarations = file_scoped:silent
csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_method_group_conversion = true:silent
csharp_style_prefer_top_level_statements = true:silent csharp_style_prefer_top_level_statements = true:silent
csharp_style_prefer_primary_constructors = true:suggestion csharp_style_prefer_primary_constructors = true:suggestion

View file

@ -1,8 +1,9 @@
using SharpChat.Auth; using SharpChat.Auth;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace SharpChat.Flashii { namespace SharpChat.Flashii;
public class FlashiiAuthResult : AuthResult {
public class FlashiiAuthResult : AuthResult {
public string UserId => UserIdRaw.ToString(); public string UserId => UserIdRaw.ToString();
public string UserName => UserNameRaw ?? string.Empty; public string UserName => UserNameRaw ?? string.Empty;
public ColourInheritable UserColour => ColourInheritable.FromMisuzu(UserColourRaw); public ColourInheritable UserColour => ColourInheritable.FromMisuzu(UserColourRaw);
@ -27,5 +28,4 @@ namespace SharpChat.Flashii {
[JsonPropertyName("perms")] [JsonPropertyName("perms")]
public UserPermissions UserPermissions { get; init; } public UserPermissions UserPermissions { get; init; }
}
} }

View file

@ -1,13 +1,13 @@
using SharpChat.Bans; using SharpChat.Bans;
namespace SharpChat.Flashii { namespace SharpChat.Flashii;
public abstract class FlashiiBanInfo(
public abstract class FlashiiBanInfo(
BanKind kind, BanKind kind,
FlashiiRawBanInfo rawBanInfo FlashiiRawBanInfo rawBanInfo
) : BanInfo { ) : BanInfo {
public BanKind Kind { get; } = kind; public BanKind Kind { get; } = kind;
public bool IsPermanent { get; } = rawBanInfo.IsPermanent; public bool IsPermanent { get; } = rawBanInfo.IsPermanent;
public DateTimeOffset ExpiresAt { get; } = rawBanInfo.ExpiresAt; public DateTimeOffset ExpiresAt { get; } = rawBanInfo.ExpiresAt;
public abstract override string ToString(); public abstract override string ToString();
}
} }

View file

@ -6,8 +6,9 @@ using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
namespace SharpChat.Flashii { namespace SharpChat.Flashii;
public class FlashiiClient(HttpClient httpClient, Config config) : AuthClient, BansClient {
public class FlashiiClient(HttpClient httpClient, Config config) : AuthClient, BansClient {
private const string DEFAULT_BASE_URL = "https://flashii.net/_sockchat"; private const string DEFAULT_BASE_URL = "https://flashii.net/_sockchat";
private readonly CachedValue<string> BaseURL = config.ReadCached("url", DEFAULT_BASE_URL); private readonly CachedValue<string> BaseURL = config.ReadCached("url", DEFAULT_BASE_URL);
@ -236,5 +237,4 @@ namespace SharpChat.Flashii {
? new FlashiiUserBanInfo(b) : new FlashiiIPAddressBanInfo(b)); ? new FlashiiUserBanInfo(b) : new FlashiiIPAddressBanInfo(b));
})]; })];
} }
}
} }

View file

@ -1,9 +1,9 @@
using SharpChat.Bans; using SharpChat.Bans;
using System.Net; using System.Net;
namespace SharpChat.Flashii { namespace SharpChat.Flashii;
public class FlashiiIPAddressBanInfo(FlashiiRawBanInfo rawBanInfo) : FlashiiBanInfo(BanKind.IPAddress, rawBanInfo), IPAddressBanInfo {
public class FlashiiIPAddressBanInfo(FlashiiRawBanInfo rawBanInfo) : FlashiiBanInfo(BanKind.IPAddress, rawBanInfo), IPAddressBanInfo {
public IPAddress Address { get; } = IPAddress.TryParse(rawBanInfo.RemoteAddress, out IPAddress? addr) && addr is not null ? addr : IPAddress.IPv6None; public IPAddress Address { get; } = IPAddress.TryParse(rawBanInfo.RemoteAddress, out IPAddress? addr) && addr is not null ? addr : IPAddress.IPv6None;
public override string ToString() => Address.ToString(); public override string ToString() => Address.ToString();
}
} }

View file

@ -1,7 +1,8 @@
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace SharpChat.Flashii { namespace SharpChat.Flashii;
public class FlashiiRawBanInfo {
public class FlashiiRawBanInfo {
[JsonPropertyName("is_ban")] [JsonPropertyName("is_ban")]
public bool IsBanned { get; set; } public bool IsBanned { get; set; }
@ -25,5 +26,4 @@ namespace SharpChat.Flashii {
public DateTimeOffset ExpiresAt { get; set; } public DateTimeOffset ExpiresAt { get; set; }
public bool HasExpired => !IsPermanent && DateTimeOffset.UtcNow >= ExpiresAt; public bool HasExpired => !IsPermanent && DateTimeOffset.UtcNow >= ExpiresAt;
}
} }

View file

@ -1,10 +1,10 @@
using SharpChat.Bans; using SharpChat.Bans;
namespace SharpChat.Flashii { namespace SharpChat.Flashii;
public class FlashiiUserBanInfo(FlashiiRawBanInfo rawBanInfo) : FlashiiBanInfo(BanKind.User, rawBanInfo), UserBanInfo {
public class FlashiiUserBanInfo(FlashiiRawBanInfo rawBanInfo) : FlashiiBanInfo(BanKind.User, rawBanInfo), UserBanInfo {
public string UserId { get; } = rawBanInfo.UserId ?? string.Empty; public string UserId { get; } = rawBanInfo.UserId ?? string.Empty;
public string UserName { get; } = rawBanInfo.UserName ?? $"({rawBanInfo.UserId ?? string.Empty})"; public string UserName { get; } = rawBanInfo.UserName ?? $"({rawBanInfo.UserId ?? string.Empty})";
public ColourInheritable UserColour { get; } = ColourInheritable.FromMisuzu(rawBanInfo.UserColourRaw); public ColourInheritable UserColour { get; } = ColourInheritable.FromMisuzu(rawBanInfo.UserColourRaw);
public override string ToString() => UserName; public override string ToString() => UserName;
}
} }

View file

@ -1,5 +1,5 @@
namespace SharpChat.SockChat { namespace SharpChat.SockChat;
public interface S2CPacket {
public interface S2CPacket {
string Pack(); string Pack();
}
} }

View file

@ -1,10 +1,11 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class AuthFailS2CPacket(
public class AuthFailS2CPacket(
AuthFailS2CPacket.Reason reason, AuthFailS2CPacket.Reason reason,
DateTimeOffset? expiresAt = null DateTimeOffset? expiresAt = null
) : S2CPacket { ) : S2CPacket {
public enum Reason { public enum Reason {
AuthInvalid, AuthInvalid,
MaxSessions, MaxSessions,
@ -39,5 +40,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class AuthSuccessS2CPacket(
public class AuthSuccessS2CPacket(
string userId, string userId,
string userName, string userName,
ColourInheritable userColour, ColourInheritable userColour,
@ -9,7 +10,7 @@ namespace SharpChat.SockChat.S2CPackets {
UserPermissions userPerms, UserPermissions userPerms,
string channelName, string channelName,
int maxMsgLength int maxMsgLength
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -36,5 +37,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,11 +1,12 @@
using SharpChat.Bans; using SharpChat.Bans;
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class BanListS2CPacket(
public class BanListS2CPacket(
long msgId, long msgId,
IEnumerable<BanListS2CPacket.Entry> entries IEnumerable<BanListS2CPacket.Entry> entries
) : S2CPacket { ) : S2CPacket {
public record Entry(BanKind type, string value); public record Entry(BanKind type, string value);
public string Pack() { public string Pack() {
@ -25,5 +26,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,11 +1,12 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ChannelCreateS2CPacket(
public class ChannelCreateS2CPacket(
string name, string name,
bool hasPassword, bool hasPassword,
bool isTemporary bool isTemporary
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -18,5 +19,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,9 +1,10 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ChannelDeleteS2CPacket(
public class ChannelDeleteS2CPacket(
string channelName string channelName
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -12,5 +13,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,12 +1,13 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ChannelUpdateS2CPacket(
public class ChannelUpdateS2CPacket(
string previousName, string previousName,
string newName, string newName,
bool hasPassword, bool hasPassword,
bool isTemporary bool isTemporary
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -21,5 +22,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,14 +1,15 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ChatMessageAddS2CPacket(
public class ChatMessageAddS2CPacket(
long msgId, long msgId,
DateTimeOffset created, DateTimeOffset created,
string userId, string userId,
string text, string text,
bool isAction, bool isAction,
bool isPrivate bool isPrivate
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -44,5 +45,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ChatMessageDeleteS2CPacket(long eventId) : S2CPacket {
public class ChatMessageDeleteS2CPacket(long eventId) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -10,5 +11,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,12 +1,13 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class CommandResponseS2CPacket(
public class CommandResponseS2CPacket(
long msgId, long msgId,
string stringId, string stringId,
bool isError = true, bool isError = true,
params object[] args params object[] args
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -48,10 +49,10 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
} }
// Abbreviated class name because otherwise shit gets wide // Abbreviated class name because otherwise shit gets wide
public static class LCR { public static class LCR {
public const string GENERIC_ERROR = "generr"; public const string GENERIC_ERROR = "generr";
public const string COMMAND_NOT_FOUND = "nocmd"; public const string COMMAND_NOT_FOUND = "nocmd";
public const string COMMAND_NOT_ALLOWED = "cmdna"; public const string COMMAND_NOT_ALLOWED = "cmdna";
@ -81,5 +82,4 @@ namespace SharpChat.SockChat.S2CPackets {
public const string USER_UNBANNED = "unban"; public const string USER_UNBANNED = "unban";
public const string FLOOD_WARN = "flwarn"; public const string FLOOD_WARN = "flwarn";
public const string NICKNAME_CHANGE = "nick"; public const string NICKNAME_CHANGE = "nick";
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ContextChannelsS2CPacket(IEnumerable<ContextChannelsS2CPacket.Entry> entries) : S2CPacket {
public class ContextChannelsS2CPacket(IEnumerable<ContextChannelsS2CPacket.Entry> entries) : S2CPacket {
public record Entry(string name, bool hasPassword, bool isTemporary); public record Entry(string name, bool hasPassword, bool isTemporary);
public string Pack() { public string Pack() {
@ -21,5 +22,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ContextClearS2CPacket(ContextClearS2CPacket.Mode mode) : S2CPacket {
public class ContextClearS2CPacket(ContextClearS2CPacket.Mode mode) : S2CPacket {
public enum Mode { public enum Mode {
Messages = 0, Messages = 0,
Users = 1, Users = 1,
@ -18,5 +19,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ContextUsersS2CPacket(IEnumerable<ContextUsersS2CPacket.Entry> entries) : S2CPacket {
public class ContextUsersS2CPacket(IEnumerable<ContextUsersS2CPacket.Entry> entries) : S2CPacket {
public record Entry(string id, string name, ColourInheritable colour, int rank, UserPermissions perms, bool visible); public record Entry(string id, string name, ColourInheritable colour, int rank, UserPermissions perms, bool visible);
public string Pack() { public string Pack() {
@ -33,5 +34,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ForceDisconnectS2CPacket(DateTimeOffset? expires = null) : S2CPacket {
public class ForceDisconnectS2CPacket(DateTimeOffset? expires = null) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -18,5 +19,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,7 @@
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class PongS2CPacket : S2CPacket {
public class PongS2CPacket : S2CPacket {
public string Pack() { public string Pack() {
return "0\tpong"; return "0\tpong";
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class UserChannelForceJoinS2CPacket(string channelName) : S2CPacket {
public class UserChannelForceJoinS2CPacket(string channelName) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -10,5 +11,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,14 +1,15 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class UserChannelJoinS2CPacket(
public class UserChannelJoinS2CPacket(
long msgId, long msgId,
string userId, string userId,
string userName, string userName,
ColourInheritable userColour, ColourInheritable userColour,
int userRank, int userRank,
UserPermissions userPerms UserPermissions userPerms
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -33,5 +34,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class UserChannelLeaveS2CPacket(long msgId, string userId) : S2CPacket {
public class UserChannelLeaveS2CPacket(long msgId, string userId) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -12,5 +13,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class UserConnectS2CPacket(
public class UserConnectS2CPacket(
long msgId, long msgId,
DateTimeOffset joined, DateTimeOffset joined,
string userId, string userId,
@ -9,7 +10,7 @@ namespace SharpChat.SockChat.S2CPackets {
ColourInheritable userColour, ColourInheritable userColour,
int userRank, int userRank,
UserPermissions userPerms UserPermissions userPerms
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -36,5 +37,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,13 +1,14 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class UserDisconnectS2CPacket(
public class UserDisconnectS2CPacket(
long msgId, long msgId,
DateTimeOffset disconnected, DateTimeOffset disconnected,
string userId, string userId,
string userName, string userName,
UserDisconnectS2CPacket.Reason reason UserDisconnectS2CPacket.Reason reason
) : S2CPacket { ) : S2CPacket {
public enum Reason { public enum Reason {
Leave, Leave,
TimeOut, TimeOut,
@ -47,5 +48,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,13 +1,14 @@
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class UserUpdateS2CPacket(
public class UserUpdateS2CPacket(
string userId, string userId,
string userName, string userName,
ColourInheritable userColour, ColourInheritable userColour,
int userRank, int userRank,
UserPermissions userPerms UserPermissions userPerms
) : S2CPacket { ) : S2CPacket {
public string Pack() { public string Pack() {
StringBuilder sb = new(); StringBuilder sb = new();
@ -30,5 +31,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -1,6 +1,6 @@
namespace SharpChat { namespace SharpChat;
public interface C2SPacketHandler {
public interface C2SPacketHandler {
bool IsMatch(C2SPacketHandlerContext ctx); bool IsMatch(C2SPacketHandlerContext ctx);
Task Handle(C2SPacketHandlerContext ctx); Task Handle(C2SPacketHandlerContext ctx);
}
} }

View file

@ -1,9 +1,10 @@
namespace SharpChat { namespace SharpChat;
public class C2SPacketHandlerContext(
public class C2SPacketHandlerContext(
string text, string text,
Context chat, Context chat,
Connection connection Connection connection
) { ) {
public string Text { get; } = text ?? throw new ArgumentNullException(nameof(text)); public string Text { get; } = text ?? throw new ArgumentNullException(nameof(text));
public Context Chat { get; } = chat ?? throw new ArgumentNullException(nameof(chat)); public Context Chat { get; } = chat ?? throw new ArgumentNullException(nameof(chat));
public Connection Connection { get; } = connection ?? throw new ArgumentNullException(nameof(connection)); public Connection Connection { get; } = connection ?? throw new ArgumentNullException(nameof(connection));
@ -15,5 +16,4 @@
public string[] SplitText(int expect) { public string[] SplitText(int expect) {
return Text.Split('\t', expect + 1); return Text.Split('\t', expect + 1);
} }
}
} }

View file

@ -3,14 +3,15 @@ using SharpChat.Bans;
using SharpChat.Configuration; using SharpChat.Configuration;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.C2SPacketHandlers { namespace SharpChat.C2SPacketHandlers;
public class AuthC2SPacketHandler(
public class AuthC2SPacketHandler(
AuthClient authClient, AuthClient authClient,
BansClient bansClient, BansClient bansClient,
Channel defaultChannel, Channel defaultChannel,
CachedValue<int> maxMsgLength, CachedValue<int> maxMsgLength,
CachedValue<int> maxConns CachedValue<int> maxConns
) : C2SPacketHandler { ) : C2SPacketHandler {
private readonly Channel DefaultChannel = defaultChannel ?? throw new ArgumentNullException(nameof(defaultChannel)); private readonly Channel DefaultChannel = defaultChannel ?? throw new ArgumentNullException(nameof(defaultChannel));
private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength)); private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
private readonly CachedValue<int> MaxConnections = maxConns ?? throw new ArgumentNullException(nameof(maxConns)); private readonly CachedValue<int> MaxConnections = maxConns ?? throw new ArgumentNullException(nameof(maxConns));
@ -108,5 +109,4 @@ namespace SharpChat.C2SPacketHandlers {
throw; throw;
} }
} }
}
} }

View file

@ -2,8 +2,9 @@ using SharpChat.Auth;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Net; using System.Net;
namespace SharpChat.C2SPacketHandlers { namespace SharpChat.C2SPacketHandlers;
public class PingC2SPacketHandler(AuthClient authClient) : C2SPacketHandler {
public class PingC2SPacketHandler(AuthClient authClient) : C2SPacketHandler {
private readonly TimeSpan BumpInterval = TimeSpan.FromMinutes(1); private readonly TimeSpan BumpInterval = TimeSpan.FromMinutes(1);
private DateTimeOffset LastBump = DateTimeOffset.MinValue; private DateTimeOffset LastBump = DateTimeOffset.MinValue;
@ -36,5 +37,4 @@ namespace SharpChat.C2SPacketHandlers {
ctx.Chat.ContextAccess.Release(); ctx.Chat.ContextAccess.Release();
} }
} }
}
} }

View file

@ -4,11 +4,12 @@ using SharpChat.Snowflake;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
namespace SharpChat.C2SPacketHandlers { namespace SharpChat.C2SPacketHandlers;
public class SendMessageC2SPacketHandler(
public class SendMessageC2SPacketHandler(
RandomSnowflake randomSnowflake, RandomSnowflake randomSnowflake,
CachedValue<int> maxMsgLength CachedValue<int> maxMsgLength
) : C2SPacketHandler { ) : C2SPacketHandler {
private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength)); private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
private List<ClientCommand> Commands { get; } = []; private List<ClientCommand> Commands { get; } = [];
@ -85,5 +86,4 @@ namespace SharpChat.C2SPacketHandlers {
ctx.Chat.ContextAccess.Release(); ctx.Chat.ContextAccess.Release();
} }
} }
}
} }

View file

@ -1,11 +1,12 @@
namespace SharpChat { namespace SharpChat;
public class Channel(
public class Channel(
string name, string name,
string password = "", string password = "",
bool isTemporary = false, bool isTemporary = false,
int rank = 0, int rank = 0,
string ownerId = "" string ownerId = ""
) { ) {
public string Name { get; } = name ?? throw new ArgumentNullException(nameof(name)); public string Name { get; } = name ?? throw new ArgumentNullException(nameof(name));
public string Password { get; set; } = password ?? string.Empty; public string Password { get; set; } = password ?? string.Empty;
public bool IsTemporary { get; set; } = isTemporary; public bool IsTemporary { get; set; } = isTemporary;
@ -36,5 +37,4 @@ namespace SharpChat {
public static bool CheckNameChar(char c) { public static bool CheckNameChar(char c) {
return char.IsLetter(c) || char.IsNumber(c) || c == '-' || c == '_'; return char.IsLetter(c) || char.IsNumber(c) || c == '-' || c == '_';
} }
}
} }

View file

@ -1,6 +1,6 @@
namespace SharpChat { namespace SharpChat;
public interface ClientCommand {
public interface ClientCommand {
bool IsMatch(ClientCommandContext ctx); bool IsMatch(ClientCommandContext ctx);
Task Dispatch(ClientCommandContext ctx); Task Dispatch(ClientCommandContext ctx);
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat { namespace SharpChat;
public class ClientCommandContext {
public class ClientCommandContext {
public string Name { get; } public string Name { get; }
public string[] Args { get; } public string[] Args { get; }
public Context Chat { get; } public Context Chat { get; }
@ -45,5 +46,4 @@
public bool NameEquals(string name) { public bool NameEquals(string name) {
return Name.Equals(name, StringComparison.InvariantCultureIgnoreCase); return Name.Equals(name, StringComparison.InvariantCultureIgnoreCase);
} }
}
} }

View file

@ -1,8 +1,9 @@
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class AFKClientCommand : ClientCommand {
public class AFKClientCommand : ClientCommand {
private const string DEFAULT = "AFK"; private const string DEFAULT = "AFK";
public const int MAX_GRAPHEMES = 5; public const int MAX_GRAPHEMES = 5;
public const int MAX_BYTES = MAX_GRAPHEMES * 10; public const int MAX_BYTES = MAX_GRAPHEMES * 10;
@ -30,5 +31,4 @@ namespace SharpChat.ClientCommands {
statusText: statusText statusText: statusText
); );
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.Events; using SharpChat.Events;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class ActionClientCommand : ClientCommand {
public class ActionClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("action") return ctx.NameEquals("action")
|| ctx.NameEquals("me"); || ctx.NameEquals("me");
@ -29,5 +30,4 @@ namespace SharpChat.ClientCommands {
false, true, false false, true, false
)); ));
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.Bans; using SharpChat.Bans;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class BanListClientCommand(BansClient bansClient) : ClientCommand {
public class BanListClientCommand(BansClient bansClient) : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("bans") return ctx.NameEquals("bans")
|| ctx.NameEquals("banned"); || ctx.NameEquals("banned");
@ -26,5 +27,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.GENERIC_ERROR, true)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.GENERIC_ERROR, true));
} }
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.Events; using SharpChat.Events;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class BroadcastClientCommand : ClientCommand {
public class BroadcastClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("say") return ctx.NameEquals("say")
|| ctx.NameEquals("broadcast"); || ctx.NameEquals("broadcast");
@ -30,5 +31,4 @@ namespace SharpChat.ClientCommands {
false, false, true false, false, true
)); ));
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class CreateChannelClientCommand : ClientCommand {
public class CreateChannelClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("create"); return ctx.NameEquals("create");
} }
@ -58,5 +59,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password); await ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password);
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_CREATED, false, createChan.Name)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_CREATED, false, createChan.Name));
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class DeleteChannelClientCommand : ClientCommand {
public class DeleteChannelClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("delchan") || ( return ctx.NameEquals("delchan") || (
ctx.NameEquals("delete") ctx.NameEquals("delete")
@ -33,5 +34,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.RemoveChannel(delChan); await ctx.Chat.RemoveChannel(delChan);
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_DELETED, false, delChan.Name)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_DELETED, false, delChan.Name));
} }
}
} }

View file

@ -1,9 +1,9 @@
using SharpChat.EventStorage; using SharpChat.EventStorage;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands namespace SharpChat.ClientCommands;
{
public class DeleteMessageClientCommand : ClientCommand { public class DeleteMessageClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("delmsg") || ( return ctx.NameEquals("delmsg") || (
ctx.NameEquals("delete") ctx.NameEquals("delete")
@ -37,5 +37,4 @@ namespace SharpChat.ClientCommands
ctx.Chat.Events.RemoveEvent(delMsg); ctx.Chat.Events.RemoveEvent(delMsg);
await ctx.Chat.Send(new ChatMessageDeleteS2CPacket(delMsg.Id)); await ctx.Chat.Send(new ChatMessageDeleteS2CPacket(delMsg.Id));
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class JoinChannelClientCommand : ClientCommand {
public class JoinChannelClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("join"); return ctx.NameEquals("join");
} }
@ -19,5 +20,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.SwitchChannel(ctx.User, joinChan, string.Join(' ', ctx.Args.Skip(1))); await ctx.Chat.SwitchChannel(ctx.User, joinChan, string.Join(' ', ctx.Args.Skip(1)));
} }
}
} }

View file

@ -2,8 +2,9 @@ using SharpChat.Bans;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Net; using System.Net;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class KickBanClientCommand(BansClient bansClient) : ClientCommand {
public class KickBanClientCommand(BansClient bansClient) : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("kick") return ctx.NameEquals("kick")
|| ctx.NameEquals("ban"); || ctx.NameEquals("ban");
@ -69,5 +70,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.BanUser(banUser, duration); await ctx.Chat.BanUser(banUser, duration);
} }
}
} }

View file

@ -2,8 +2,9 @@ using SharpChat.SockChat.S2CPackets;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class NickClientCommand : ClientCommand {
public class NickClientCommand : ClientCommand {
private const int MAX_GRAPHEMES = 16; private const int MAX_GRAPHEMES = 16;
private const int MAX_BYTES = MAX_GRAPHEMES * 10; private const int MAX_BYTES = MAX_GRAPHEMES * 10;
@ -59,5 +60,4 @@ namespace SharpChat.ClientCommands {
string? previousName = targetUser.UserId == ctx.User.UserId ? (targetUser.NickName ?? targetUser.UserName) : null; string? previousName = targetUser.UserId == ctx.User.UserId ? (targetUser.NickName ?? targetUser.UserName) : null;
await ctx.Chat.UpdateUser(targetUser, nickName: nickStr, silent: previousName == null); await ctx.Chat.UpdateUser(targetUser, nickName: nickStr, silent: previousName == null);
} }
}
} }

View file

@ -2,8 +2,9 @@ using SharpChat.Bans;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Net; using System.Net;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class PardonAddressClientCommand(BansClient bansClient) : ClientCommand {
public class PardonAddressClientCommand(BansClient bansClient) : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("pardonip") return ctx.NameEquals("pardonip")
|| ctx.NameEquals("unbanip"); || ctx.NameEquals("unbanip");
@ -36,5 +37,4 @@ namespace SharpChat.ClientCommands {
else else
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USER_NOT_BANNED, true, unbanAddrTarget)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USER_NOT_BANNED, true, unbanAddrTarget));
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.Bans; using SharpChat.Bans;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class PardonUserClientCommand(BansClient bansClient) : ClientCommand {
public class PardonUserClientCommand(BansClient bansClient) : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("pardon") return ctx.NameEquals("pardon")
|| ctx.NameEquals("unban"); || ctx.NameEquals("unban");
@ -42,5 +43,4 @@ namespace SharpChat.ClientCommands {
else else
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USER_NOT_BANNED, true, unbanUserDisplay)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USER_NOT_BANNED, true, unbanUserDisplay));
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class PasswordChannelClientCommand : ClientCommand {
public class PasswordChannelClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("pwd") return ctx.NameEquals("pwd")
|| ctx.NameEquals("password"); || ctx.NameEquals("password");
@ -23,5 +24,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.UpdateChannel(ctx.Channel, password: chanPass); await ctx.Chat.UpdateChannel(ctx.Channel, password: chanPass);
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_PASSWORD_CHANGED, false)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_PASSWORD_CHANGED, false));
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class RankChannelClientCommand : ClientCommand {
public class RankChannelClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("rank") return ctx.NameEquals("rank")
|| ctx.NameEquals("privilege") || ctx.NameEquals("privilege")
@ -24,5 +25,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.UpdateChannel(ctx.Channel, hierarchy: chanHierarchy); await ctx.Chat.UpdateChannel(ctx.Channel, hierarchy: chanHierarchy);
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_HIERARCHY_CHANGED, false)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_HIERARCHY_CHANGED, false));
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Net; using System.Net;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class RemoteAddressClientCommand : ClientCommand {
public class RemoteAddressClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("ip") return ctx.NameEquals("ip")
|| ctx.NameEquals("whois"); || ctx.NameEquals("whois");
@ -27,5 +28,4 @@ namespace SharpChat.ClientCommands {
foreach(IPAddress ip in ctx.Chat.GetRemoteAddresses(ipUser)) foreach(IPAddress ip in ctx.Chat.GetRemoteAddresses(ipUser))
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.IP_ADDRESS, false, ipUser.UserName, ip)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.IP_ADDRESS, false, ipUser.UserName, ip));
} }
}
} }

View file

@ -1,7 +1,8 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class ShutdownRestartClientCommand(ManualResetEvent waitHandle, Func<bool> shutdownCheck) : ClientCommand {
public class ShutdownRestartClientCommand(ManualResetEvent waitHandle, Func<bool> shutdownCheck) : ClientCommand {
private readonly ManualResetEvent WaitHandle = waitHandle ?? throw new ArgumentNullException(nameof(waitHandle)); private readonly ManualResetEvent WaitHandle = waitHandle ?? throw new ArgumentNullException(nameof(waitHandle));
private readonly Func<bool> ShutdownCheck = shutdownCheck ?? throw new ArgumentNullException(nameof(shutdownCheck)); private readonly Func<bool> ShutdownCheck = shutdownCheck ?? throw new ArgumentNullException(nameof(shutdownCheck));
@ -27,5 +28,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.Update(); await ctx.Chat.Update();
WaitHandle?.Set(); WaitHandle?.Set();
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.Events; using SharpChat.Events;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class WhisperClientCommand : ClientCommand {
public class WhisperClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("whisper") return ctx.NameEquals("whisper")
|| ctx.NameEquals("msg"); || ctx.NameEquals("msg");
@ -41,5 +42,4 @@ namespace SharpChat.ClientCommands {
true, false, false true, false, false
)); ));
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Text; using System.Text;
namespace SharpChat.ClientCommands { namespace SharpChat.ClientCommands;
public class WhoClientCommand : ClientCommand {
public class WhoClientCommand : ClientCommand {
public bool IsMatch(ClientCommandContext ctx) { public bool IsMatch(ClientCommandContext ctx) {
return ctx.NameEquals("who"); return ctx.NameEquals("who");
} }
@ -58,5 +59,4 @@ namespace SharpChat.ClientCommands {
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USERS_LISTING_CHANNEL, false, whoChan.Name, whoChanSB)); await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.USERS_LISTING_CHANNEL, false, whoChan.Name, whoChanSB));
} }
} }
}
} }

View file

@ -2,8 +2,9 @@ using Fleck;
using SharpChat.SockChat; using SharpChat.SockChat;
using System.Net; using System.Net;
namespace SharpChat { namespace SharpChat;
public class Connection : IDisposable {
public class Connection : IDisposable {
public const int ID_LENGTH = 20; public const int ID_LENGTH = 20;
#if DEBUG #if DEBUG
@ -86,5 +87,4 @@ namespace SharpChat {
public override int GetHashCode() { public override int GetHashCode() {
return Id.GetHashCode(); return Id.GetHashCode();
} }
}
} }

View file

@ -5,8 +5,9 @@ using SharpChat.SockChat;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Net; using System.Net;
namespace SharpChat { namespace SharpChat;
public class Context {
public class Context {
public record ChannelUserAssoc(string UserId, string ChannelName); public record ChannelUserAssoc(string UserId, string ChannelName);
public readonly SemaphoreSlim ContextAccess = new(1, 1); public readonly SemaphoreSlim ContextAccess = new(1, 1);
@ -409,5 +410,4 @@ namespace SharpChat {
foreach(User user in Users.Where(u => u.Rank >= channel.Rank)) foreach(User user in Users.Where(u => u.Rank >= channel.Rank))
await SendTo(user, new ChannelDeleteS2CPacket(channel.Name)); await SendTo(user, new ChannelDeleteS2CPacket(channel.Name));
} }
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
public interface EventStorage {
public interface EventStorage {
void AddEvent( void AddEvent(
long id, long id,
string type, string type,
@ -16,5 +17,4 @@ namespace SharpChat.EventStorage {
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);
}
} }

View file

@ -2,8 +2,9 @@ using MySqlConnector;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
public partial class MariaDBEventStorage(string connString) : EventStorage {
public partial class MariaDBEventStorage(string connString) : EventStorage {
private string ConnectionString { get; } = connString ?? throw new ArgumentNullException(nameof(connString)); private string ConnectionString { get; } = connString ?? throw new ArgumentNullException(nameof(connString));
public void AddEvent( public void AddEvent(
@ -127,5 +128,4 @@ namespace SharpChat.EventStorage {
new MySqlParameter("id", evt.Id) new MySqlParameter("id", evt.Id)
); );
} }
}
} }

View file

@ -1,8 +1,9 @@
using MySqlConnector; using MySqlConnector;
using SharpChat.Configuration; using SharpChat.Configuration;
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
public partial class MariaDBEventStorage {
public partial class MariaDBEventStorage {
public static string BuildConnString(Configuration.Config config) { public static string BuildConnString(Configuration.Config config) {
return BuildConnString( return BuildConnString(
config.ReadValue("host", "localhost"), config.ReadValue("host", "localhost"),
@ -83,5 +84,4 @@ namespace SharpChat.EventStorage {
return default; return default;
} }
}
} }

View file

@ -1,7 +1,8 @@
using MySqlConnector; using MySqlConnector;
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
public partial class MariaDBEventStorage {
public partial class MariaDBEventStorage {
private void DoMigration(string name, Action action) { private void DoMigration(string name, Action action) {
bool done = RunQueryValue<long>( bool done = RunQueryValue<long>(
"SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name", "SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name",
@ -80,5 +81,4 @@ namespace SharpChat.EventStorage {
+ ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;" + ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;"
); );
} }
}
} }

View file

@ -1,10 +1,10 @@
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
[Flags]
public enum StoredEventFlags { [Flags]
public enum StoredEventFlags {
None = 0, None = 0,
Action = 1, Action = 1,
Broadcast = 1 << 1, Broadcast = 1 << 1,
Log = 1 << 2, Log = 1 << 2,
Private = 1 << 3, Private = 1 << 3,
}
} }

View file

@ -1,7 +1,8 @@
using System.Text.Json; using System.Text.Json;
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
public class StoredEventInfo(
public class StoredEventInfo(
long id, long id,
string type, string type,
User? sender, User? sender,
@ -10,7 +11,7 @@ namespace SharpChat.EventStorage {
string? channelName, string? channelName,
JsonDocument data, JsonDocument data,
StoredEventFlags flags StoredEventFlags flags
) { ) {
public long Id { get; set; } = id; public long Id { get; set; } = id;
public string Type { get; set; } = type; public string Type { get; set; } = type;
public User? Sender { get; set; } = sender; public User? Sender { get; set; } = sender;
@ -19,5 +20,4 @@ namespace SharpChat.EventStorage {
public string? ChannelName { get; set; } = channelName; public string? ChannelName { get; set; } = channelName;
public StoredEventFlags Flags { get; set; } = flags; public StoredEventFlags Flags { get; set; } = flags;
public JsonDocument Data { get; set; } = data; public JsonDocument Data { get; set; } = data;
}
} }

View file

@ -1,7 +1,8 @@
using System.Text.Json; using System.Text.Json;
namespace SharpChat.EventStorage { namespace SharpChat.EventStorage;
public class VirtualEventStorage : EventStorage {
public class VirtualEventStorage : EventStorage {
private readonly Dictionary<long, StoredEventInfo> Events = []; private readonly Dictionary<long, StoredEventInfo> Events = [];
public void AddEvent( public void AddEvent(
@ -61,5 +62,4 @@ namespace SharpChat.EventStorage {
return [.. subset.Skip(start).Take(amount)]; return [.. subset.Skip(start).Take(amount)];
} }
}
} }

View file

@ -1,3 +1,3 @@
namespace SharpChat.Events { namespace SharpChat.Events;
public interface ChatEvent {}
} public interface ChatEvent {}

View file

@ -1,5 +1,6 @@
namespace SharpChat.Events { namespace SharpChat.Events;
public class MessageCreateEvent(
public class MessageCreateEvent(
long msgId, long msgId,
string channelName, string channelName,
string senderId, string senderId,
@ -13,7 +14,7 @@ namespace SharpChat.Events {
bool isPrivate, bool isPrivate,
bool isAction, bool isAction,
bool isBroadcast bool isBroadcast
) : ChatEvent { ) : ChatEvent {
public long MessageId { get; } = msgId; public long MessageId { get; } = msgId;
public string ChannelName { get; } = channelName; public string ChannelName { get; } = channelName;
public string SenderId { get; } = senderId; public string SenderId { get; } = senderId;
@ -27,5 +28,4 @@ namespace SharpChat.Events {
public bool IsPrivate { get; } = isPrivate; public bool IsPrivate { get; } = isPrivate;
public bool IsAction { get; } = isAction; public bool IsAction { get; } = isAction;
public bool IsBroadcast { get; } = isBroadcast; public bool IsBroadcast { get; } = isBroadcast;
}
} }

View file

@ -3,8 +3,9 @@ using SharpChat.EventStorage;
using SharpChat.Flashii; using SharpChat.Flashii;
using System.Text; using System.Text;
namespace SharpChat { namespace SharpChat;
public class Program {
public class Program {
public const string CONFIG = "sharpchat.cfg"; public const string CONFIG = "sharpchat.cfg";
public static void Main() { public static void Main() {
@ -143,5 +144,4 @@ namespace SharpChat {
sw.Flush(); sw.Flush();
} }
}
} }

View file

@ -12,8 +12,9 @@ using System.Text;
// Fleck's Socket wrapper doesn't provide any way to do this with the normally provided APIs // Fleck's Socket wrapper doesn't provide any way to do this with the normally provided APIs
// https://github.com/statianzo/Fleck/blob/1.1.0/src/Fleck/WebSocketServer.cs // https://github.com/statianzo/Fleck/blob/1.1.0/src/Fleck/WebSocketServer.cs
namespace SharpChat { namespace SharpChat;
public class SharpChatWebSocketServer : IWebSocketServer {
public class SharpChatWebSocketServer : IWebSocketServer {
private readonly string _scheme; private readonly string _scheme;
private readonly IPAddress _locationIP; private readonly IPAddress _locationIP;
@ -163,5 +164,4 @@ namespace SharpChat {
connection.StartReceiving(); connection.StartReceiving();
} }
} }
}
} }

View file

@ -1,8 +1,9 @@
using SharpChat.EventStorage; using SharpChat.EventStorage;
using System.Text; using System.Text;
namespace SharpChat.SockChat.S2CPackets { namespace SharpChat.SockChat.S2CPackets;
public class ContextMessageS2CPacket(StoredEventInfo evt, bool notify = false) : S2CPacket {
public class ContextMessageS2CPacket(StoredEventInfo evt, bool notify = false) : S2CPacket {
public StoredEventInfo Event { get; private set; } = evt ?? throw new ArgumentNullException(nameof(evt)); public StoredEventInfo Event { get; private set; } = evt ?? throw new ArgumentNullException(nameof(evt));
public string Pack() { public string Pack() {
@ -111,5 +112,4 @@ namespace SharpChat.SockChat.S2CPackets {
return sb.ToString(); return sb.ToString();
} }
}
} }

View file

@ -7,8 +7,9 @@ using SharpChat.Configuration;
using SharpChat.SockChat.S2CPackets; using SharpChat.SockChat.S2CPackets;
using System.Net; using System.Net;
namespace SharpChat { namespace SharpChat;
public class SockChatServer : IDisposable {
public class SockChatServer : IDisposable {
public const ushort DEFAULT_PORT = 6770; public const ushort DEFAULT_PORT = 6770;
public const int DEFAULT_MSG_LENGTH_MAX = 5000; public const int DEFAULT_MSG_LENGTH_MAX = 5000;
public const int DEFAULT_MAX_CONNECTIONS = 5; public const int DEFAULT_MAX_CONNECTIONS = 5;
@ -236,5 +237,4 @@ namespace SharpChat {
Server?.Dispose(); Server?.Dispose();
} }
}
} }

View file

@ -2,8 +2,9 @@ using SharpChat.ClientCommands;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
namespace SharpChat { namespace SharpChat;
public class User(
public class User(
string userId, string userId,
string userName, string userName,
ColourInheritable colour, ColourInheritable colour,
@ -12,7 +13,7 @@ namespace SharpChat {
string nickName = "", string nickName = "",
UserStatus status = UserStatus.Online, UserStatus status = UserStatus.Online,
string statusText = "" 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;
@ -69,5 +70,4 @@ namespace SharpChat {
? $"@{user2.UserId}-{user1.UserId}" ? $"@{user2.UserId}-{user1.UserId}"
: $"@{user1.UserId}-{user2.UserId}"; : $"@{user1.UserId}-{user2.UserId}";
} }
}
} }

View file

@ -1,7 +1,7 @@
namespace SharpChat { namespace SharpChat;
public enum UserStatus {
public enum UserStatus {
Online, Online,
Away, Away,
Offline, Offline,
}
} }

View file

@ -1,8 +1,8 @@
using System.Net; using System.Net;
namespace SharpChat.Auth { namespace SharpChat.Auth;
public interface AuthClient {
public interface AuthClient {
Task<AuthResult> AuthVerifyAsync(IPAddress remoteAddr, string scheme, string token); Task<AuthResult> AuthVerifyAsync(IPAddress remoteAddr, string scheme, string token);
Task AuthBumpUsersOnlineAsync(IEnumerable<(IPAddress remoteAddr, string userId)> entries); Task AuthBumpUsersOnlineAsync(IEnumerable<(IPAddress remoteAddr, string userId)> entries);
}
} }

View file

@ -1,3 +1,3 @@
namespace SharpChat.Auth { namespace SharpChat.Auth;
public class AuthFailedException(string message) : Exception(message) {}
} public class AuthFailedException(string message) : Exception(message) {}

View file

@ -1,9 +1,9 @@
namespace SharpChat.Auth { namespace SharpChat.Auth;
public interface AuthResult {
public interface AuthResult {
string UserId { get; } string UserId { get; }
string UserName { get; } string UserName { get; }
ColourInheritable UserColour { get; } ColourInheritable UserColour { get; }
int UserRank { get; } int UserRank { get; }
UserPermissions UserPermissions { get; } UserPermissions UserPermissions { get; }
}
} }

View file

@ -1,9 +1,9 @@
namespace SharpChat.Bans { namespace SharpChat.Bans;
public interface BanInfo {
public interface BanInfo {
BanKind Kind { get; } BanKind Kind { get; }
bool IsPermanent { get; } bool IsPermanent { get; }
DateTimeOffset ExpiresAt { get; } DateTimeOffset ExpiresAt { get; }
public bool HasExpired => !IsPermanent && DateTimeOffset.UtcNow >= ExpiresAt; public bool HasExpired => !IsPermanent && DateTimeOffset.UtcNow >= ExpiresAt;
string ToString(); string ToString();
}
} }

View file

@ -1,6 +1,6 @@
namespace SharpChat.Bans { namespace SharpChat.Bans;
public enum BanKind {
public enum BanKind {
User, User,
IPAddress, IPAddress,
}
} }

View file

@ -1,7 +1,8 @@
using System.Net; using System.Net;
namespace SharpChat.Bans { namespace SharpChat.Bans;
public interface BansClient {
public interface BansClient {
Task BanCreateAsync( Task BanCreateAsync(
BanKind kind, BanKind kind,
TimeSpan duration, TimeSpan duration,
@ -14,5 +15,4 @@ namespace SharpChat.Bans {
Task<bool> BanRevokeAsync(BanInfo info); Task<bool> BanRevokeAsync(BanInfo info);
Task<BanInfo?> BanGetAsync(string? userIdOrName = null, IPAddress? remoteAddr = null); Task<BanInfo?> BanGetAsync(string? userIdOrName = null, IPAddress? remoteAddr = null);
Task<BanInfo[]> BanGetListAsync(); Task<BanInfo[]> BanGetListAsync();
}
} }

View file

@ -1,7 +1,7 @@
using System.Net; using System.Net;
namespace SharpChat.Bans { namespace SharpChat.Bans;
public interface IPAddressBanInfo : BanInfo {
public interface IPAddressBanInfo : BanInfo {
IPAddress Address { get; } IPAddress Address { get; }
}
} }

View file

@ -1,7 +1,7 @@
namespace SharpChat.Bans { namespace SharpChat.Bans;
public interface UserBanInfo : BanInfo {
public interface UserBanInfo : BanInfo {
string UserId { get; } string UserId { get; }
string UserName { get; } string UserName { get; }
ColourInheritable UserColour { get; } ColourInheritable UserColour { get; }
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat { namespace SharpChat;
public readonly record struct ColourInheritable(ColourRgb? rgb) {
public readonly record struct ColourInheritable(ColourRgb? rgb) {
public static readonly ColourInheritable None = new(null); public static readonly ColourInheritable None = new(null);
public override string ToString() => rgb.HasValue ? rgb.Value.ToString() : "inherit"; public override string ToString() => rgb.HasValue ? rgb.Value.ToString() : "inherit";
@ -10,5 +11,4 @@ namespace SharpChat {
private const int MSZ_INHERIT = 0x40000000; private const int MSZ_INHERIT = 0x40000000;
public int ToMisuzu() => rgb.HasValue ? rgb.Value.Raw : MSZ_INHERIT; public int ToMisuzu() => rgb.HasValue ? rgb.Value.Raw : MSZ_INHERIT;
public static ColourInheritable FromMisuzu(int msz) => (msz & MSZ_INHERIT) > 0 ? None : new(new ColourRgb(msz & 0xFFFFFF)); public static ColourInheritable FromMisuzu(int msz) => (msz & MSZ_INHERIT) > 0 ? None : new(new ColourRgb(msz & 0xFFFFFF));
}
} }

View file

@ -1,9 +1,9 @@
namespace SharpChat { namespace SharpChat;
public readonly record struct ColourRgb(int Raw) {
public readonly record struct ColourRgb(int Raw) {
public byte Red => (byte)((Raw >> 16) & 0xFF); public byte Red => (byte)((Raw >> 16) & 0xFF);
public byte Green => (byte)((Raw >> 8) & 0xFF); public byte Green => (byte)((Raw >> 8) & 0xFF);
public byte Blue => (byte)(Raw & 0xFF); public byte Blue => (byte)(Raw & 0xFF);
public override string ToString() => string.Format("#{0:x2}{1:x2}{2:x2}", Red, Green, Blue); public override string ToString() => string.Format("#{0:x2}{1:x2}{2:x2}", Red, Green, Blue);
public static ColourRgb FromRgb(byte red, byte green, byte blue) => new(red << 16 | green << 8 | blue); public static ColourRgb FromRgb(byte red, byte green, byte blue) => new(red << 16 | green << 8 | blue);
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat.Configuration { namespace SharpChat.Configuration;
public class CachedValue<T>(Config config, string name, TimeSpan lifetime, T? fallback) {
public class CachedValue<T>(Config config, string name, TimeSpan lifetime, T? fallback) {
private Config Config { get; } = config ?? throw new ArgumentNullException(nameof(config)); private Config Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
private string Name { get; } = name ?? throw new ArgumentNullException(nameof(name)); private string Name { get; } = name ?? throw new ArgumentNullException(nameof(name));
private object ConfigAccess { get; } = new(); private object ConfigAccess { get; } = new();
@ -30,5 +31,4 @@ namespace SharpChat.Configuration {
public override string ToString() { public override string ToString() {
return Value?.ToString() ?? string.Empty; return Value?.ToString() ?? string.Empty;
} }
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat.Configuration { namespace SharpChat.Configuration;
public interface Config : IDisposable {
public interface Config : IDisposable {
/// <summary> /// <summary>
/// Creates a proxy object that forces all names to start with the given prefix. /// Creates a proxy object that forces all names to start with the given prefix.
/// </summary> /// </summary>
@ -25,5 +26,4 @@ namespace SharpChat.Configuration {
/// Creates an object that caches the read value for a certain amount of time, avoiding disk reads for frequently used non-static values. /// Creates an object that caches the read value for a certain amount of time, avoiding disk reads for frequently used non-static values.
/// </summary> /// </summary>
CachedValue<T> ReadCached<T>(string name, T? fallback = default, TimeSpan? lifetime = null); CachedValue<T> ReadCached<T>(string name, T? fallback = default, TimeSpan? lifetime = null);
}
} }

View file

@ -1,9 +1,9 @@
namespace SharpChat.Configuration { namespace SharpChat.Configuration;
public abstract class ConfigException : Exception {
public abstract class ConfigException : Exception {
public ConfigException(string message) : base(message) { } public ConfigException(string message) : base(message) { }
public ConfigException(string message, Exception ex) : base(message, ex) { } public ConfigException(string message, Exception ex) : base(message, ex) { }
}
public class ConfigLockException() : ConfigException("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 ConfigLockException() : ConfigException("Unable to acquire lock for reading configuration.") {}
public class ConfigTypeException(Exception ex) : ConfigException("Given type does not match the value in the configuration.", ex) {}

View file

@ -1,5 +1,6 @@
namespace SharpChat.Configuration { namespace SharpChat.Configuration;
public class ScopedConfig(Config config, string prefix) : Config {
public class ScopedConfig(Config config, string prefix) : Config {
private Config Config { get; } = config ?? throw new ArgumentNullException(nameof(config)); private Config Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
private string Prefix { get; } = prefix ?? throw new ArgumentNullException(nameof(prefix)); private string Prefix { get; } = prefix ?? throw new ArgumentNullException(nameof(prefix));
@ -30,5 +31,4 @@ namespace SharpChat.Configuration {
public void Dispose() { public void Dispose() {
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
}
} }

View file

@ -1,7 +1,8 @@
using System.Text; using System.Text;
namespace SharpChat.Configuration { namespace SharpChat.Configuration;
public class StreamConfig : Config {
public class StreamConfig : Config {
private Stream Stream { get; } private Stream Stream { get; }
private StreamReader StreamReader { get; } private StreamReader StreamReader { get; }
private Mutex Lock { get; } private Mutex Lock { get; }
@ -111,5 +112,4 @@ namespace SharpChat.Configuration {
Stream.Dispose(); Stream.Dispose();
Lock.Dispose(); Lock.Dispose();
} }
}
} }

View file

@ -1,8 +1,9 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
namespace SharpChat { namespace SharpChat;
public static class Logger {
public static class Logger {
public static void Write(string str) { public static void Write(string str) {
Console.WriteLine(string.Format("[{1}] {0}", str, DateTime.Now)); Console.WriteLine(string.Format("[{1}] {0}", str, DateTime.Now));
} }
@ -29,5 +30,4 @@ namespace SharpChat {
public static void Debug(object obj) { public static void Debug(object obj) {
Write(obj); Write(obj);
} }
}
} }

View file

@ -1,8 +1,9 @@
using System.Buffers; using System.Buffers;
using System.Security.Cryptography; using System.Security.Cryptography;
namespace SharpChat { namespace SharpChat;
public static class RNG {
public static class RNG {
public const string CHARS = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"; public const string CHARS = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789";
private static Random NormalRandom { get; } = new(); private static Random NormalRandom { get; } = new();
@ -78,5 +79,4 @@ namespace SharpChat {
public static string SecureRandomString(int length) { public static string SecureRandomString(int length) {
return RandomStringInternal(SecureNext, length); return RandomStringInternal(SecureNext, length);
} }
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat { namespace SharpChat;
public class RateLimiter {
public class RateLimiter {
private readonly int Size; private readonly int Size;
private readonly int MinimumDelay; private readonly int MinimumDelay;
private readonly int RiskyOffset; private readonly int RiskyOffset;
@ -31,5 +32,4 @@
TimePoints[i - 1] = TimePoints[i]; TimePoints[i - 1] = TimePoints[i];
TimePoints[Size - 1] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); TimePoints[Size - 1] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
} }
}
} }

View file

@ -1,8 +1,9 @@
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
namespace SharpChat { namespace SharpChat;
public static class SharpInfo {
public static class SharpInfo {
private const string NAME = @"SharpChat"; private const string NAME = @"SharpChat";
private const string UNKNOWN = @"XXXXXXXXXX"; private const string UNKNOWN = @"XXXXXXXXXX";
@ -32,5 +33,4 @@ namespace SharpChat {
sb.Append(VersionStringShort); sb.Append(VersionStringShort);
ProgramName = sb.ToString(); ProgramName = sb.ToString();
} }
}
} }

View file

@ -1,13 +1,13 @@
using System.Security.Cryptography; using System.Security.Cryptography;
namespace SharpChat.Snowflake { namespace SharpChat.Snowflake;
public class RandomSnowflake(
public class RandomSnowflake(
SnowflakeGenerator? generator = null SnowflakeGenerator? generator = null
) { ) {
public readonly SnowflakeGenerator Generator = generator ?? new SnowflakeGenerator(); public readonly SnowflakeGenerator Generator = generator ?? new SnowflakeGenerator();
public long Next(DateTimeOffset? at = null) { public long Next(DateTimeOffset? at = null) {
return Generator.Next(Math.Abs(BitConverter.ToInt64(RandomNumberGenerator.GetBytes(8))), at); return Generator.Next(Math.Abs(BitConverter.ToInt64(RandomNumberGenerator.GetBytes(8))), at);
} }
}
} }

View file

@ -1,5 +1,6 @@
namespace SharpChat.Snowflake { namespace SharpChat.Snowflake;
public class SnowflakeGenerator {
public class SnowflakeGenerator {
public const long MASK = 0x7FFFFFFFFFFFFFFF; public const long MASK = 0x7FFFFFFFFFFFFFFF;
// previous default epoch was 1588377600000, but snowflakes are much larger than SharpIds // previous default epoch was 1588377600000, but snowflakes are much larger than SharpIds
public const long EPOCH = 1356998400000; public const long EPOCH = 1356998400000;
@ -31,5 +32,4 @@
public long Next(long sequence, DateTimeOffset? at = null) { public long Next(long sequence, DateTimeOffset? at = null) {
return ((Now(at) & TimestampMask) << Shift) | (sequence & SequenceMask); return ((Now(at) & TimestampMask) << Shift) | (sequence & SequenceMask);
} }
}
} }

View file

@ -1,6 +1,7 @@
namespace SharpChat { namespace SharpChat;
[Flags]
public enum UserPermissions : int { [Flags]
public enum UserPermissions : int {
KickUser = 0x00000001, KickUser = 0x00000001,
BanUser = 0x00000002, BanUser = 0x00000002,
//SilenceUser = 0x00000004, //SilenceUser = 0x00000004,
@ -20,5 +21,4 @@
EditAnyMessage = 0x00004000, EditAnyMessage = 0x00004000,
SeeIPAddress = 0x00008000, SeeIPAddress = 0x00008000,
ViewLogs = 0x00040000, ViewLogs = 0x00040000,
}
} }