Disable global nullable.
This commit is contained in:
parent
40f8fc2e86
commit
f5c8f2ae1d
40 changed files with 209 additions and 200 deletions
SharpChat
ChatColour.csChatConnection.csChatContext.csChatUser.cs
Commands
AFKCommand.csBanListCommand.csDeleteChannelCommand.csDeleteMessageCommand.csJoinChannelCommand.csKickBanCommand.csNickCommand.csPardonAddressCommand.csPardonUserCommand.csRemoteAddressCommand.csWhisperCommand.csWhoCommand.cs
Config
EventStorage
IEventStorage.csMariaDBEventStorage.csMariaDBEventStorage_Database.csMariaDBEventStorage_Migrations.csStoredEventInfo.csVirtualEventStorage.cs
Events
Misuzu
Packet
PacketHandlers
Program.csSharpChat.csprojSharpChatWebSocketServer.csSharpInfo.csSockChatServer.cs
|
@ -23,7 +23,7 @@ namespace SharpChat {
|
|||
Inherits = false;
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object obj) {
|
||||
public override bool Equals([NotNullWhen(true)] object? obj) {
|
||||
return obj is ChatColour colour && Equals(colour);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace SharpChat {
|
|||
public string Id { get; }
|
||||
public bool IsDisposed { get; private set; }
|
||||
public DateTimeOffset LastPing { get; set; } = DateTimeOffset.Now;
|
||||
public ChatUser User { get; set; }
|
||||
public ChatUser? User { get; set; }
|
||||
|
||||
private int CloseCode { get; set; } = 1000;
|
||||
|
||||
|
@ -27,18 +27,16 @@ namespace SharpChat {
|
|||
|
||||
public bool IsAlive => !IsDisposed && !HasTimedOut;
|
||||
|
||||
public bool IsAuthed => IsAlive && User is not null;
|
||||
|
||||
public ChatConnection(IWebSocketConnection sock) {
|
||||
Socket = sock;
|
||||
Id = RNG.SecureRandomString(ID_LENGTH);
|
||||
|
||||
if(!IPAddress.TryParse(sock.ConnectionInfo.ClientIpAddress, out IPAddress addr))
|
||||
if(!IPAddress.TryParse(sock.ConnectionInfo.ClientIpAddress, out IPAddress? addr))
|
||||
throw new Exception("Unable to parse remote address?????");
|
||||
|
||||
if(IPAddress.IsLoopback(addr)
|
||||
&& sock.ConnectionInfo.Headers.TryGetValue("X-Real-IP", out string addrStr)
|
||||
&& IPAddress.TryParse(addrStr, out IPAddress realAddr))
|
||||
&& sock.ConnectionInfo.Headers.TryGetValue("X-Real-IP", out string? addrStr)
|
||||
&& IPAddress.TryParse(addrStr, out IPAddress? realAddr))
|
||||
addr = realAddr;
|
||||
|
||||
RemoteAddress = addr;
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace SharpChat {
|
|||
return;
|
||||
|
||||
IEnumerable<ChatUser> users = Users.Where(u => uids.Any(uid => uid == u.UserId));
|
||||
ChatUser target = users.FirstOrDefault(u => u.UserId != mce.SenderId);
|
||||
ChatUser? target = users.FirstOrDefault(u => u.UserId != mce.SenderId);
|
||||
if(target == null)
|
||||
return;
|
||||
|
||||
|
@ -52,15 +52,16 @@ namespace SharpChat {
|
|||
true
|
||||
));
|
||||
} else {
|
||||
ChatChannel channel = Channels.FirstOrDefault(c => c.NameEquals(mce.ChannelName));
|
||||
SendTo(channel, new ChatMessageAddPacket(
|
||||
mce.MessageId,
|
||||
DateTimeOffset.Now,
|
||||
mce.SenderId,
|
||||
mce.MessageText,
|
||||
mce.IsAction,
|
||||
false
|
||||
));
|
||||
ChatChannel? channel = Channels.FirstOrDefault(c => c.NameEquals(mce.ChannelName));
|
||||
if(channel is not null)
|
||||
SendTo(channel, new ChatMessageAddPacket(
|
||||
mce.MessageId,
|
||||
DateTimeOffset.Now,
|
||||
mce.SenderId,
|
||||
mce.MessageText,
|
||||
mce.IsAction,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
Events.AddEvent(
|
||||
|
@ -125,11 +126,11 @@ namespace SharpChat {
|
|||
|
||||
public void UpdateUser(
|
||||
ChatUser user,
|
||||
string userName = null,
|
||||
string nickName = null,
|
||||
string? userName = null,
|
||||
string? nickName = null,
|
||||
ChatColour? colour = null,
|
||||
ChatUserStatus? status = null,
|
||||
string statusText = null,
|
||||
string? statusText = null,
|
||||
int? rank = null,
|
||||
ChatUserPermissions? perms = null,
|
||||
bool? isSuper = null,
|
||||
|
@ -241,7 +242,7 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public void SwitchChannel(ChatUser user, ChatChannel chan, string password) {
|
||||
if(UserLastChannel.TryGetValue(user.UserId, out ChatChannel ulc) && chan == ulc) {
|
||||
if(UserLastChannel.TryGetValue(user.UserId, out ChatChannel? ulc) && chan == ulc) {
|
||||
ForceChannel(user);
|
||||
return;
|
||||
}
|
||||
|
@ -294,7 +295,7 @@ namespace SharpChat {
|
|||
ArgumentNullException.ThrowIfNull(packet);
|
||||
|
||||
foreach(ChatConnection conn in Connections)
|
||||
if(conn.IsAuthed)
|
||||
if(conn.IsAlive && conn.User is not null)
|
||||
conn.Send(packet);
|
||||
}
|
||||
|
||||
|
@ -312,7 +313,7 @@ namespace SharpChat {
|
|||
ArgumentNullException.ThrowIfNull(packet);
|
||||
|
||||
// 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.IsAlive && c.User is not null && IsInChannel(c.User, channel));
|
||||
foreach(ChatConnection conn in conns)
|
||||
conn.Send(packet);
|
||||
}
|
||||
|
@ -322,7 +323,7 @@ namespace SharpChat {
|
|||
ArgumentNullException.ThrowIfNull(packet);
|
||||
|
||||
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.IsAlive && conn.User is not null && ChannelUsers.Any(cu => cu.UserId == conn.User.UserId && chans.Any(chan => chan.NameEquals(cu.ChannelName))));
|
||||
foreach(ChatConnection conn in conns)
|
||||
conn.Send(packet);
|
||||
}
|
||||
|
@ -331,7 +332,7 @@ namespace SharpChat {
|
|||
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) {
|
||||
ArgumentNullException.ThrowIfNull(user);
|
||||
|
||||
if(chan == null && !UserLastChannel.TryGetValue(user.UserId, out chan))
|
||||
|
@ -340,7 +341,7 @@ namespace SharpChat {
|
|||
SendTo(user, new UserChannelForceJoinPacket(chan));
|
||||
}
|
||||
|
||||
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) {
|
||||
ArgumentNullException.ThrowIfNull(channel);
|
||||
if(!Channels.Contains(channel))
|
||||
throw new ArgumentException("Provided channel is not registered with this manager.", nameof(channel));
|
||||
|
@ -364,8 +365,8 @@ namespace SharpChat {
|
|||
if(channel == null || Channels.Count < 1)
|
||||
return;
|
||||
|
||||
ChatChannel defaultChannel = Channels.FirstOrDefault();
|
||||
if(defaultChannel == null)
|
||||
ChatChannel? defaultChannel = Channels.FirstOrDefault();
|
||||
if(defaultChannel is null)
|
||||
return;
|
||||
|
||||
// Remove channel from the listing
|
||||
|
|
|
@ -24,9 +24,9 @@ namespace SharpChat {
|
|||
public int Rank { get; set; } = rank;
|
||||
public ChatUserPermissions Permissions { get; set; } = perms;
|
||||
public bool IsSuper { get; set; }
|
||||
public string NickName { get; set; } = nickName ?? string.Empty;
|
||||
public string NickName { get; set; } = nickName;
|
||||
public ChatUserStatus Status { get; set; } = status;
|
||||
public string StatusText { get; set; } = statusText ?? string.Empty;
|
||||
public string StatusText { get; set; } = statusText;
|
||||
|
||||
public string LegacyName => string.IsNullOrWhiteSpace(NickName) ? UserName : $"~{NickName}";
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
string statusText = ctx.Args.FirstOrDefault();
|
||||
string? statusText = ctx.Args.FirstOrDefault();
|
||||
if(string.IsNullOrWhiteSpace(statusText))
|
||||
statusText = DEFAULT;
|
||||
else {
|
||||
|
|
|
@ -19,9 +19,12 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
Task.Run(async () => {
|
||||
ctx.Chat.SendTo(ctx.User, new BanListPacket(
|
||||
await Misuzu.GetBanListAsync()
|
||||
));
|
||||
MisuzuBanInfo[]? mbi = await Misuzu.GetBanListAsync();
|
||||
|
||||
if(mbi is null)
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
else
|
||||
ctx.Chat.SendTo(ctx.User, new BanListPacket(mbi));
|
||||
}).Wait();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
string delChanName = string.Join('_', ctx.Args);
|
||||
ChatChannel delChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(delChanName));
|
||||
ChatChannel? delChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(delChanName));
|
||||
|
||||
if(delChan == null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, delChanName));
|
||||
|
|
|
@ -20,16 +20,16 @@ namespace SharpChat.Commands
|
|||
return;
|
||||
}
|
||||
|
||||
string firstArg = ctx.Args.FirstOrDefault();
|
||||
string? firstArg = ctx.Args.FirstOrDefault();
|
||||
|
||||
if(string.IsNullOrWhiteSpace(firstArg) || !firstArg.All(char.IsDigit) || !long.TryParse(firstArg, out long delSeqId)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
StoredEventInfo delMsg = ctx.Chat.Events.GetEvent(delSeqId);
|
||||
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
|
||||
|
||||
if(delMsg == null || delMsg.Sender.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender.UserId != ctx.User.UserId)) {
|
||||
if(delMsg?.Sender is null || delMsg.Sender.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender.UserId != ctx.User.UserId)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.MESSAGE_DELETE_ERROR));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
string joinChanStr = ctx.Args.FirstOrDefault();
|
||||
ChatChannel joinChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(joinChanStr));
|
||||
string joinChanStr = ctx.Args.FirstOrDefault() ?? "Channel";
|
||||
ChatChannel? joinChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(joinChanStr));
|
||||
|
||||
if(joinChan == null) {
|
||||
if(joinChan is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, joinChanStr));
|
||||
ctx.Chat.ForceChannel(ctx.User);
|
||||
return;
|
||||
|
|
|
@ -21,13 +21,13 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
}
|
||||
|
||||
string banUserTarget = ctx.Args.ElementAtOrDefault(0);
|
||||
string banDurationStr = ctx.Args.ElementAtOrDefault(1);
|
||||
string? banUserTarget = ctx.Args.ElementAtOrDefault(0);
|
||||
string? banDurationStr = ctx.Args.ElementAtOrDefault(1);
|
||||
int banReasonIndex = 1;
|
||||
ChatUser banUser = null;
|
||||
ChatUser? banUser = null;
|
||||
|
||||
if(banUserTarget == null || (banUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(banUserTarget))) == null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, banUser == null ? "User" : banUserTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, banUserTarget ?? "User"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,11 @@ namespace SharpChat.Commands {
|
|||
string userIp = ctx.Chat.GetRemoteAddresses(banUser).FirstOrDefault()?.ToString() ?? string.Empty;
|
||||
|
||||
// obviously it makes no sense to only check for one ip address but that's current misuzu limitations
|
||||
MisuzuBanInfo fbi = await Misuzu.CheckBanAsync(userId, userIp);
|
||||
MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId, userIp);
|
||||
if(fbi is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fbi.IsBanned && !fbi.HasExpired) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||
|
|
|
@ -20,7 +20,8 @@ namespace SharpChat.Commands {
|
|||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
ChatUser targetUser = null;
|
||||
|
||||
ChatUser? targetUser = null;
|
||||
int offset = 0;
|
||||
|
||||
if(setOthersNick && long.TryParse(ctx.Args.FirstOrDefault(), out long targetUserId) && targetUserId > 0) {
|
||||
|
@ -56,7 +57,7 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
}
|
||||
|
||||
string previousName = targetUser == ctx.User ? (targetUser.NickName ?? targetUser.UserName) : null;
|
||||
string? previousName = targetUser.UserId == ctx.User.UserId ? (targetUser.NickName ?? targetUser.UserName) : null;
|
||||
ctx.Chat.UpdateUser(targetUser, nickName: nickStr, silent: previousName == null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
}
|
||||
|
||||
string unbanAddrTarget = ctx.Args.FirstOrDefault();
|
||||
if(string.IsNullOrWhiteSpace(unbanAddrTarget) || !IPAddress.TryParse(unbanAddrTarget, out IPAddress unbanAddr)) {
|
||||
string? unbanAddrTarget = ctx.Args.FirstOrDefault();
|
||||
if(string.IsNullOrWhiteSpace(unbanAddrTarget) || !IPAddress.TryParse(unbanAddrTarget, out IPAddress? unbanAddr)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
@ -29,7 +29,11 @@ namespace SharpChat.Commands {
|
|||
unbanAddrTarget = unbanAddr.ToString();
|
||||
|
||||
Task.Run(async () => {
|
||||
MisuzuBanInfo banInfo = await Misuzu.CheckBanAsync(ipAddr: unbanAddrTarget);
|
||||
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(ipAddr: unbanAddrTarget);
|
||||
if(banInfo is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!banInfo.IsBanned || banInfo.HasExpired) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanAddrTarget));
|
||||
|
|
|
@ -20,13 +20,13 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
bool unbanUserTargetIsName = true;
|
||||
string unbanUserTarget = ctx.Args.FirstOrDefault();
|
||||
string? unbanUserTarget = ctx.Args.FirstOrDefault();
|
||||
if(string.IsNullOrWhiteSpace(unbanUserTarget)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
ChatUser unbanUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(unbanUserTarget));
|
||||
ChatUser? unbanUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(unbanUserTarget));
|
||||
if(unbanUser == null && long.TryParse(unbanUserTarget, out long unbanUserId)) {
|
||||
unbanUserTargetIsName = false;
|
||||
unbanUser = ctx.Chat.Users.FirstOrDefault(u => u.UserId == unbanUserId);
|
||||
|
@ -36,7 +36,11 @@ namespace SharpChat.Commands {
|
|||
unbanUserTarget = unbanUser.UserId.ToString();
|
||||
|
||||
Task.Run(async () => {
|
||||
MisuzuBanInfo banInfo = await Misuzu.CheckBanAsync(unbanUserTarget, userIdIsName: unbanUserTargetIsName);
|
||||
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(unbanUserTarget, userIdIsName: unbanUserTargetIsName);
|
||||
if(banInfo is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!banInfo.IsBanned || banInfo.HasExpired) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanUserTarget));
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
}
|
||||
|
||||
string ipUserStr = ctx.Args.FirstOrDefault();
|
||||
ChatUser ipUser;
|
||||
string? ipUserStr = ctx.Args.FirstOrDefault();
|
||||
ChatUser? ipUser = null;
|
||||
|
||||
if(string.IsNullOrWhiteSpace(ipUserStr) || (ipUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(ipUserStr))) == null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, ipUserStr ?? "User"));
|
||||
|
|
|
@ -16,8 +16,8 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
}
|
||||
|
||||
string whisperUserStr = ctx.Args.FirstOrDefault();
|
||||
ChatUser whisperUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(whisperUserStr));
|
||||
string whisperUserStr = ctx.Args.FirstOrDefault() ?? string.Empty;
|
||||
ChatUser? whisperUser = ctx.Chat.Users.FirstOrDefault(u => u.NameEquals(whisperUserStr));
|
||||
|
||||
if(whisperUser == null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_FOUND, true, whisperUserStr));
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace SharpChat.Commands {
|
|||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
StringBuilder whoChanSB = new();
|
||||
string whoChanStr = ctx.Args.FirstOrDefault();
|
||||
string? whoChanStr = ctx.Args.FirstOrDefault();
|
||||
|
||||
if(string.IsNullOrEmpty(whoChanStr)) {
|
||||
foreach(ChatUser whoUser in ctx.Chat.Users) {
|
||||
|
@ -29,9 +29,9 @@ namespace SharpChat.Commands {
|
|||
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_SERVER, false, whoChanSB));
|
||||
} else {
|
||||
ChatChannel whoChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(whoChanStr));
|
||||
ChatChannel? whoChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(whoChanStr));
|
||||
|
||||
if(whoChan == null) {
|
||||
if(whoChan is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, whoChanStr));
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Config {
|
||||
public class CachedValue<T>(IConfig config, string name, TimeSpan lifetime, T fallback) {
|
||||
public class CachedValue<T>(IConfig config, string name, TimeSpan lifetime, T? fallback) {
|
||||
private IConfig Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
|
||||
private string Name { get; } = name ?? throw new ArgumentNullException(nameof(name));
|
||||
private object ConfigAccess { get; } = new();
|
||||
|
||||
private object CurrentValue { get; set; }
|
||||
private object? CurrentValue { get; set; } = default(T);
|
||||
private DateTimeOffset LastRead { get; set; }
|
||||
|
||||
public T Value {
|
||||
public T? Value {
|
||||
get {
|
||||
lock(ConfigAccess) { // this lock doesn't really make sense since it doesn't affect other config calls
|
||||
DateTimeOffset now = DateTimeOffset.Now;
|
||||
|
@ -19,18 +19,18 @@ namespace SharpChat.Config {
|
|||
Logger.Debug($"Read {Name} ({CurrentValue})");
|
||||
}
|
||||
}
|
||||
return (T)CurrentValue;
|
||||
return (T?)CurrentValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator T(CachedValue<T> val) => val.Value;
|
||||
public static implicit operator T?(CachedValue<T?> val) => val.Value;
|
||||
|
||||
public void Refresh() {
|
||||
LastRead = DateTimeOffset.MinValue;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return Value.ToString();
|
||||
return Value?.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,22 +10,22 @@ namespace SharpChat.Config {
|
|||
/// <summary>
|
||||
/// Reads a raw (string) value from the config.
|
||||
/// </summary>
|
||||
string ReadValue(string name, string fallback = null);
|
||||
string? ReadValue(string name, string? fallback = null);
|
||||
|
||||
/// <summary>
|
||||
/// Reads and casts value from the config.
|
||||
/// </summary>
|
||||
/// <exception cref="ConfigTypeException">Type conversion failed.</exception>
|
||||
T ReadValue<T>(string name, T fallback = default);
|
||||
T? ReadValue<T>(string name, T? fallback = default);
|
||||
|
||||
/// <summary>
|
||||
/// Reads and casts a value from the config. Returns fallback when type conversion fails.
|
||||
/// </summary>
|
||||
T SafeReadValue<T>(string name, T fallback);
|
||||
T? SafeReadValue<T>(string name, T? fallback);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an object that caches the read value for a certain amount of time, avoiding disk reads for frequently used non-static values.
|
||||
/// </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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,15 +9,15 @@ namespace SharpChat.Config {
|
|||
return Prefix + name;
|
||||
}
|
||||
|
||||
public string ReadValue(string name, string fallback = null) {
|
||||
public string? ReadValue(string name, string? fallback = null) {
|
||||
return Config.ReadValue(GetName(name), fallback);
|
||||
}
|
||||
|
||||
public T ReadValue<T>(string name, T fallback = default) {
|
||||
public T? ReadValue<T>(string name, T? fallback = default) {
|
||||
return Config.ReadValue(GetName(name), fallback);
|
||||
}
|
||||
|
||||
public T SafeReadValue<T>(string name, T fallback) {
|
||||
public T? SafeReadValue<T>(string name, T? fallback) {
|
||||
return Config.SafeReadValue(GetName(name), fallback);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ namespace SharpChat.Config {
|
|||
return Config.ScopeTo(GetName(prefix));
|
||||
}
|
||||
|
||||
public CachedValue<T> ReadCached<T>(string name, T fallback = default, TimeSpan? lifetime = null) {
|
||||
public CachedValue<T> ReadCached<T>(string name, T? fallback = default, TimeSpan? lifetime = null) {
|
||||
return Config.ReadCached(GetName(name), fallback, lifetime);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,14 +27,14 @@ namespace SharpChat.Config {
|
|||
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
|
||||
throw new ConfigLockException();
|
||||
|
||||
try {
|
||||
Stream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
string line;
|
||||
string? line;
|
||||
while((line = StreamReader.ReadLine()) != null) {
|
||||
if(string.IsNullOrWhiteSpace(line))
|
||||
continue;
|
||||
|
@ -56,8 +56,8 @@ namespace SharpChat.Config {
|
|||
return fallback;
|
||||
}
|
||||
|
||||
public T ReadValue<T>(string name, T fallback = default) {
|
||||
object value = ReadValue(name);
|
||||
public T? ReadValue<T>(string name, T? fallback = default) {
|
||||
object? value = ReadValue(name);
|
||||
if(value == null)
|
||||
return fallback;
|
||||
|
||||
|
@ -77,7 +77,7 @@ namespace SharpChat.Config {
|
|||
}
|
||||
}
|
||||
|
||||
public T SafeReadValue<T>(string name, T fallback) {
|
||||
public T? SafeReadValue<T>(string name, T? fallback) {
|
||||
try {
|
||||
return ReadValue(name, fallback);
|
||||
} catch(ConfigTypeException) {
|
||||
|
@ -94,7 +94,7 @@ namespace SharpChat.Config {
|
|||
return new ScopedConfig(this, prefix);
|
||||
}
|
||||
|
||||
public CachedValue<T> ReadCached<T>(string name, T fallback = default, TimeSpan? lifetime = null) {
|
||||
public CachedValue<T> ReadCached<T>(string name, T? fallback = default, TimeSpan? lifetime = null) {
|
||||
return new CachedValue<T>(this, name, lifetime ?? CACHE_LIFETIME, fallback);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ namespace SharpChat.EventStorage
|
|||
int senderRank,
|
||||
string senderNick,
|
||||
ChatUserPermissions senderPerms,
|
||||
object data = null,
|
||||
object? data = null,
|
||||
StoredEventFlags flags = StoredEventFlags.None
|
||||
);
|
||||
void RemoveEvent(StoredEventInfo evt);
|
||||
StoredEventInfo GetEvent(long seqId);
|
||||
StoredEventInfo? GetEvent(long seqId);
|
||||
IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,16 +4,21 @@ using System.Collections.Generic;
|
|||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SharpChat.EventStorage
|
||||
{
|
||||
namespace SharpChat.EventStorage {
|
||||
public partial class MariaDBEventStorage(string connString) : IEventStorage {
|
||||
private string ConnectionString { get; } = connString ?? throw new ArgumentNullException(nameof(connString));
|
||||
|
||||
public void AddEvent(
|
||||
long id, string type,
|
||||
long id,
|
||||
string type,
|
||||
string channelName,
|
||||
long senderId, string senderName, ChatColour senderColour, int senderRank, string senderNick, ChatUserPermissions senderPerms,
|
||||
object data = null,
|
||||
long senderId,
|
||||
string senderName,
|
||||
ChatColour senderColour,
|
||||
int senderRank,
|
||||
string senderNick,
|
||||
ChatUserPermissions senderPerms,
|
||||
object? data = null,
|
||||
StoredEventFlags flags = StoredEventFlags.None
|
||||
) {
|
||||
ArgumentNullException.ThrowIfNull(type);
|
||||
|
@ -37,30 +42,9 @@ namespace SharpChat.EventStorage
|
|||
);
|
||||
}
|
||||
|
||||
public long AddEvent(string type, ChatUser user, ChatChannel channel, object data = null, StoredEventFlags flags = StoredEventFlags.None) {
|
||||
ArgumentNullException.ThrowIfNull(type);
|
||||
|
||||
long id = SharpId.Next();
|
||||
|
||||
AddEvent(
|
||||
id, type,
|
||||
channel?.Name,
|
||||
user?.UserId ?? 0,
|
||||
user?.UserName ?? string.Empty,
|
||||
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) {
|
||||
try {
|
||||
using MySqlDataReader reader = RunQuery(
|
||||
using MySqlDataReader? reader = RunQuery(
|
||||
"SELECT `event_id`, `event_type`, `event_flags`, `event_data`, `event_target`"
|
||||
+ ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`"
|
||||
+ ", UNIX_TIMESTAMP(`event_created`) AS `event_created`"
|
||||
|
@ -70,6 +54,9 @@ namespace SharpChat.EventStorage
|
|||
new MySqlParameter("id", seqId)
|
||||
);
|
||||
|
||||
if(reader is null)
|
||||
return null;
|
||||
|
||||
while(reader.Read()) {
|
||||
StoredEventInfo evt = ReadEvent(reader);
|
||||
if(evt != null)
|
||||
|
@ -92,7 +79,7 @@ namespace SharpChat.EventStorage
|
|||
ChatColour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
||||
reader.GetInt32("event_sender_rank"),
|
||||
(ChatUserPermissions)reader.GetInt32("event_sender_perms"),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick")
|
||||
reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? string.Empty : reader.GetString("event_sender_nick")
|
||||
),
|
||||
DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_deleted")) ? null : DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_deleted")),
|
||||
|
@ -106,7 +93,7 @@ namespace SharpChat.EventStorage
|
|||
List<StoredEventInfo> events = [];
|
||||
|
||||
try {
|
||||
using MySqlDataReader reader = RunQuery(
|
||||
using MySqlDataReader? reader = RunQuery(
|
||||
"SELECT `event_id`, `event_type`, `event_flags`, `event_data`, `event_target`"
|
||||
+ ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`"
|
||||
+ ", UNIX_TIMESTAMP(`event_created`) AS `event_created`"
|
||||
|
@ -120,6 +107,8 @@ namespace SharpChat.EventStorage
|
|||
new MySqlParameter("amount", amount),
|
||||
new MySqlParameter("offset", offset)
|
||||
);
|
||||
if(reader is null)
|
||||
return events;
|
||||
|
||||
while(reader.Read()) {
|
||||
StoredEventInfo evt = ReadEvent(reader);
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace SharpChat.EventStorage {
|
|||
);
|
||||
}
|
||||
|
||||
public static string BuildConnString(string host, string username, string password, string database) {
|
||||
public static string BuildConnString(string? host, string? username, string? password, string? database) {
|
||||
return new MySqlConnectionStringBuilder {
|
||||
Server = host,
|
||||
UserID = username,
|
||||
|
@ -49,7 +49,7 @@ namespace SharpChat.EventStorage {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private MySqlDataReader RunQuery(string command, params MySqlParameter[] parameters) {
|
||||
private MySqlDataReader? RunQuery(string command, params MySqlParameter[] parameters) {
|
||||
try {
|
||||
MySqlConnection conn = GetConnection();
|
||||
MySqlCommand cmd = conn.CreateCommand();
|
||||
|
@ -64,7 +64,8 @@ namespace SharpChat.EventStorage {
|
|||
return null;
|
||||
}
|
||||
|
||||
private object RunQueryValue(string command, params MySqlParameter[] parameters) {
|
||||
private T RunQueryValue<T>(string command, params MySqlParameter[] parameters)
|
||||
where T : struct {
|
||||
try {
|
||||
using MySqlConnection conn = GetConnection();
|
||||
using MySqlCommand cmd = conn.CreateCommand();
|
||||
|
@ -72,12 +73,15 @@ namespace SharpChat.EventStorage {
|
|||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
cmd.Prepare();
|
||||
return cmd.ExecuteScalar();
|
||||
|
||||
object? raw = cmd.ExecuteScalar();
|
||||
if(raw is T value)
|
||||
return value;
|
||||
} catch(MySqlException ex) {
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
namespace SharpChat.EventStorage {
|
||||
public partial class MariaDBEventStorage {
|
||||
private void DoMigration(string name, Action action) {
|
||||
bool done = (long)RunQueryValue(
|
||||
bool done = RunQueryValue<long>(
|
||||
"SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name",
|
||||
new MySqlParameter("name", name)
|
||||
) > 0;
|
||||
|
|
|
@ -5,19 +5,19 @@ namespace SharpChat.EventStorage {
|
|||
public class StoredEventInfo(
|
||||
long id,
|
||||
string type,
|
||||
ChatUser sender,
|
||||
ChatUser? sender,
|
||||
DateTimeOffset created,
|
||||
DateTimeOffset? deleted,
|
||||
string channelName,
|
||||
string? channelName,
|
||||
JsonDocument data,
|
||||
StoredEventFlags flags
|
||||
) {
|
||||
public long Id { get; set; } = id;
|
||||
public string Type { get; set; } = type;
|
||||
public ChatUser Sender { get; set; } = sender;
|
||||
public ChatUser? Sender { get; set; } = sender;
|
||||
public DateTimeOffset Created { get; set; } = created;
|
||||
public DateTimeOffset? Deleted { get; set; } = deleted;
|
||||
public string ChannelName { get; set; } = channelName;
|
||||
public string? ChannelName { get; set; } = channelName;
|
||||
public StoredEventFlags Flags { get; set; } = flags;
|
||||
public JsonDocument Data { get; set; } = data;
|
||||
}
|
||||
|
|
|
@ -8,10 +8,16 @@ namespace SharpChat.EventStorage {
|
|||
private readonly Dictionary<long, StoredEventInfo> Events = [];
|
||||
|
||||
public void AddEvent(
|
||||
long id, string type,
|
||||
long id,
|
||||
string type,
|
||||
string channelName,
|
||||
long senderId, string senderName, ChatColour senderColour, int senderRank, string senderNick, ChatUserPermissions senderPerms,
|
||||
object data = null,
|
||||
long senderId,
|
||||
string senderName,
|
||||
ChatColour senderColour,
|
||||
int senderRank,
|
||||
string senderNick,
|
||||
ChatUserPermissions senderPerms,
|
||||
object? data = null,
|
||||
StoredEventFlags flags = StoredEventFlags.None
|
||||
) {
|
||||
ArgumentNullException.ThrowIfNull(type);
|
||||
|
@ -28,8 +34,8 @@ namespace SharpChat.EventStorage {
|
|||
), DateTimeOffset.Now, null, channelName, hack, flags));
|
||||
}
|
||||
|
||||
public StoredEventInfo GetEvent(long seqId) {
|
||||
return Events.TryGetValue(seqId, out StoredEventInfo evt) ? evt : null;
|
||||
public StoredEventInfo? GetEvent(long seqId) {
|
||||
return Events.TryGetValue(seqId, out StoredEventInfo? evt) ? evt : null;
|
||||
}
|
||||
|
||||
public void RemoveEvent(StoredEventInfo evt) {
|
||||
|
|
|
@ -25,7 +25,6 @@ namespace SharpChat.Events {
|
|||
public string SenderNickName { get; } = senderNickName;
|
||||
public ChatUserPermissions SenderPerms { get; } = senderPerms;
|
||||
public DateTimeOffset MessageCreated { get; } = msgCreated;
|
||||
public string MessageChannel { get; }
|
||||
public string MessageText { get; } = msgText;
|
||||
public bool IsPrivate { get; } = isPrivate;
|
||||
public bool IsAction { get; } = isAction;
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace SharpChat.Misuzu {
|
|||
public long UserId { get; set; }
|
||||
|
||||
[JsonPropertyName("username")]
|
||||
public string UserName { get; set; }
|
||||
public string? UserName { get; set; }
|
||||
|
||||
[JsonPropertyName("colour_raw")]
|
||||
public int ColourRaw { get; set; }
|
||||
|
|
|
@ -7,10 +7,10 @@ namespace SharpChat.Misuzu {
|
|||
public bool IsBanned { get; set; }
|
||||
|
||||
[JsonPropertyName("user_id")]
|
||||
public string UserId { get; set; }
|
||||
public string? UserId { get; set; }
|
||||
|
||||
[JsonPropertyName("ip_addr")]
|
||||
public string RemoteAddress { get; set; }
|
||||
public string? RemoteAddress { get; set; }
|
||||
|
||||
[JsonPropertyName("is_perma")]
|
||||
public bool IsPermanent { get; set; }
|
||||
|
@ -20,7 +20,7 @@ namespace SharpChat.Misuzu {
|
|||
|
||||
// only populated in list request
|
||||
[JsonPropertyName("user_name")]
|
||||
public string UserName { get; set; }
|
||||
public string? UserName { get; set; }
|
||||
|
||||
[JsonPropertyName("user_colour")]
|
||||
public int UserColourRaw { get; set; }
|
||||
|
|
|
@ -46,11 +46,11 @@ namespace SharpChat.Misuzu {
|
|||
}
|
||||
|
||||
public string CreateBufferSignature(byte[] bytes) {
|
||||
using HMACSHA256 algo = new(Encoding.UTF8.GetBytes(SecretKey));
|
||||
using HMACSHA256 algo = new(Encoding.UTF8.GetBytes(SecretKey!));
|
||||
return string.Concat(algo.ComputeHash(bytes).Select(c => c.ToString("x2")));
|
||||
}
|
||||
|
||||
public async Task<MisuzuAuthInfo> AuthVerifyAsync(string method, string token, string ipAddr) {
|
||||
public async Task<MisuzuAuthInfo?> AuthVerifyAsync(string method, string token, string ipAddr) {
|
||||
method ??= string.Empty;
|
||||
token ??= string.Empty;
|
||||
ipAddr ??= string.Empty;
|
||||
|
@ -112,7 +112,7 @@ namespace SharpChat.Misuzu {
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<MisuzuBanInfo> CheckBanAsync(string userId = null, string ipAddr = null, bool userIdIsName = false) {
|
||||
public async Task<MisuzuBanInfo?> CheckBanAsync(string? userId = null, string? ipAddr = null, bool userIdIsName = false) {
|
||||
userId ??= string.Empty;
|
||||
ipAddr ??= string.Empty;
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace SharpChat.Misuzu {
|
|||
);
|
||||
}
|
||||
|
||||
public async Task<MisuzuBanInfo[]> GetBanListAsync() {
|
||||
public async Task<MisuzuBanInfo[]?> GetBanListAsync() {
|
||||
string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
|
||||
string url = string.Format(BANS_LIST_URL, BaseURL, Uri.EscapeDataString(now));
|
||||
string sig = string.Format(BANS_LIST_SIG, now);
|
||||
|
@ -169,8 +169,8 @@ namespace SharpChat.Misuzu {
|
|||
string target = kind switch {
|
||||
BanRevokeKind.UserId => banInfo.UserId,
|
||||
BanRevokeKind.RemoteAddress => banInfo.RemoteAddress,
|
||||
_ => string.Empty,
|
||||
};
|
||||
_ => null,
|
||||
} ?? string.Empty;
|
||||
|
||||
string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
|
||||
string url = string.Format(BANS_REVOKE_URL, BaseURL, Uri.EscapeDataString(type), Uri.EscapeDataString(target), Uri.EscapeDataString(now));
|
||||
|
|
|
@ -12,9 +12,9 @@ namespace SharpChat.Packet {
|
|||
|
||||
public class AuthFailPacket : ServerPacket {
|
||||
public AuthFailReason Reason { get; private set; }
|
||||
public MisuzuBanInfo BanInfo { get; private set; }
|
||||
public MisuzuBanInfo? BanInfo { get; private set; }
|
||||
|
||||
public AuthFailPacket(AuthFailReason reason, MisuzuBanInfo fbi = null) {
|
||||
public AuthFailPacket(AuthFailReason reason, MisuzuBanInfo? fbi = null) {
|
||||
Reason = reason;
|
||||
|
||||
if(reason == AuthFailReason.Banned)
|
||||
|
@ -43,10 +43,10 @@ namespace SharpChat.Packet {
|
|||
if(Reason == AuthFailReason.Banned) {
|
||||
sb.Append('\t');
|
||||
|
||||
if(BanInfo.IsPermanent)
|
||||
if(BanInfo?.IsPermanent == true)
|
||||
sb.Append("-1");
|
||||
else
|
||||
sb.Append(BanInfo.ExpiresAt.ToUnixTimeSeconds());
|
||||
sb.Append(BanInfo?.ExpiresAt.ToUnixTimeSeconds() ?? 0);
|
||||
}
|
||||
|
||||
yield return sb.ToString();
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append("\t-1\t0\fbanlist\f");
|
||||
|
||||
foreach(MisuzuBanInfo ban in Bans) {
|
||||
string banStr = string.IsNullOrEmpty(ban.UserName) ? ban.RemoteAddress : ban.UserName;
|
||||
string banStr = string.IsNullOrEmpty(ban.UserName) ? (ban.RemoteAddress ?? "::") : (ban.UserName ?? $"({ban.UserId})");
|
||||
sb.AppendFormat(@"<a href=""javascript:void(0);"" onclick=""Chat.SendMessageWrapper('/unban '+ this.innerHTML);"">{0}</a>, ", banStr);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace SharpChat.Packet
|
|||
switch(Event.Type) {
|
||||
case "msg:add":
|
||||
case "SharpChat.Events.ChatMessage":
|
||||
if(isBroadcast) {
|
||||
if(isBroadcast || Event.Sender is null) {
|
||||
sb.Append(V1_CHATBOT);
|
||||
sb.Append("0\fsay\f");
|
||||
} else {
|
||||
|
@ -39,11 +39,11 @@ namespace SharpChat.Packet
|
|||
sb.Append("<i>");
|
||||
|
||||
sb.Append(
|
||||
Event.Data.RootElement.GetProperty("text").GetString()
|
||||
(Event.Data.RootElement.GetProperty("text").GetString()?
|
||||
.Replace("<", "<")
|
||||
.Replace(">", ">")
|
||||
.Replace("\n", " <br/> ")
|
||||
.Replace("\t", " ")
|
||||
.Replace("\t", " ")) ?? string.Empty
|
||||
);
|
||||
|
||||
if(isAction)
|
||||
|
@ -54,21 +54,21 @@ namespace SharpChat.Packet
|
|||
case "SharpChat.Events.UserConnectEvent":
|
||||
sb.Append(V1_CHATBOT);
|
||||
sb.Append("0\fjoin\f");
|
||||
sb.Append(Event.Sender.LegacyName);
|
||||
sb.Append(Event.Sender?.LegacyName ?? "?????");
|
||||
break;
|
||||
|
||||
case "chan:join":
|
||||
case "SharpChat.Events.UserChannelJoinEvent":
|
||||
sb.Append(V1_CHATBOT);
|
||||
sb.Append("0\fjchan\f");
|
||||
sb.Append(Event.Sender.LegacyName);
|
||||
sb.Append(Event.Sender?.LegacyName ?? "?????");
|
||||
break;
|
||||
|
||||
case "chan:leave":
|
||||
case "SharpChat.Events.UserChannelLeaveEvent":
|
||||
sb.Append(V1_CHATBOT);
|
||||
sb.Append("0\flchan\f");
|
||||
sb.Append(Event.Sender.LegacyName);
|
||||
sb.Append(Event.Sender?.LegacyName ?? "?????");
|
||||
break;
|
||||
|
||||
case "user:disconnect":
|
||||
|
@ -93,7 +93,7 @@ namespace SharpChat.Packet
|
|||
}
|
||||
|
||||
sb.Append('\f');
|
||||
sb.Append(Event.Sender.LegacyName);
|
||||
sb.Append(Event.Sender?.LegacyName ?? "?????");
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,14 @@ namespace SharpChat.PacketHandlers {
|
|||
public void Handle(ChatPacketHandlerContext ctx) {
|
||||
string[] args = ctx.SplitText(3);
|
||||
|
||||
string authMethod = args.ElementAtOrDefault(1);
|
||||
string? authMethod = args.ElementAtOrDefault(1);
|
||||
if(string.IsNullOrWhiteSpace(authMethod)) {
|
||||
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
|
||||
ctx.Connection.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
string authToken = args.ElementAtOrDefault(2);
|
||||
string? authToken = args.ElementAtOrDefault(2);
|
||||
if(string.IsNullOrWhiteSpace(authToken)) {
|
||||
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
|
||||
ctx.Connection.Dispose();
|
||||
|
@ -47,7 +47,7 @@ namespace SharpChat.PacketHandlers {
|
|||
}
|
||||
|
||||
Task.Run(async () => {
|
||||
MisuzuAuthInfo fai;
|
||||
MisuzuAuthInfo? fai;
|
||||
string ipAddr = ctx.Connection.RemoteAddress.ToString();
|
||||
|
||||
try {
|
||||
|
@ -63,14 +63,14 @@ namespace SharpChat.PacketHandlers {
|
|||
#endif
|
||||
}
|
||||
|
||||
if(!fai.Success) {
|
||||
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: {fai.Reason}");
|
||||
if(fai?.Success != true) {
|
||||
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: {fai?.Reason ?? "unknown"}");
|
||||
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
|
||||
ctx.Connection.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
MisuzuBanInfo fbi;
|
||||
MisuzuBanInfo? fbi;
|
||||
try {
|
||||
fbi = await Misuzu.CheckBanAsync(fai.UserId.ToString(), ipAddr);
|
||||
} catch(Exception ex) {
|
||||
|
@ -84,7 +84,7 @@ namespace SharpChat.PacketHandlers {
|
|||
#endif
|
||||
}
|
||||
|
||||
if(fbi.IsBanned && !fbi.HasExpired) {
|
||||
if(fbi?.IsBanned == true && !fbi.HasExpired) {
|
||||
Logger.Write($"<{ctx.Connection.Id}> User is banned.");
|
||||
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Banned, fbi));
|
||||
ctx.Connection.Dispose();
|
||||
|
@ -93,12 +93,12 @@ namespace SharpChat.PacketHandlers {
|
|||
|
||||
await ctx.Chat.ContextAccess.WaitAsync();
|
||||
try {
|
||||
ChatUser user = ctx.Chat.Users.FirstOrDefault(u => u.UserId == fai.UserId);
|
||||
ChatUser? user = ctx.Chat.Users.FirstOrDefault(u => u.UserId == fai.UserId);
|
||||
|
||||
if(user == null)
|
||||
user = new ChatUser(
|
||||
fai.UserId,
|
||||
fai.UserName,
|
||||
fai.UserName ?? $"({fai.UserId})",
|
||||
fai.Colour,
|
||||
fai.Rank,
|
||||
fai.Permissions
|
||||
|
@ -106,7 +106,7 @@ namespace SharpChat.PacketHandlers {
|
|||
else
|
||||
ctx.Chat.UpdateUser(
|
||||
user,
|
||||
userName: fai.UserName,
|
||||
userName: fai.UserName ?? $"({fai.UserId})",
|
||||
colour: fai.Colour,
|
||||
rank: fai.Rank,
|
||||
perms: fai.Permissions
|
||||
|
@ -125,7 +125,7 @@ namespace SharpChat.PacketHandlers {
|
|||
|
||||
if(File.Exists("welcome.txt")) {
|
||||
IEnumerable<string> lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x));
|
||||
string line = lines.ElementAtOrDefault(RNG.Next(lines.Count()));
|
||||
string? line = lines.ElementAtOrDefault(RNG.Next(lines.Count()));
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(line))
|
||||
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, line));
|
||||
|
|
|
@ -27,10 +27,8 @@ namespace SharpChat.PacketHandlers {
|
|||
public void Handle(ChatPacketHandlerContext ctx) {
|
||||
string[] args = ctx.SplitText(3);
|
||||
|
||||
ChatUser user = ctx.Connection.User;
|
||||
|
||||
// No longer concats everything after index 1 with \t, no previous implementation did that either
|
||||
string messageText = args.ElementAtOrDefault(2);
|
||||
ChatUser? user = ctx.Connection.User;
|
||||
string? messageText = args.ElementAtOrDefault(2);
|
||||
|
||||
if(user == null || !user.Can(ChatUserPermissions.SendMessage) || string.IsNullOrWhiteSpace(messageText))
|
||||
return;
|
||||
|
@ -41,8 +39,8 @@ namespace SharpChat.PacketHandlers {
|
|||
|
||||
ctx.Chat.ContextAccess.Wait();
|
||||
try {
|
||||
if(!ctx.Chat.UserLastChannel.TryGetValue(user.UserId, out ChatChannel channel)
|
||||
&& !ctx.Chat.IsInChannel(user, channel))
|
||||
if(!ctx.Chat.UserLastChannel.TryGetValue(user.UserId, out ChatChannel? channel)
|
||||
&& (channel is null || !ctx.Chat.IsInChannel(user, channel)))
|
||||
return;
|
||||
|
||||
if(user.Status != ChatUserStatus.Online)
|
||||
|
@ -62,19 +60,11 @@ namespace SharpChat.PacketHandlers {
|
|||
|
||||
if(messageText.StartsWith('/')) {
|
||||
ChatCommandContext context = new(messageText, ctx.Chat, user, ctx.Connection, channel);
|
||||
|
||||
IChatCommand command = null;
|
||||
|
||||
foreach(IChatCommand cmd in Commands)
|
||||
if(cmd.IsMatch(context)) {
|
||||
command = cmd;
|
||||
break;
|
||||
cmd.Dispatch(context);
|
||||
return;
|
||||
}
|
||||
|
||||
if(command != null) {
|
||||
command.Dispatch(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace SharpChat {
|
|||
public class Program {
|
||||
public const string CONFIG = "sharpchat.cfg";
|
||||
|
||||
public static void Main(string[] args) {
|
||||
public static void Main() {
|
||||
Console.WriteLine(@" _____ __ ________ __ ");
|
||||
Console.WriteLine(@" / ___// /_ ____ __________ / ____/ /_ ____ _/ /_");
|
||||
Console.WriteLine(@" \__ \/ __ \/ __ `/ ___/ __ \/ / / __ \/ __ `/ __/");
|
||||
|
@ -29,7 +29,7 @@ namespace SharpChat {
|
|||
using ManualResetEvent mre = new(false);
|
||||
bool hasCancelled = false;
|
||||
|
||||
void cancelKeyPressHandler(object sender, ConsoleCancelEventArgs ev) {
|
||||
void cancelKeyPressHandler(object? sender, ConsoleCancelEventArgs ev) {
|
||||
Console.CancelKeyPress -= cancelKeyPressHandler;
|
||||
hasCancelled = true;
|
||||
ev.Cancel = true;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
using Fleck;
|
||||
#nullable disable
|
||||
|
||||
using Fleck;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
|
@ -19,9 +19,9 @@ namespace SharpChat {
|
|||
#endif
|
||||
|
||||
try {
|
||||
using Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(@"SharpChat.version.txt");
|
||||
using Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(@"SharpChat.version.txt")!;
|
||||
using StreamReader sr = new(s);
|
||||
VersionString = sr.ReadLine().Trim();
|
||||
VersionString = sr.ReadLine()!.Trim();
|
||||
VersionStringShort = VersionString.Length > 10 ? VersionString[..10] : VersionString;
|
||||
} catch {
|
||||
VersionStringShort = VersionString = UNKNOWN;
|
||||
|
|
|
@ -53,24 +53,27 @@ namespace SharpChat {
|
|||
|
||||
Context = new ChatContext(evtStore);
|
||||
|
||||
string[] channelNames = config.ReadValue("channels", DEFAULT_CHANNELS);
|
||||
string[]? channelNames = config.ReadValue("channels", DEFAULT_CHANNELS);
|
||||
if(channelNames is not null)
|
||||
foreach(string channelName in channelNames) {
|
||||
IConfig channelCfg = config.ScopeTo($"channels:{channelName}");
|
||||
|
||||
foreach(string channelName in channelNames) {
|
||||
IConfig channelCfg = config.ScopeTo($"channels:{channelName}");
|
||||
string name = channelCfg.SafeReadValue("name", string.Empty)!;
|
||||
if(string.IsNullOrWhiteSpace(name))
|
||||
name = channelName;
|
||||
|
||||
string name = channelCfg.SafeReadValue("name", string.Empty);
|
||||
if(string.IsNullOrWhiteSpace(name))
|
||||
name = channelName;
|
||||
ChatChannel channelInfo = new(
|
||||
name,
|
||||
channelCfg.SafeReadValue("password", string.Empty)!,
|
||||
rank: channelCfg.SafeReadValue("minRank", 0)
|
||||
);
|
||||
|
||||
ChatChannel channelInfo = new(
|
||||
name,
|
||||
channelCfg.SafeReadValue("password", string.Empty),
|
||||
rank: channelCfg.SafeReadValue("minRank", 0)
|
||||
);
|
||||
Context.Channels.Add(channelInfo);
|
||||
DefaultChannel ??= channelInfo;
|
||||
}
|
||||
|
||||
Context.Channels.Add(channelInfo);
|
||||
DefaultChannel ??= channelInfo;
|
||||
}
|
||||
if(DefaultChannel is null)
|
||||
throw new Exception("The default channel could not be determined.");
|
||||
|
||||
GuestHandlers.Add(new AuthHandler(Misuzu, DefaultChannel, MaxMessageLength, MaxConnections));
|
||||
|
||||
|
@ -156,13 +159,13 @@ namespace SharpChat {
|
|||
|
||||
// this doesn't affect non-authed connections?????
|
||||
if(conn.User is not null && conn.User.Rank < FloodKickExemptRank) {
|
||||
ChatUser banUser = null;
|
||||
ChatUser? banUser = null;
|
||||
string banAddr = string.Empty;
|
||||
TimeSpan banDuration = TimeSpan.MinValue;
|
||||
|
||||
Context.ContextAccess.Wait();
|
||||
try {
|
||||
if(!Context.UserRateLimiters.TryGetValue(conn.User.UserId, out RateLimiter rateLimiter))
|
||||
if(!Context.UserRateLimiters.TryGetValue(conn.User.UserId, out RateLimiter? rateLimiter))
|
||||
Context.UserRateLimiters.Add(conn.User.UserId, rateLimiter = new RateLimiter(
|
||||
ChatUser.DEFAULT_SIZE,
|
||||
ChatUser.DEFAULT_MINIMUM_DELAY,
|
||||
|
@ -202,7 +205,7 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
ChatPacketHandlerContext context = new(msg, Context, conn);
|
||||
IChatPacketHandler handler = conn.User is null
|
||||
IChatPacketHandler? handler = conn.User is null
|
||||
? GuestHandlers.FirstOrDefault(h => h.IsMatch(context))
|
||||
: AuthedHandlers.FirstOrDefault(h => h.IsMatch(context));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue