Switched to Index brand random Snowflakes instead of SharpIds.
If you were still handling message ids as integers in an environment that can't handle signed 64-bit integers you're going to be having a fun time after this update!
This commit is contained in:
parent
f5c8f2ae1d
commit
e17aed7c25
77 changed files with 290 additions and 338 deletions
SharpChat.sln
SharpChat
ChatCommandContext.csChatConnection.csChatContext.csChatPacketHandlerContext.csChatUser.csChatUserPermissions.cs
Commands
AFKCommand.csActionCommand.csBanListCommand.csBroadcastCommand.csCreateChannelCommand.csDeleteChannelCommand.csDeleteMessageCommand.csJoinChannelCommand.csKickBanCommand.csNickCommand.csPardonAddressCommand.csPardonUserCommand.csPasswordChannelCommand.csRankChannelCommand.csRemoteAddressCommand.csShutdownRestartCommand.csWhisperCommand.csWhoCommand.cs
Config
EventStorage
IEventStorage.csMariaDBEventStorage.csMariaDBEventStorage_Migrations.csStoredEventFlags.csStoredEventInfo.csVirtualEventStorage.cs
Events
IServerPacket.csMisuzu
Packet
AuthFailPacket.csAuthSuccessPacket.csBanListPacket.csChannelCreatePacket.csChannelDeletePacket.csChannelUpdatePacket.csChatMessageAddPacket.csChatMessageDeletePacket.csContextChannelsPacket.csContextClearPacket.csContextMessagePacket.csContextUsersPacket.csForceDisconnectPacket.csLegacyCommandResponse.csPongPacket.csUserChannelForceJoinPacket.csUserChannelJoinPacket.csUserChannelLeavePacket.csUserConnectPacket.csUserDisconnectPacket.csUserUpdatePacket.cs
PacketHandlers
Program.csRNG.csRateLimiter.csSharpChat.csprojSharpChatWebSocketServer.csSharpId.csSharpInfo.csSockChatServer.csSharpChatCommon
|
@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
start.sh = start.sh
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpChatCommon", "SharpChatCommon\SharpChatCommon.csproj", "{C8B619A7-7815-426D-B459-20EE26F7460E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -24,6 +26,10 @@ Global
|
|||
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DDB24C19-B802-4C96-AC15-0449C6FC77F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C8B619A7-7815-426D-B459-20EE26F7460E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C8B619A7-7815-426D-B459-20EE26F7460E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C8B619A7-7815-426D-B459-20EE26F7460E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C8B619A7-7815-426D-B459-20EE26F7460E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat {
|
||||
namespace SharpChat {
|
||||
public class ChatCommandContext {
|
||||
public string Name { get; }
|
||||
public string[] Args { get; }
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using Fleck;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace SharpChat {
|
||||
|
|
|
@ -1,30 +1,35 @@
|
|||
using SharpChat.Events;
|
||||
using SharpChat.EventStorage;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SharpChat.Snowflake;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
public class ChatContext(IEventStorage evtStore) {
|
||||
public class ChatContext {
|
||||
public record ChannelUserAssoc(long UserId, string ChannelName);
|
||||
|
||||
public readonly SemaphoreSlim ContextAccess = new(1, 1);
|
||||
|
||||
public SnowflakeGenerator SnowflakeGenerator { get; } = new();
|
||||
public RandomSnowflake RandomSnowflake { get; }
|
||||
|
||||
public HashSet<ChatChannel> Channels { get; } = [];
|
||||
public HashSet<ChatConnection> Connections { get; } = [];
|
||||
public HashSet<ChatUser> Users { get; } = [];
|
||||
public IEventStorage Events { get; } = evtStore ?? throw new ArgumentNullException(nameof(evtStore));
|
||||
public IEventStorage Events { get; }
|
||||
public HashSet<ChannelUserAssoc> ChannelUsers { get; } = [];
|
||||
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = [];
|
||||
public Dictionary<long, ChatChannel> UserLastChannel { get; } = [];
|
||||
|
||||
public ChatContext(IEventStorage evtStore) {
|
||||
Events = evtStore ?? throw new ArgumentNullException(nameof(evtStore));
|
||||
RandomSnowflake = new(SnowflakeGenerator);
|
||||
}
|
||||
|
||||
public void DispatchEvent(IChatEvent eventInfo) {
|
||||
if(eventInfo is MessageCreateEvent mce) {
|
||||
if(mce.IsBroadcast) {
|
||||
Send(new LegacyCommandResponse(LCR.BROADCAST, false, mce.MessageText));
|
||||
Send(new LegacyCommandResponse(RandomSnowflake.Next(), LCR.BROADCAST, false, mce.MessageText));
|
||||
} else if(mce.IsPrivate) {
|
||||
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed
|
||||
// e.g. nook sees @Arysil and Arysil sees @nook
|
||||
|
@ -185,7 +190,7 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
if(hasChanged)
|
||||
SendToUserChannels(user, new UserUpdatePacket(user, previousName));
|
||||
SendToUserChannels(user, new UserUpdatePacket(RandomSnowflake.Next(), user, previousName));
|
||||
}
|
||||
|
||||
public void BanUser(ChatUser user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
|
||||
|
@ -205,8 +210,9 @@ namespace SharpChat {
|
|||
|
||||
public void HandleJoin(ChatUser user, ChatChannel chan, ChatConnection conn, int maxMsgLength) {
|
||||
if(!IsInChannel(user, chan)) {
|
||||
SendTo(chan, new UserConnectPacket(DateTimeOffset.Now, user));
|
||||
Events.AddEvent(SharpId.Next(), "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
long msgId = RandomSnowflake.Next();
|
||||
SendTo(chan, new UserConnectPacket(msgId, DateTimeOffset.Now, user));
|
||||
Events.AddEvent(msgId, "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
}
|
||||
|
||||
conn.Send(new AuthSuccessPacket(user, chan, maxMsgLength));
|
||||
|
@ -233,8 +239,9 @@ namespace SharpChat {
|
|||
foreach(ChatChannel chan in channels) {
|
||||
ChannelUsers.Remove(new ChannelUserAssoc(user.UserId, chan.Name));
|
||||
|
||||
SendTo(chan, new UserDisconnectPacket(DateTimeOffset.Now, user, reason));
|
||||
Events.AddEvent(SharpId.Next(), "user:disconnect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, new { reason = (int)reason }, StoredEventFlags.Log);
|
||||
long msgId = RandomSnowflake.Next();
|
||||
SendTo(chan, new UserDisconnectPacket(msgId, DateTimeOffset.Now, user, reason));
|
||||
Events.AddEvent(msgId, "user:disconnect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, new { reason = (int)reason }, StoredEventFlags.Log);
|
||||
|
||||
if(chan.IsTemporary && chan.IsOwner(user))
|
||||
RemoveChannel(chan);
|
||||
|
@ -249,13 +256,13 @@ namespace SharpChat {
|
|||
|
||||
if(!user.Can(ChatUserPermissions.JoinAnyChannel) && chan.IsOwner(user)) {
|
||||
if(chan.Rank > user.Rank) {
|
||||
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INSUFFICIENT_HIERARCHY, true, chan.Name));
|
||||
SendTo(user, new LegacyCommandResponse(RandomSnowflake.Next(), LCR.CHANNEL_INSUFFICIENT_HIERARCHY, true, chan.Name));
|
||||
ForceChannel(user);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(chan.Password) && chan.Password != password) {
|
||||
SendTo(user, new LegacyCommandResponse(LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
|
||||
SendTo(user, new LegacyCommandResponse(RandomSnowflake.Next(), LCR.CHANNEL_INVALID_PASSWORD, true, chan.Name));
|
||||
ForceChannel(user);
|
||||
return;
|
||||
}
|
||||
|
@ -270,10 +277,13 @@ namespace SharpChat {
|
|||
|
||||
ChatChannel oldChan = UserLastChannel[user.UserId];
|
||||
|
||||
SendTo(oldChan, new UserChannelLeavePacket(user));
|
||||
Events.AddEvent(SharpId.Next(), "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
SendTo(chan, new UserChannelJoinPacket(user));
|
||||
Events.AddEvent(SharpId.Next(), "chan:join", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
long leaveId = RandomSnowflake.Next();
|
||||
SendTo(oldChan, new UserChannelLeavePacket(leaveId, user));
|
||||
Events.AddEvent(leaveId, "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
|
||||
long joinId = RandomSnowflake.Next();
|
||||
SendTo(chan, new UserChannelJoinPacket(joinId, user));
|
||||
Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
|
||||
SendTo(user, new ContextClearPacket(ContextClearMode.MessagesUsers));
|
||||
SendTo(user, new ContextUsersPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)));
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat {
|
||||
namespace SharpChat {
|
||||
public class ChatPacketHandlerContext(
|
||||
string text,
|
||||
ChatContext chat,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using SharpChat.Commands;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using SharpChat.Commands;
|
||||
|
||||
namespace SharpChat {
|
||||
public class ChatUser(
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat {
|
||||
namespace SharpChat {
|
||||
[Flags]
|
||||
public enum ChatUserPermissions : int {
|
||||
KickUser = 0x00000001,
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using SharpChat.Events;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class ActionCommand : IChatCommand {
|
||||
|
@ -18,7 +16,7 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
ctx.Chat.RandomSnowflake.Next(),
|
||||
ctx.Channel.Name,
|
||||
ctx.User.UserId,
|
||||
ctx.User.UserName,
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class BanListCommand(MisuzuClient msz) : IChatCommand {
|
||||
|
@ -13,8 +11,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.BanUser | ChatUserPermissions.KickUser)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,9 @@ namespace SharpChat.Commands {
|
|||
MisuzuBanInfo[]? mbi = await Misuzu.GetBanListAsync();
|
||||
|
||||
if(mbi is null)
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.GENERIC_ERROR, true));
|
||||
else
|
||||
ctx.Chat.SendTo(ctx.User, new BanListPacket(mbi));
|
||||
ctx.Chat.SendTo(ctx.User, new BanListPacket(msgId, mbi));
|
||||
}).Wait();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using SharpChat.Events;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class BroadcastCommand : IChatCommand {
|
||||
|
@ -10,13 +9,15 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.Broadcast)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
msgId,
|
||||
string.Empty,
|
||||
ctx.User.UserId,
|
||||
ctx.User.UserName,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class CreateChannelCommand : IChatCommand {
|
||||
|
@ -8,8 +7,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.CreateChannel)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -17,7 +18,7 @@ namespace SharpChat.Commands {
|
|||
|
||||
bool createChanHasHierarchy;
|
||||
if(ctx.Args.Length < 1 || (createChanHasHierarchy = firstArg.All(char.IsDigit) && ctx.Args.Length < 2)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -27,19 +28,19 @@ namespace SharpChat.Commands {
|
|||
createChanHierarchy = 0;
|
||||
|
||||
if(createChanHierarchy > ctx.User.Rank) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.INSUFFICIENT_HIERARCHY));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.INSUFFICIENT_HIERARCHY));
|
||||
return;
|
||||
}
|
||||
|
||||
string createChanName = string.Join('_', ctx.Args.Skip(createChanHasHierarchy ? 1 : 0));
|
||||
|
||||
if(!ChatChannel.CheckName(createChanName)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NAME_INVALID));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_NAME_INVALID));
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx.Chat.Channels.Any(c => c.NameEquals(createChanName))) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_ALREADY_EXISTS, true, createChanName));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_ALREADY_EXISTS, true, createChanName));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -55,7 +56,7 @@ namespace SharpChat.Commands {
|
|||
ctx.Chat.SendTo(ccu, new ChannelCreatePacket(ctx.Channel));
|
||||
|
||||
ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password);
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_CREATED, false, createChan.Name));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_CREATED, false, createChan.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class DeleteChannelCommand : IChatCommand {
|
||||
|
@ -11,8 +10,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(ctx.Args.Length < 1 || string.IsNullOrWhiteSpace(ctx.Args.FirstOrDefault())) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -20,17 +21,17 @@ namespace SharpChat.Commands {
|
|||
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));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_NOT_FOUND, true, delChanName));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.DeleteChannel) && delChan.IsOwner(ctx.User)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_DELETE_FAILED, true, delChan.Name));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_DELETE_FAILED, true, delChan.Name));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.Chat.RemoveChannel(delChan);
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_DELETED, false, delChan.Name));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_DELETED, false, delChan.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using SharpChat.EventStorage;
|
||||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands
|
||||
{
|
||||
|
@ -13,24 +12,25 @@ namespace SharpChat.Commands
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
bool deleteAnyMessage = ctx.User.Can(ChatUserPermissions.DeleteAnyMessage);
|
||||
|
||||
if(!deleteAnyMessage && !ctx.User.Can(ChatUserPermissions.DeleteOwnMessage)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
|
||||
|
||||
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));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.MESSAGE_DELETE_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class JoinChannelCommand : IChatCommand {
|
||||
|
@ -8,11 +7,12 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
string joinChanStr = ctx.Args.FirstOrDefault() ?? "Channel";
|
||||
ChatChannel? joinChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(joinChanStr));
|
||||
|
||||
if(joinChan is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, joinChanStr));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_NOT_FOUND, true, joinChanStr));
|
||||
ctx.Chat.ForceChannel(ctx.User);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class KickBanCommand(MisuzuClient msz) : IChatCommand {
|
||||
|
@ -15,9 +12,10 @@ namespace SharpChat.Commands {
|
|||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
bool isBanning = ctx.NameEquals("ban");
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(isBanning ? ChatUserPermissions.BanUser : ChatUserPermissions.KickUser)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -27,19 +25,19 @@ namespace SharpChat.Commands {
|
|||
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, banUserTarget ?? "User"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_FOUND, true, banUserTarget ?? "User"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ctx.User.IsSuper && banUser.Rank >= ctx.User.Rank && banUser != ctx.User) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||
return;
|
||||
}
|
||||
|
||||
TimeSpan duration = isBanning ? TimeSpan.MaxValue : TimeSpan.Zero;
|
||||
if(!string.IsNullOrWhiteSpace(banDurationStr) && double.TryParse(banDurationStr, out double durationSeconds)) {
|
||||
if(durationSeconds < 0) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,12 +59,12 @@ namespace SharpChat.Commands {
|
|||
// 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);
|
||||
if(fbi is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.GENERIC_ERROR, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fbi.IsBanned && !fbi.HasExpired) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.KICK_NOT_ALLOWED, true, banUser.LegacyName));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
|
@ -14,10 +12,11 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
bool setOthersNick = ctx.User.Can(ChatUserPermissions.SetOthersNickname);
|
||||
|
||||
if(!setOthersNick && !ctx.User.Can(ChatUserPermissions.SetOwnNickname)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -32,7 +31,7 @@ namespace SharpChat.Commands {
|
|||
targetUser ??= ctx.User;
|
||||
|
||||
if(ctx.Args.Length < offset) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -53,7 +52,7 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(nickStr) && ctx.Chat.Users.Any(u => u.NameEquals(nickStr))) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.NAME_IN_USE, true, nickStr));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.NAME_IN_USE, true, nickStr));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class PardonAddressCommand(MisuzuClient msz) : IChatCommand {
|
||||
|
@ -15,14 +12,16 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.BanUser | ChatUserPermissions.KickUser)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -31,20 +30,20 @@ namespace SharpChat.Commands {
|
|||
Task.Run(async () => {
|
||||
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(ipAddr: unbanAddrTarget);
|
||||
if(banInfo is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.GENERIC_ERROR, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!banInfo.IsBanned || banInfo.HasExpired) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanAddrTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_BANNED, true, unbanAddrTarget));
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasBanned = await Misuzu.RevokeBanAsync(banInfo, MisuzuClient.BanRevokeKind.RemoteAddress);
|
||||
if(wasBanned)
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_UNBANNED, false, unbanAddrTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_UNBANNED, false, unbanAddrTarget));
|
||||
else
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanAddrTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_BANNED, true, unbanAddrTarget));
|
||||
}).Wait();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class PardonUserCommand(MisuzuClient msz) : IChatCommand {
|
||||
|
@ -14,15 +11,17 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.BanUser | ChatUserPermissions.KickUser)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
bool unbanUserTargetIsName = true;
|
||||
string? unbanUserTarget = ctx.Args.FirstOrDefault();
|
||||
if(string.IsNullOrWhiteSpace(unbanUserTarget)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -38,20 +37,20 @@ namespace SharpChat.Commands {
|
|||
Task.Run(async () => {
|
||||
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(unbanUserTarget, userIdIsName: unbanUserTargetIsName);
|
||||
if(banInfo is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.GENERIC_ERROR, true));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.GENERIC_ERROR, true));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!banInfo.IsBanned || banInfo.HasExpired) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanUserTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_BANNED, true, unbanUserTarget));
|
||||
return;
|
||||
}
|
||||
|
||||
bool wasBanned = await Misuzu.RevokeBanAsync(banInfo, MisuzuClient.BanRevokeKind.UserId);
|
||||
if(wasBanned)
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_UNBANNED, false, unbanUserTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_UNBANNED, false, unbanUserTarget));
|
||||
else
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USER_NOT_BANNED, true, unbanUserTarget));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_BANNED, true, unbanUserTarget));
|
||||
}).Wait();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.SetChannelPassword) || ctx.Channel.IsOwner(ctx.User)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19,7 +21,7 @@ namespace SharpChat.Commands {
|
|||
chanPass = string.Empty;
|
||||
|
||||
ctx.Chat.UpdateChannel(ctx.Channel, password: chanPass);
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_PASSWORD_CHANGED, false));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_PASSWORD_CHANGED, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class RankChannelCommand : IChatCommand {
|
||||
|
@ -10,18 +9,20 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.SetChannelHierarchy) || ctx.Channel.IsOwner(ctx.User)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(ctx.Args.Length < 1 || !int.TryParse(ctx.Args.First(), out int chanHierarchy) || chanHierarchy > ctx.User.Rank) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.INSUFFICIENT_HIERARCHY));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.INSUFFICIENT_HIERARCHY));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.Chat.UpdateChannel(ctx.Channel, hierarchy: chanHierarchy);
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_HIERARCHY_CHANGED, false));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_HIERARCHY_CHANGED, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
|
@ -10,8 +9,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(!ctx.User.Can(ChatUserPermissions.SeeIPAddress)) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, "/ip"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, "/ip"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19,12 +20,12 @@ namespace SharpChat.Commands {
|
|||
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"));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_FOUND, true, ipUserStr ?? "User"));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(IPAddress ip in ctx.Chat.GetRemoteAddresses(ipUser))
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.IP_ADDRESS, false, ipUser.UserName, ip));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.IP_ADDRESS, false, ipUser.UserName, ip));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class ShutdownRestartCommand(ManualResetEvent waitHandle, Func<bool> shutdownCheck) : IChatCommand {
|
||||
|
@ -14,7 +12,8 @@ namespace SharpChat.Commands {
|
|||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
if(ctx.User.UserId != 1) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_NOT_ALLOWED, true, $"/{ctx.Name}"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using SharpChat.Events;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
public class WhisperCommand : IChatCommand {
|
||||
|
@ -11,8 +9,10 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
|
||||
if(ctx.Args.Length < 2) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.COMMAND_FORMAT_ERROR));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.COMMAND_FORMAT_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace SharpChat.Commands {
|
|||
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));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USER_NOT_FOUND, true, whisperUserStr));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace SharpChat.Commands {
|
|||
return;
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
msgId,
|
||||
ChatUser.GetDMChannelName(ctx.User, whisperUser),
|
||||
ctx.User.UserId,
|
||||
ctx.User.UserName,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Packet;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Commands {
|
||||
|
@ -9,6 +8,7 @@ namespace SharpChat.Commands {
|
|||
}
|
||||
|
||||
public void Dispatch(ChatCommandContext ctx) {
|
||||
long msgId = ctx.Chat.RandomSnowflake.Next();
|
||||
StringBuilder whoChanSB = new();
|
||||
string? whoChanStr = ctx.Args.FirstOrDefault();
|
||||
|
||||
|
@ -27,17 +27,17 @@ namespace SharpChat.Commands {
|
|||
if(whoChanSB.Length > 2)
|
||||
whoChanSB.Length -= 2;
|
||||
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_SERVER, false, whoChanSB));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USERS_LISTING_SERVER, false, whoChanSB));
|
||||
} else {
|
||||
ChatChannel? whoChan = ctx.Chat.Channels.FirstOrDefault(c => c.NameEquals(whoChanStr));
|
||||
|
||||
if(whoChan is null) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.CHANNEL_NOT_FOUND, true, whoChanStr));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.CHANNEL_NOT_FOUND, true, whoChanStr));
|
||||
return;
|
||||
}
|
||||
|
||||
if(whoChan.Rank > ctx.User.Rank || (whoChan.HasPassword && !ctx.User.Can(ChatUserPermissions.JoinAnyChannel))) {
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_ERROR, true, whoChanStr));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USERS_LISTING_ERROR, true, whoChanStr));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace SharpChat.Commands {
|
|||
if(whoChanSB.Length > 2)
|
||||
whoChanSB.Length -= 2;
|
||||
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(LCR.USERS_LISTING_CHANNEL, false, whoChan.Name, whoChanSB));
|
||||
ctx.Chat.SendTo(ctx.User, new LegacyCommandResponse(msgId, LCR.USERS_LISTING_CHANNEL, false, whoChan.Name, whoChanSB));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Config {
|
||||
namespace SharpChat.Config {
|
||||
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));
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Config {
|
||||
namespace SharpChat.Config {
|
||||
public abstract class ConfigException : Exception {
|
||||
public ConfigException(string message) : base(message) { }
|
||||
public ConfigException(string message, Exception ex) : base(message, ex) { }
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Config {
|
||||
namespace SharpChat.Config {
|
||||
public interface IConfig : IDisposable {
|
||||
/// <summary>
|
||||
/// Creates a proxy object that forces all names to start with the given prefix.
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Config {
|
||||
namespace SharpChat.Config {
|
||||
public class ScopedConfig(IConfig config, string prefix) : IConfig {
|
||||
private IConfig Config { get; } = config ?? throw new ArgumentNullException(nameof(config));
|
||||
private string Prefix { get; } = prefix ?? throw new ArgumentNullException(nameof(prefix));
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Config {
|
||||
public class StreamConfig : IConfig {
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpChat.EventStorage
|
||||
{
|
||||
namespace SharpChat.EventStorage {
|
||||
public interface IEventStorage {
|
||||
void AddEvent(
|
||||
long id,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using MySqlConnector;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using MySqlConnector;
|
||||
using System;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
public partial class MariaDBEventStorage {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
namespace SharpChat.EventStorage {
|
||||
[Flags]
|
||||
public enum StoredEventFlags {
|
||||
None = 0,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
public class StoredEventInfo(
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
public class VirtualEventStorage : IEventStorage {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
namespace SharpChat.Events {
|
||||
public class MessageCreateEvent(
|
||||
long msgId,
|
||||
string channelName,
|
||||
|
|
|
@ -1,15 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpChat {
|
||||
namespace SharpChat {
|
||||
public interface IServerPacket {
|
||||
long SequenceId { get; }
|
||||
IEnumerable<string> Pack();
|
||||
}
|
||||
|
||||
public abstract class ServerPacket(long sequenceId = 0) : IServerPacket {
|
||||
// Allow sequence id to be manually set for potential message repeats
|
||||
public long SequenceId { get; } = sequenceId > 0 ? sequenceId : SharpId.Next();
|
||||
|
||||
public abstract IEnumerable<string> Pack();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharpChat.Misuzu {
|
||||
public class MisuzuAuthInfo {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharpChat.Misuzu {
|
||||
public class MisuzuBanInfo {
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
using SharpChat.Config;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.Misuzu {
|
||||
public class MisuzuClient {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using SharpChat.Misuzu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
|
@ -10,7 +8,7 @@ namespace SharpChat.Packet {
|
|||
Banned,
|
||||
}
|
||||
|
||||
public class AuthFailPacket : ServerPacket {
|
||||
public class AuthFailPacket : IServerPacket {
|
||||
public AuthFailReason Reason { get; private set; }
|
||||
public MisuzuBanInfo? BanInfo { get; private set; }
|
||||
|
||||
|
@ -21,7 +19,7 @@ namespace SharpChat.Packet {
|
|||
BanInfo = fbi ?? throw new ArgumentNullException(nameof(fbi));
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('1');
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class AuthSuccessPacket(
|
||||
ChatUser user,
|
||||
ChatChannel channel,
|
||||
int maxMsgLength
|
||||
) : ServerPacket {
|
||||
) : IServerPacket {
|
||||
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('1');
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
using SharpChat.Misuzu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class BanListPacket(IEnumerable<MisuzuBanInfo> bans) : ServerPacket {
|
||||
public class BanListPacket(
|
||||
long msgId,
|
||||
IEnumerable<MisuzuBanInfo> bans
|
||||
) : IServerPacket {
|
||||
public IEnumerable<MisuzuBanInfo> Bans { get; private set; } = bans ?? throw new ArgumentNullException(nameof(bans));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('2');
|
||||
|
@ -25,7 +25,7 @@ namespace SharpChat.Packet {
|
|||
sb.Length -= 2;
|
||||
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
sb.Append("\t10010");
|
||||
|
||||
yield return sb.ToString();
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ChannelCreatePacket(ChatChannel channel) : ServerPacket {
|
||||
public class ChannelCreatePacket(ChatChannel channel) : IServerPacket {
|
||||
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('4');
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ChannelDeletePacket(ChatChannel channel) : ServerPacket {
|
||||
public class ChannelDeletePacket(ChatChannel channel) : IServerPacket {
|
||||
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('4');
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ChannelUpdatePacket(string previousName, ChatChannel channel) : ServerPacket {
|
||||
public class ChannelUpdatePacket(string previousName, ChatChannel channel) : IServerPacket {
|
||||
public string PreviousName { get; private set; } = previousName ?? throw new ArgumentNullException(nameof(previousName));
|
||||
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('4');
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ChatMessageAddPacket(
|
||||
|
@ -10,10 +8,10 @@ namespace SharpChat.Packet {
|
|||
string text,
|
||||
bool isAction,
|
||||
bool isPrivate
|
||||
) : ServerPacket(msgId) {
|
||||
) : IServerPacket {
|
||||
public string Text { get; } = text ?? throw new ArgumentNullException(nameof(text));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('2');
|
||||
|
@ -39,7 +37,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append("</i>");
|
||||
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
sb.AppendFormat(
|
||||
"\t1{0}0{1}{2}",
|
||||
isAction ? '1' : '0',
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ChatMessageDeletePacket(long eventId) : ServerPacket {
|
||||
public override IEnumerable<string> Pack() {
|
||||
public class ChatMessageDeletePacket(long eventId) : IServerPacket {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('6');
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ContextChannelsPacket(IEnumerable<ChatChannel> channels) : ServerPacket {
|
||||
public class ContextChannelsPacket(IEnumerable<ChatChannel> channels) : IServerPacket {
|
||||
public IEnumerable<ChatChannel> Channels { get; private set; } = channels?.Where(c => c != null) ?? throw new ArgumentNullException(nameof(channels));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('7');
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public enum ContextClearMode {
|
||||
|
@ -10,8 +9,8 @@ namespace SharpChat.Packet {
|
|||
MessagesUsersChannels = 4,
|
||||
}
|
||||
|
||||
public class ContextClearPacket(ContextClearMode mode) : ServerPacket {
|
||||
public override IEnumerable<string> Pack() {
|
||||
public class ContextClearPacket(ContextClearMode mode) : IServerPacket {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('8');
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
using SharpChat.EventStorage;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet
|
||||
{
|
||||
public class ContextMessagePacket(StoredEventInfo evt, bool notify = false) : ServerPacket {
|
||||
public class ContextMessagePacket(StoredEventInfo evt, bool notify = false) : IServerPacket {
|
||||
public StoredEventInfo Event { get; private set; } = evt ?? throw new ArgumentNullException(nameof(evt));
|
||||
|
||||
private const string V1_CHATBOT = "-1\tChatBot\tinherit\t\t";
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
bool isAction = Event.Flags.HasFlag(StoredEventFlags.Action);
|
||||
bool isBroadcast = Event.Flags.HasFlag(StoredEventFlags.Broadcast);
|
||||
bool isPrivate = Event.Flags.HasFlag(StoredEventFlags.Private);
|
||||
|
@ -98,7 +96,7 @@ namespace SharpChat.Packet
|
|||
}
|
||||
|
||||
sb.Append('\t');
|
||||
sb.Append(Event.Id < 1 ? SequenceId : Event.Id);
|
||||
sb.Append(Event.Id);
|
||||
sb.Append('\t');
|
||||
sb.Append(notify ? '1' : '0');
|
||||
sb.AppendFormat(
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class ContextUsersPacket(IEnumerable<ChatUser> users) : ServerPacket {
|
||||
public class ContextUsersPacket(IEnumerable<ChatUser> users) : IServerPacket {
|
||||
public IEnumerable<ChatUser> Users { get; private set; } = users?.Where(u => u != null) ?? throw new ArgumentNullException(nameof(users));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('7');
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public enum ForceDisconnectReason {
|
||||
|
@ -8,7 +6,7 @@ namespace SharpChat.Packet {
|
|||
Banned = 1,
|
||||
}
|
||||
|
||||
public class ForceDisconnectPacket : ServerPacket {
|
||||
public class ForceDisconnectPacket : IServerPacket {
|
||||
public ForceDisconnectReason Reason { get; private set; }
|
||||
public DateTimeOffset Expires { get; private set; }
|
||||
|
||||
|
@ -22,7 +20,7 @@ namespace SharpChat.Packet {
|
|||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('9');
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class LegacyCommandResponse(
|
||||
long msgId,
|
||||
string stringId,
|
||||
bool isError = true,
|
||||
params object[] args
|
||||
) : ServerPacket {
|
||||
) : IServerPacket {
|
||||
public string StringId { get; private set; } = stringId ?? throw new ArgumentNullException(nameof(stringId));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
if(StringId == LCR.WELCOME) {
|
||||
|
@ -43,7 +42,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append(StringId);
|
||||
sb.Append("\t0");
|
||||
} else
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
|
||||
sb.Append("\t10010");
|
||||
/*sb.AppendFormat(
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class PongPacket : ServerPacket {
|
||||
public override IEnumerable<string> Pack() {
|
||||
namespace SharpChat.Packet {
|
||||
public class PongPacket : IServerPacket {
|
||||
public IEnumerable<string> Pack() {
|
||||
yield return "0\tpong";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class UserChannelForceJoinPacket(ChatChannel channel) : ServerPacket {
|
||||
public class UserChannelForceJoinPacket(ChatChannel channel) : IServerPacket {
|
||||
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('5');
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class UserChannelJoinPacket(ChatUser user) : ServerPacket {
|
||||
public class UserChannelJoinPacket(long msgId, ChatUser user) : IServerPacket {
|
||||
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('5');
|
||||
|
@ -15,7 +13,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append('\t');
|
||||
sb.Append(User.Pack());
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
|
||||
yield return sb.ToString();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class UserChannelLeavePacket(ChatUser user) : ServerPacket {
|
||||
public class UserChannelLeavePacket(long msgId, ChatUser user) : IServerPacket {
|
||||
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('5');
|
||||
|
@ -15,7 +13,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append('\t');
|
||||
sb.Append(User.UserId);
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
|
||||
yield return sb.ToString();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class UserConnectPacket(DateTimeOffset joined, ChatUser user) : ServerPacket {
|
||||
public class UserConnectPacket(long msgId, DateTimeOffset joined, ChatUser user) : IServerPacket {
|
||||
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('1');
|
||||
|
@ -15,7 +13,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append('\t');
|
||||
sb.Append(User.Pack());
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
|
||||
yield return sb.ToString();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public enum UserDisconnectReason {
|
||||
|
@ -10,10 +8,15 @@ namespace SharpChat.Packet {
|
|||
Flood,
|
||||
}
|
||||
|
||||
public class UserDisconnectPacket(DateTimeOffset disconnected, ChatUser user, UserDisconnectReason reason) : ServerPacket {
|
||||
public class UserDisconnectPacket(
|
||||
long msgId,
|
||||
DateTimeOffset disconnected,
|
||||
ChatUser user,
|
||||
UserDisconnectReason reason
|
||||
) : IServerPacket {
|
||||
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
sb.Append('3');
|
||||
|
@ -42,7 +45,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append('\t');
|
||||
sb.Append(disconnected.ToUnixTimeSeconds());
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
|
||||
yield return sb.ToString();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.Packet {
|
||||
public class UserUpdatePacket(ChatUser user, string previousName = "") : ServerPacket {
|
||||
public class UserUpdatePacket(long msgId, ChatUser user, string previousName = "") : IServerPacket {
|
||||
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
|
||||
|
||||
public override IEnumerable<string> Pack() {
|
||||
public IEnumerable<string> Pack() {
|
||||
StringBuilder sb = new();
|
||||
|
||||
bool isSilent = string.IsNullOrEmpty(previousName);
|
||||
|
@ -20,7 +18,7 @@ namespace SharpChat.Packet {
|
|||
sb.Append('\f');
|
||||
sb.Append(User.LegacyNameWithStatus);
|
||||
sb.Append('\t');
|
||||
sb.Append(SequenceId);
|
||||
sb.Append(msgId);
|
||||
sb.Append("\t10010");
|
||||
yield return sb.ToString();
|
||||
sb.Clear();
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
using SharpChat.Config;
|
||||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.PacketHandlers {
|
||||
public class AuthHandler(
|
||||
|
@ -121,14 +116,14 @@ namespace SharpChat.PacketHandlers {
|
|||
|
||||
ctx.Connection.BumpPing();
|
||||
ctx.Connection.User = user;
|
||||
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, $"Welcome to Flashii Chat, {user.UserName}!"));
|
||||
ctx.Connection.Send(new LegacyCommandResponse(0, LCR.WELCOME, false, $"Welcome to Flashii Chat, {user.UserName}!"));
|
||||
|
||||
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()));
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(line))
|
||||
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, line));
|
||||
ctx.Connection.Send(new LegacyCommandResponse(0, LCR.WELCOME, false, line));
|
||||
}
|
||||
|
||||
ctx.Chat.HandleJoin(user, DefaultChannel, ctx.Connection, MaxMessageLength);
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpChat.PacketHandlers {
|
||||
public class PingHandler(MisuzuClient msz) : IChatPacketHandler {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
using SharpChat.Config;
|
||||
using SharpChat.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SharpChat.Snowflake;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat.PacketHandlers {
|
||||
public class SendMessageHandler(CachedValue<int> maxMsgLength) : IChatPacketHandler {
|
||||
public class SendMessageHandler(
|
||||
RandomSnowflake randomSnowflake,
|
||||
CachedValue<int> maxMsgLength
|
||||
) : IChatPacketHandler {
|
||||
private readonly CachedValue<int> MaxMessageLength = maxMsgLength ?? throw new ArgumentNullException(nameof(maxMsgLength));
|
||||
|
||||
private List<IChatCommand> Commands { get; } = [];
|
||||
|
@ -68,7 +69,7 @@ namespace SharpChat.PacketHandlers {
|
|||
}
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
randomSnowflake.Next(),
|
||||
channel.Name,
|
||||
user.UserId,
|
||||
user.UserName,
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
using SharpChat.Config;
|
||||
using SharpChat.EventStorage;
|
||||
using SharpChat.Misuzu;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
public class Program {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Buffers;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace SharpChat {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat {
|
||||
namespace SharpChat {
|
||||
public class RateLimiter {
|
||||
private readonly int Size;
|
||||
private readonly int MinimumDelay;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -31,4 +32,8 @@
|
|||
<EmbeddedResource Include="version.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharpChatCommon\SharpChatCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
#nullable disable
|
||||
|
||||
using Fleck;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
public static class SharpId {
|
||||
private const long EPOCH = 1588377600000;
|
||||
private static int Counter = 0;
|
||||
|
||||
public static long Next()
|
||||
=> ((DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH) << 8)
|
||||
| (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat {
|
||||
|
|
|
@ -5,11 +5,6 @@ using SharpChat.EventStorage;
|
|||
using SharpChat.Misuzu;
|
||||
using SharpChat.Packet;
|
||||
using SharpChat.PacketHandlers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
public class SockChatServer : IDisposable {
|
||||
|
@ -79,7 +74,7 @@ namespace SharpChat {
|
|||
|
||||
AuthedHandlers.AddRange([
|
||||
new PingHandler(Misuzu),
|
||||
SendMessageHandler = new SendMessageHandler(MaxMessageLength),
|
||||
SendMessageHandler = new SendMessageHandler(Context.RandomSnowflake, MaxMessageLength),
|
||||
]);
|
||||
|
||||
SendMessageHandler.AddCommands([
|
||||
|
@ -184,7 +179,7 @@ namespace SharpChat {
|
|||
|
||||
if(banUser is not null) {
|
||||
if(banDuration == TimeSpan.MinValue) {
|
||||
Context.SendTo(conn.User, new LegacyCommandResponse(LCR.FLOOD_WARN, false));
|
||||
Context.SendTo(conn.User, new LegacyCommandResponse(Context.RandomSnowflake.Next(), LCR.FLOOD_WARN, false));
|
||||
} else {
|
||||
Context.BanUser(conn.User, banDuration, UserDisconnectReason.Flood);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace SharpChat {
|
10
SharpChatCommon/SharpChatCommon.csproj
Normal file
10
SharpChatCommon/SharpChatCommon.csproj
Normal file
|
@ -0,0 +1,10 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>SharpChat</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
13
SharpChatCommon/Snowflake/RandomSnowflake.cs
Normal file
13
SharpChatCommon/Snowflake/RandomSnowflake.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Security.Cryptography;
|
||||
|
||||
namespace SharpChat.Snowflake {
|
||||
public class RandomSnowflake(
|
||||
SnowflakeGenerator? generator = null
|
||||
) {
|
||||
public readonly SnowflakeGenerator Generator = generator ?? new SnowflakeGenerator();
|
||||
|
||||
public long Next(DateTimeOffset? at = null) {
|
||||
return Generator.Next(Math.Abs(BitConverter.ToInt64(RandomNumberGenerator.GetBytes(8))), at);
|
||||
}
|
||||
}
|
||||
}
|
35
SharpChatCommon/Snowflake/SnowflakeGenerator.cs
Normal file
35
SharpChatCommon/Snowflake/SnowflakeGenerator.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
namespace SharpChat.Snowflake {
|
||||
public class SnowflakeGenerator {
|
||||
public const long MASK = 0x7FFFFFFFFFFFFFFF;
|
||||
// previous default epoch was 1588377600000, but snowflakes are much larger than SharpIds
|
||||
public const long EPOCH = 1356998400000;
|
||||
public const byte SHIFT = 16;
|
||||
|
||||
public readonly long Epoch;
|
||||
public readonly byte Shift;
|
||||
public readonly long TimestampMask;
|
||||
public readonly long SequenceMask;
|
||||
|
||||
public SnowflakeGenerator(long epoch = EPOCH, byte shift = SHIFT) {
|
||||
if(epoch is < 0 or > MASK)
|
||||
throw new ArgumentException("Epoch must be a positive int64.", nameof(epoch));
|
||||
if(shift is < 1 or > 63)
|
||||
throw new ArgumentException("Shift must be between or equal to 1 and 63", nameof(shift));
|
||||
|
||||
Epoch = epoch;
|
||||
Shift = shift;
|
||||
|
||||
// i think Index only does this as a hack for how integers work in PHP but its gonna run Once per application instance lol
|
||||
TimestampMask = ~(~0L << (63 - shift));
|
||||
SequenceMask = ~(~0L << shift);
|
||||
}
|
||||
|
||||
public long Now(DateTimeOffset? at = null) {
|
||||
return Math.Max(0, (at ?? DateTimeOffset.UtcNow).ToUnixTimeMilliseconds() - Epoch);
|
||||
}
|
||||
|
||||
public long Next(long sequence, DateTimeOffset? at = null) {
|
||||
return ((Now(at) & TimestampMask) << Shift) | (sequence & SequenceMask);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue