Apply S2C and C2S naming scheme for easy packet direction identification.

This commit is contained in:
flash 2024-05-20 23:00:47 +00:00
parent a0e6fbbeea
commit 980ec5b855
89 changed files with 409 additions and 408 deletions

View file

@ -1,6 +1,6 @@
using SharpChat.Events;
using SharpChat.EventStorage;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Collections.Generic;
using System.Linq;
@ -24,7 +24,7 @@ namespace SharpChat {
public void DispatchEvent(IChatEvent eventInfo) {
if(eventInfo is MessageCreateEvent mce) {
if(mce.IsBroadcast) {
Send(new MessageBroadcastPacket(mce.MessageText));
Send(new MessageBroadcastS2CPacket(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
@ -43,7 +43,7 @@ namespace SharpChat {
return;
foreach(UserInfo user in users)
SendTo(user, new MessageAddPacket(
SendTo(user, new MessageAddS2CPacket(
mce.MessageId,
DateTimeOffset.Now,
mce.SenderId,
@ -54,7 +54,7 @@ namespace SharpChat {
} else {
ChannelInfo? channel = Channels.Get(mce.ChannelName, SockChatUtility.SanitiseChannelName);
if(channel != null)
SendTo(channel, new MessageAddPacket(
SendTo(channel, new MessageAddS2CPacket(
mce.MessageId,
DateTimeOffset.Now,
mce.SenderId,
@ -170,9 +170,9 @@ namespace SharpChat {
if(hasChanged) {
if(previousName != null)
SendToUserChannels(user, new UserUpdateNotificationPacket(previousName, SockChatUtility.GetUserNameWithStatus(user)));
SendToUserChannels(user, new UserUpdateNotificationS2CPacket(previousName, SockChatUtility.GetUserNameWithStatus(user)));
SendToUserChannels(user, new UserUpdatePacket(
SendToUserChannels(user, new UserUpdateS2CPacket(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
user.Colour,
@ -185,9 +185,9 @@ namespace SharpChat {
public void BanUser(UserInfo user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
if(duration > TimeSpan.Zero) {
DateTimeOffset expires = duration >= TimeSpan.MaxValue ? DateTimeOffset.MaxValue : DateTimeOffset.Now + duration;
SendTo(user, new ForceDisconnectPacket(expires));
SendTo(user, new ForceDisconnectS2CPacket(expires));
} else
SendTo(user, new ForceDisconnectPacket());
SendTo(user, new ForceDisconnectS2CPacket());
ConnectionInfo[] conns = Connections.GetUser(user);
foreach(ConnectionInfo conn in conns) {
@ -203,7 +203,7 @@ namespace SharpChat {
public void HandleChannelEventLog(string channelName, Action<SockChatS2CPacket> handler) {
foreach(StoredEventInfo msg in Events.GetChannelEventLog(channelName))
handler(msg.Type switch {
"msg:add" => new MessageAddLogPacket(
"msg:add" => new MessageAddLogS2CPacket(
msg.Id,
msg.Created,
msg.Sender?.UserId ?? -1,
@ -217,23 +217,23 @@ namespace SharpChat {
msg.Flags.HasFlag(StoredEventFlags.Broadcast),
false
),
"user:connect" => new UserConnectLogPacket(
"user:connect" => new UserConnectLogS2CPacket(
msg.Id,
msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
),
"user:disconnect" => new UserDisconnectLogPacket(
"user:disconnect" => new UserDisconnectLogS2CPacket(
msg.Id,
msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserNameWithStatus(msg.Sender),
(UserDisconnectReason)msg.Data.RootElement.GetProperty("reason").GetByte()
),
"chan:join" => new UserChannelJoinLogPacket(
"chan:join" => new UserChannelJoinLogS2CPacket(
msg.Id,
msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
),
"chan:leave" => new UserChannelLeaveLogPacket(
"chan:leave" => new UserChannelLeaveLogS2CPacket(
msg.Id,
msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
@ -244,7 +244,7 @@ namespace SharpChat {
public void HandleJoin(UserInfo user, ChannelInfo chan, ConnectionInfo conn, int maxMsgLength) {
if(!ChannelsUsers.Has(chan, user)) {
SendTo(chan, new UserConnectPacket(
SendTo(chan, new UserConnectS2CPacket(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
user.Colour,
@ -254,7 +254,7 @@ namespace SharpChat {
Events.AddEvent("user:connect", user, chan, flags: StoredEventFlags.Log);
}
conn.Send(new AuthSuccessPacket(
conn.Send(new AuthSuccessS2CPacket(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
user.Colour,
@ -263,8 +263,8 @@ namespace SharpChat {
chan.Name,
maxMsgLength
));
conn.Send(new UsersPopulatePacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulatePacket.ListEntry(
conn.Send(new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulateS2CPacket.ListEntry(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
user.Colour,
@ -276,8 +276,8 @@ namespace SharpChat {
HandleChannelEventLog(chan.Name, p => conn.Send(p));
conn.Send(new ChannelsPopulatePacket(Channels.GetMany(isPublic: true, minRank: user.Rank).Select(
channel => new ChannelsPopulatePacket.ListEntry(channel.Name, channel.HasPassword, channel.IsTemporary)
conn.Send(new ChannelsPopulateS2CPacket(Channels.GetMany(isPublic: true, minRank: user.Rank).Select(
channel => new ChannelsPopulateS2CPacket.ListEntry(channel.Name, channel.HasPassword, channel.IsTemporary)
).ToArray()));
if(Users.Get(userId: user.UserId) == null)
@ -294,7 +294,7 @@ namespace SharpChat {
ChannelsUsers.DeleteUser(user);
foreach(ChannelInfo chan in channels) {
SendTo(chan, new UserDisconnectPacket(
SendTo(chan, new UserDisconnectS2CPacket(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
reason
@ -314,13 +314,13 @@ namespace SharpChat {
if(!user.Permissions.HasFlag(UserPermissions.JoinAnyChannel) && chan.IsOwner(user)) {
if(chan.Rank > user.Rank) {
SendTo(user, new ChannelRankTooLowErrorPacket(chan.Name));
SendTo(user, new ChannelRankTooLowErrorS2CPacket(chan.Name));
ForceChannel(user);
return;
}
if(!string.IsNullOrEmpty(chan.Password) && chan.Password.Equals(password)) {
SendTo(user, new ChannelPasswordWrongErrorPacket(chan.Name));
SendTo(user, new ChannelPasswordWrongErrorS2CPacket(chan.Name));
ForceChannel(user);
return;
}
@ -333,11 +333,11 @@ namespace SharpChat {
ChannelInfo? oldChan = Channels.Get(ChannelsUsers.GetUserLastChannel(user));
if(oldChan != null) {
SendTo(oldChan, new UserChannelLeavePacket(user.UserId));
SendTo(oldChan, new UserChannelLeaveS2CPacket(user.UserId));
Events.AddEvent("chan:leave", user, oldChan, flags: StoredEventFlags.Log);
}
SendTo(chan, new UserChannelJoinPacket(
SendTo(chan, new UserChannelJoinS2CPacket(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
user.Colour,
@ -348,9 +348,9 @@ namespace SharpChat {
if(oldChan != null)
Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log);
SendTo(user, new ContextClearPacket(ContextClearPacket.ClearMode.MessagesUsers));
SendTo(user, new UsersPopulatePacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulatePacket.ListEntry(
SendTo(user, new ContextClearS2CPacket(ContextClearS2CPacket.ClearMode.MessagesUsers));
SendTo(user, new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulateS2CPacket.ListEntry(
user.UserId,
SockChatUtility.GetUserNameWithStatus(user),
user.Colour,
@ -401,7 +401,7 @@ namespace SharpChat {
public void ForceChannel(UserInfo user, ChannelInfo? chan = null) {
chan ??= Channels.Get(ChannelsUsers.GetUserLastChannel(user));
if(chan != null)
SendTo(user, new UserChannelForceJoinPacket(chan.Name));
SendTo(user, new UserChannelForceJoinS2CPacket(chan.Name));
}
public void UpdateChannel(
@ -424,7 +424,7 @@ namespace SharpChat {
// TODO: Users that no longer have access to the channel/gained access to the channel by the rank change should receive delete and create packets respectively
// the server currently doesn't keep track of what channels a user is already aware of so can't really simulate this yet.
foreach(UserInfo user in Users.GetMany(minRank: channel.Rank))
SendTo(user, new ChannelUpdatePacket(prevName, channel.Name, channel.HasPassword, channel.IsTemporary));
SendTo(user, new ChannelUpdateS2CPacket(prevName, channel.Name, channel.HasPassword, channel.IsTemporary));
}
public void RemoveChannel(ChannelInfo channel) {
@ -445,7 +445,7 @@ namespace SharpChat {
// Broadcast deletion of channel
foreach(UserInfo user in Users.GetMany(minRank: channel.Rank))
SendTo(user, new ChannelDeletePacket(channel.Name));
SendTo(user, new ChannelDeleteS2CPacket(channel.Name));
}
}
}

View file

@ -1,31 +1,31 @@
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace SharpChat.Commands {
public class BanListCommand : IUserCommand {
public class BanListCommand : ISockChatClientCommand {
private readonly MisuzuClient Misuzu;
public BanListCommand(MisuzuClient msz) {
Misuzu = msz;
}
public bool IsMatch(UserCommandContext ctx) {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("bans")
|| ctx.NameEquals("banned");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.KickUser)
&& !ctx.User.Permissions.HasFlag(UserPermissions.BanUser)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
Task.Run(async () => {
ctx.Chat.SendTo(ctx.User, new BanListResponsePacket(
ctx.Chat.SendTo(ctx.User, new BanListResponseS2CPacket(
(await Misuzu.GetBanListAsync() ?? Array.Empty<MisuzuBanInfo>()).Select(
ban => string.IsNullOrEmpty(ban.UserName) ? (string.IsNullOrEmpty(ban.RemoteAddress) ? string.Empty : ban.RemoteAddress) : ban.UserName
).ToArray()

View file

@ -1,15 +1,15 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class ChannelCreateCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class ChannelCreateCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("create");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.CreateChannel)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
@ -17,7 +17,7 @@ namespace SharpChat.Commands {
bool createChanHasHierarchy;
if(!ctx.Args.Any() || (createChanHasHierarchy = firstArg.All(char.IsDigit) && ctx.Args.Length < 2)) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -27,19 +27,19 @@ namespace SharpChat.Commands {
createChanHierarchy = 0;
if(createChanHierarchy > ctx.User.Rank) {
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorPacket());
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorS2CPacket());
return;
}
string createChanName = string.Join('_', ctx.Args.Skip(createChanHasHierarchy ? 1 : 0));
if(!SockChatUtility.CheckChannelName(createChanName)) {
ctx.Chat.SendTo(ctx.User, new ChannelNameFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new ChannelNameFormatErrorS2CPacket());
return;
}
if(ctx.Chat.Channels.Get(createChanName, SockChatUtility.SanitiseChannelName) != null) {
ctx.Chat.SendTo(ctx.User, new ChannelNameInUseErrorPacket(createChanName));
ctx.Chat.SendTo(ctx.User, new ChannelNameInUseErrorS2CPacket(createChanName));
return;
}
@ -52,14 +52,14 @@ namespace SharpChat.Commands {
ctx.Chat.Channels.Add(createChan, sanitiseName: SockChatUtility.SanitiseChannelName);
foreach(UserInfo ccu in ctx.Chat.Users.GetMany(minRank: ctx.Channel.Rank))
ctx.Chat.SendTo(ccu, new ChannelCreatePacket(
ctx.Chat.SendTo(ccu, new ChannelCreateS2CPacket(
ctx.Channel.Name,
ctx.Channel.HasPassword,
ctx.Channel.IsTemporary
));
ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password);
ctx.Chat.SendTo(ctx.User, new ChannelCreateResponsePacket(createChan.Name));
ctx.Chat.SendTo(ctx.User, new ChannelCreateResponseS2CPacket(createChan.Name));
}
}
}

View file

@ -1,18 +1,18 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class ChannelDeleteCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class ChannelDeleteCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("delchan") || (
ctx.NameEquals("delete")
&& ctx.Args.FirstOrDefault()?.All(char.IsDigit) == false
);
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.Args.Any() || string.IsNullOrWhiteSpace(ctx.Args.FirstOrDefault())) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -20,17 +20,17 @@ namespace SharpChat.Commands {
ChannelInfo? delChan = ctx.Chat.Channels.Get(delChanName, SockChatUtility.SanitiseChannelName);
if(delChan == null) {
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(delChanName));
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorS2CPacket(delChanName));
return;
}
if(!ctx.User.Permissions.HasFlag(UserPermissions.DeleteChannel) || !delChan.IsOwner(ctx.User)) {
ctx.Chat.SendTo(ctx.User, new ChannelDeleteNotAllowedErrorPacket(delChan.Name));
ctx.Chat.SendTo(ctx.User, new ChannelDeleteNotAllowedErrorS2CPacket(delChan.Name));
return;
}
ctx.Chat.RemoveChannel(delChan);
ctx.Chat.SendTo(ctx.User, new ChannelDeleteResponsePacket(delChan.Name));
ctx.Chat.SendTo(ctx.User, new ChannelDeleteResponseS2CPacket(delChan.Name));
}
}
}

View file

@ -1,18 +1,18 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class ChannelJoinCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class ChannelJoinCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("join");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
string joinChanStr = ctx.Args.FirstOrDefault() ?? string.Empty;
ChannelInfo? joinChan = ctx.Chat.Channels.Get(joinChanStr, SockChatUtility.SanitiseChannelName);
if(joinChan == null) {
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(joinChanStr));
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorS2CPacket(joinChanStr));
ctx.Chat.ForceChannel(ctx.User);
return;
}

View file

@ -1,15 +1,15 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
namespace SharpChat.Commands {
public class ChannelPasswordCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class ChannelPasswordCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("pwd")
|| ctx.NameEquals("password");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.SetChannelPassword) || !ctx.Channel.IsOwner(ctx.User)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
@ -19,7 +19,7 @@ namespace SharpChat.Commands {
chanPass = string.Empty;
ctx.Chat.UpdateChannel(ctx.Channel, password: chanPass);
ctx.Chat.SendTo(ctx.User, new ChannelPasswordChangedResponsePacket());
ctx.Chat.SendTo(ctx.User, new ChannelPasswordChangedResponseS2CPacket());
}
}
}

View file

@ -1,27 +1,27 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class ChannelRankCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class ChannelRankCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("rank")
|| ctx.NameEquals("privilege")
|| ctx.NameEquals("priv");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.SetChannelHierarchy) || !ctx.Channel.IsOwner(ctx.User)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
if(!ctx.Args.Any() || !int.TryParse(ctx.Args.First(), out int chanHierarchy) || chanHierarchy > ctx.User.Rank) {
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorPacket());
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorS2CPacket());
return;
}
ctx.Chat.UpdateChannel(ctx.Channel, minRank: chanHierarchy);
ctx.Chat.SendTo(ctx.User, new ChannelRankChangedResponsePacket());
ctx.Chat.SendTo(ctx.User, new ChannelRankChangedResponseS2CPacket());
}
}
}

View file

@ -0,0 +1,6 @@
namespace SharpChat.Commands {
public interface ISockChatClientCommand {
bool IsMatch(SockChatClientCommandContext ctx);
void Dispatch(SockChatClientCommandContext ctx);
}
}

View file

@ -1,27 +1,27 @@
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace SharpChat.Commands {
public class KickBanCommand : IUserCommand {
public class KickBanCommand : ISockChatClientCommand {
private readonly MisuzuClient Misuzu;
public KickBanCommand(MisuzuClient msz) {
Misuzu = msz;
}
public bool IsMatch(UserCommandContext ctx) {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("kick")
|| ctx.NameEquals("ban");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
bool isBanning = ctx.NameEquals("ban");
if(!ctx.User.Permissions.HasFlag(isBanning ? UserPermissions.BanUser : UserPermissions.KickUser)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
@ -32,19 +32,19 @@ namespace SharpChat.Commands {
(string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(banUserTarget);
if(string.IsNullOrEmpty(name) || (banUser = ctx.Chat.Users.Get(name: name, nameTarget: target)) == null) {
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(banUserTarget));
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorS2CPacket(banUserTarget));
return;
}
if(!ctx.User.IsSuper && banUser.Rank >= ctx.User.Rank && banUser != ctx.User) {
ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorPacket(SockChatUtility.GetUserName(banUser)));
ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorS2CPacket(SockChatUtility.GetUserName(banUser)));
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 CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -64,7 +64,7 @@ namespace SharpChat.Commands {
MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId);
if(fbi != null && fbi.IsBanned && !fbi.HasExpired) {
ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorPacket(SockChatUtility.GetUserName(banUser)));
ctx.Chat.SendTo(ctx.User, new KickBanNotAllowedErrorS2CPacket(SockChatUtility.GetUserName(banUser)));
return;
}

View file

@ -3,13 +3,13 @@ using System;
using System.Linq;
namespace SharpChat.Commands {
public class MessageActionCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class MessageActionCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("action")
|| ctx.NameEquals("me");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.Args.Any())
return;

View file

@ -1,17 +1,17 @@
using SharpChat.Events;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
namespace SharpChat.Commands {
public class MessageBroadcastCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class MessageBroadcastCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("say")
|| ctx.NameEquals("broadcast");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.Broadcast)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}

View file

@ -1,41 +1,40 @@
using SharpChat.EventStorage;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands
{
public class MessageDeleteCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
namespace SharpChat.Commands {
public class MessageDeleteCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("delmsg") || (
ctx.NameEquals("delete")
&& ctx.Args.FirstOrDefault()?.All(char.IsDigit) == true
);
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
bool deleteAnyMessage = ctx.User.Permissions.HasFlag(UserPermissions.DeleteAnyMessage);
if(!deleteAnyMessage && !ctx.User.Permissions.HasFlag(UserPermissions.DeleteOwnMessage)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(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 CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
if(delMsg == null || delMsg.Sender?.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender?.UserId != ctx.User.UserId)) {
ctx.Chat.SendTo(ctx.User, new MessageDeleteNotAllowedErrorPacket());
ctx.Chat.SendTo(ctx.User, new MessageDeleteNotAllowedErrorS2CPacket());
return;
}
ctx.Chat.Events.RemoveEvent(delMsg);
ctx.Chat.Send(new MessageDeletePacket(delMsg.Id));
ctx.Chat.Send(new MessageDeleteS2CPacket(delMsg.Id));
}
}
}

View file

@ -1,18 +1,18 @@
using SharpChat.Events;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Linq;
namespace SharpChat.Commands {
public class MessageWhisperCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class MessageWhisperCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("whisper")
|| ctx.NameEquals("msg");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(ctx.Args.Length < 2) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -21,7 +21,7 @@ namespace SharpChat.Commands {
UserInfo? whisperUser = ctx.Chat.Users.Get(name: name, nameTarget: target);
if(whisperUser == null) {
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(whisperUserStr));
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorS2CPacket(whisperUserStr));
return;
}

View file

@ -1,32 +1,32 @@
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace SharpChat.Commands {
public class PardonAddressCommand : IUserCommand {
public class PardonAddressCommand : ISockChatClientCommand {
private readonly MisuzuClient Misuzu;
public PardonAddressCommand(MisuzuClient msz) {
Misuzu = msz;
}
public bool IsMatch(UserCommandContext ctx) {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("pardonip")
|| ctx.NameEquals("unbanip");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.KickUser)
&& !ctx.User.Permissions.HasFlag(UserPermissions.BanUser)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
string? unbanAddrTarget = ctx.Args.FirstOrDefault();
if(string.IsNullOrWhiteSpace(unbanAddrTarget) || !IPAddress.TryParse(unbanAddrTarget, out IPAddress? unbanAddr)) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -36,15 +36,15 @@ namespace SharpChat.Commands {
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(ipAddr: unbanAddrTarget);
if(banInfo?.IsBanned != true || banInfo.HasExpired) {
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanAddrTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorS2CPacket(unbanAddrTarget));
return;
}
bool wasBanned = await Misuzu.RevokeBanAsync(banInfo, MisuzuClient.BanRevokeKind.RemoteAddress);
if(wasBanned)
ctx.Chat.SendTo(ctx.User, new PardonResponsePacket(unbanAddrTarget));
ctx.Chat.SendTo(ctx.User, new PardonResponseS2CPacket(unbanAddrTarget));
else
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanAddrTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorS2CPacket(unbanAddrTarget));
}).Wait();
}
}

View file

@ -1,32 +1,32 @@
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
using System.Threading.Tasks;
namespace SharpChat.Commands {
public class PardonUserCommand : IUserCommand {
public class PardonUserCommand : ISockChatClientCommand {
private readonly MisuzuClient Misuzu;
public PardonUserCommand(MisuzuClient msz) {
Misuzu = msz;
}
public bool IsMatch(UserCommandContext ctx) {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("pardon")
|| ctx.NameEquals("unban");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.KickUser)
&& !ctx.User.Permissions.HasFlag(UserPermissions.BanUser)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
bool unbanUserTargetIsName = true;
string? unbanUserTarget = ctx.Args.FirstOrDefault();
if(string.IsNullOrWhiteSpace(unbanUserTarget)) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -44,15 +44,15 @@ namespace SharpChat.Commands {
MisuzuBanInfo? banInfo = await Misuzu.CheckBanAsync(unbanUserTarget, userIdIsName: unbanUserTargetIsName);
if(banInfo?.IsBanned != true || banInfo.HasExpired) {
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanUserTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorS2CPacket(unbanUserTarget));
return;
}
bool wasBanned = await Misuzu.RevokeBanAsync(banInfo, MisuzuClient.BanRevokeKind.UserId);
if(wasBanned)
ctx.Chat.SendTo(ctx.User, new PardonResponsePacket(unbanUserTarget));
ctx.Chat.SendTo(ctx.User, new PardonResponseS2CPacket(unbanUserTarget));
else
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorPacket(unbanUserTarget));
ctx.Chat.SendTo(ctx.User, new KickBanNoRecordErrorS2CPacket(unbanUserTarget));
}).Wait();
}
}

View file

@ -1,9 +1,9 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Threading;
namespace SharpChat.Commands {
public class ShutdownRestartCommand : IUserCommand {
public class ShutdownRestartCommand : ISockChatClientCommand {
private readonly ManualResetEvent WaitHandle;
private readonly Func<bool> ShuttingDown;
private readonly Action<bool> SetShutdown;
@ -18,14 +18,14 @@ namespace SharpChat.Commands {
SetShutdown = setShutdown;
}
public bool IsMatch(UserCommandContext ctx) {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("shutdown")
|| ctx.NameEquals("restart");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(ctx.User.UserId != 1) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}

View file

@ -1,8 +1,8 @@
using System;
using System.Linq;
namespace SharpChat {
public class UserCommandContext {
namespace SharpChat.Commands {
public class SockChatClientCommandContext {
public string Name { get; }
public string[] Args { get; }
public ChatContext Chat { get; }
@ -10,7 +10,7 @@ namespace SharpChat {
public ConnectionInfo Connection { get; }
public ChannelInfo Channel { get; }
public UserCommandContext(
public SockChatClientCommandContext(
string text,
ChatContext chat,
UserInfo user,

View file

@ -1,15 +1,15 @@
using System.Linq;
namespace SharpChat.Commands {
public class UserAFKCommand : IUserCommand {
public class UserAFKCommand : ISockChatClientCommand {
private const string DEFAULT = "AFK";
private const int MAX_LENGTH = 5;
public bool IsMatch(UserCommandContext ctx) {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("afk");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
string? statusText = ctx.Args.FirstOrDefault();
if(string.IsNullOrWhiteSpace(statusText))
statusText = DEFAULT;

View file

@ -1,17 +1,17 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class UserNickCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class UserNickCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("nick");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
bool setOthersNick = ctx.User.Permissions.HasFlag(UserPermissions.SetOthersNickname);
if(!setOthersNick && !ctx.User.Permissions.HasFlag(UserPermissions.SetOwnNickname)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
@ -26,7 +26,7 @@ namespace SharpChat.Commands {
targetUser ??= ctx.User;
if(ctx.Args.Length < offset) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket());
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return;
}
@ -43,7 +43,7 @@ namespace SharpChat.Commands {
nickStr = string.Empty;
if(!string.IsNullOrWhiteSpace(nickStr) && ctx.Chat.Users.Get(name: nickStr, nameTarget: UsersContext.NameTarget.UserAndNickName) != null) {
ctx.Chat.SendTo(ctx.User, new UserNameInUseErrorPacket(nickStr));
ctx.Chat.SendTo(ctx.User, new UserNameInUseErrorS2CPacket(nickStr));
return;
}

View file

@ -1,17 +1,17 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class WhoCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class WhoCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("who");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
string? channelName = ctx.Args.FirstOrDefault();
if(string.IsNullOrEmpty(channelName)) {
ctx.Chat.SendTo(ctx.User, new WhoServerResponsePacket(
ctx.Chat.SendTo(ctx.User, new WhoServerResponseS2CPacket(
ctx.Chat.Users.All.Select(u => SockChatUtility.GetUserNameWithStatus(u)).ToArray(),
SockChatUtility.GetUserName(ctx.User)
));
@ -21,16 +21,16 @@ namespace SharpChat.Commands {
ChannelInfo? channel = ctx.Chat.Channels.Get(channelName, SockChatUtility.SanitiseChannelName);
if(channel == null) {
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(channelName));
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorS2CPacket(channelName));
return;
}
if(channel.Rank > ctx.User.Rank || (channel.HasPassword && !ctx.User.Permissions.HasFlag(UserPermissions.JoinAnyChannel))) {
ctx.Chat.SendTo(ctx.User, new WhoChannelNotFoundErrorPacket(channelName));
ctx.Chat.SendTo(ctx.User, new WhoChannelNotFoundErrorS2CPacket(channelName));
return;
}
ctx.Chat.SendTo(ctx.User, new WhoChannelResponsePacket(
ctx.Chat.SendTo(ctx.User, new WhoChannelResponseS2CPacket(
channel.Name,
ctx.Chat.GetChannelUsers(channel).Select(user => SockChatUtility.GetUserNameWithStatus(user)).ToArray(),
SockChatUtility.GetUserNameWithStatus(ctx.User)

View file

@ -1,16 +1,16 @@
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System.Linq;
namespace SharpChat.Commands {
public class WhoisCommand : IUserCommand {
public bool IsMatch(UserCommandContext ctx) {
public class WhoisCommand : ISockChatClientCommand {
public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("ip")
|| ctx.NameEquals("whois");
}
public void Dispatch(UserCommandContext ctx) {
public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.SeeIPAddress)) {
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorPacket(ctx.Name));
ctx.Chat.SendTo(ctx.User, new CommandNotAllowedErrorS2CPacket(ctx.Name));
return;
}
@ -19,12 +19,12 @@ namespace SharpChat.Commands {
(string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(ipUserStr);
if(string.IsNullOrWhiteSpace(name) || (ipUser = ctx.Chat.Users.Get(name: name, nameTarget: target)) == null) {
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(ipUserStr));
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorS2CPacket(ipUserStr));
return;
}
foreach(string remoteAddr in ctx.Chat.Connections.GetUserRemoteAddresses(ipUser))
ctx.Chat.SendTo(ctx.User, new WhoisResponsePacket(ipUser.UserName, remoteAddr));
ctx.Chat.SendTo(ctx.User, new WhoisResponseS2CPacket(ipUser.UserName, remoteAddr));
}
}
}

View file

@ -1,4 +1,5 @@
using Fleck;
using SharpChat.PacketsS2C;
using System;
using System.Net;

View file

@ -1,7 +1,6 @@
using System.Collections.Generic;
namespace SharpChat.EventStorage
{
namespace SharpChat.EventStorage {
public interface IEventStorage {
void AddEvent(
long id, string type,

View file

@ -1,10 +1,8 @@
using System;
namespace SharpChat.EventStorage
{
namespace SharpChat.EventStorage {
[Flags]
public enum StoredEventFlags
{
public enum StoredEventFlags {
None = 0,
Action = 1,
Broadcast = 1 << 1,

View file

@ -1,6 +0,0 @@
namespace SharpChat {
public interface IPacketHandler {
bool IsMatch(PacketHandlerContext ctx);
void Handle(PacketHandlerContext ctx);
}
}

View file

@ -1,6 +0,0 @@
namespace SharpChat {
public interface IUserCommand {
bool IsMatch(UserCommandContext ctx);
void Dispatch(UserCommandContext ctx);
}
}

View file

@ -1,7 +0,0 @@
namespace SharpChat.Packet {
public class PongPacket : SockChatS2CPacket {
public override string Pack() {
return "0\tpong";
}
}
}

View file

@ -1,14 +1,14 @@
using SharpChat.Config;
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace SharpChat.PacketHandlers {
public class AuthHandler : IPacketHandler {
namespace SharpChat.PacketsC2S {
public class AuthC2SPacketHandler : IC2SPacketHandler {
public const string MOTD_FILE = @"welcome.txt";
private readonly DateTimeOffset Started;
@ -17,7 +17,7 @@ namespace SharpChat.PacketHandlers {
private readonly CachedValue<int> MaxMessageLength;
private readonly CachedValue<int> MaxConnections;
public AuthHandler(
public AuthC2SPacketHandler(
DateTimeOffset started,
MisuzuClient msz,
ChannelInfo? defaultChannel,
@ -31,23 +31,23 @@ namespace SharpChat.PacketHandlers {
MaxConnections = maxConns;
}
public bool IsMatch(PacketHandlerContext ctx) {
public bool IsMatch(C2SPacketHandlerContext ctx) {
return ctx.CheckPacketId("1");
}
public void Handle(PacketHandlerContext ctx) {
public void Handle(C2SPacketHandlerContext ctx) {
string[] args = ctx.SplitText(3);
string? authMethod = args.ElementAtOrDefault(1);
if(string.IsNullOrWhiteSpace(authMethod)) {
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.AuthInvalid));
ctx.Connection.Close(1000);
return;
}
string? authToken = args.ElementAtOrDefault(2);
if(string.IsNullOrWhiteSpace(authToken)) {
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.AuthInvalid));
ctx.Connection.Close(1000);
return;
}
@ -66,7 +66,7 @@ namespace SharpChat.PacketHandlers {
fai = await Misuzu.AuthVerifyAsync(authMethod, authToken, ipAddr);
} catch(Exception ex) {
Logger.Write($"<{ctx.Connection.RemoteEndPoint}> Failed to authenticate: {ex}");
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.AuthInvalid));
ctx.Connection.Close(1000);
#if DEBUG
throw;
@ -77,14 +77,14 @@ namespace SharpChat.PacketHandlers {
if(fai == null) {
Logger.Debug($"<{ctx.Connection.RemoteEndPoint}> Auth fail: <null>");
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.Null));
ctx.Connection.Close(1000);
return;
}
if(!fai.Success) {
Logger.Debug($"<{ctx.Connection.RemoteEndPoint}> Auth fail: {fai.Reason}");
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.AuthInvalid));
ctx.Connection.Close(1000);
return;
}
@ -94,7 +94,7 @@ namespace SharpChat.PacketHandlers {
fbi = await Misuzu.CheckBanAsync(fai.UserId.ToString(), ipAddr);
} catch(Exception ex) {
Logger.Write($"<{ctx.Connection.RemoteEndPoint}> Failed auth ban check: {ex}");
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.AuthInvalid));
ctx.Connection.Close(1000);
#if DEBUG
throw;
@ -105,14 +105,14 @@ namespace SharpChat.PacketHandlers {
if(fbi == null) {
Logger.Debug($"<{ctx.Connection.RemoteEndPoint}> Ban check fail: <null>");
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.Null));
ctx.Connection.Close(1000);
return;
}
if(fbi.IsBanned && !fbi.HasExpired) {
Logger.Write($"<{ctx.Connection.RemoteEndPoint}> User is banned.");
ctx.Connection.Send(new AuthFailPacket(fbi.ExpiresAt));
ctx.Connection.Send(new AuthFailS2CPacket(fbi.ExpiresAt));
ctx.Connection.Close(1000);
return;
}
@ -142,21 +142,21 @@ namespace SharpChat.PacketHandlers {
// Enforce a maximum amount of connections per user
if(ctx.Chat.Connections.GetCountForUser(user) >= MaxConnections) {
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.MaxSessions));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.FailReason.MaxSessions));
ctx.Connection.Close(1000);
return;
}
ctx.Connection.BumpPing();
ctx.Chat.Connections.SetUser(ctx.Connection, user);
ctx.Connection.Send(new MOTDPacket(Started, $"Welcome to Flashii Chat, {user.UserName}!"));
ctx.Connection.Send(new MOTDS2CPacket(Started, $"Welcome to Flashii Chat, {user.UserName}!"));
if(File.Exists(MOTD_FILE)) {
IEnumerable<string> lines = File.ReadAllLines(MOTD_FILE).Where(x => !string.IsNullOrWhiteSpace(x));
string? line = lines.ElementAtOrDefault(RNG.Next(lines.Count()));
if(!string.IsNullOrWhiteSpace(line))
ctx.Connection.Send(new MOTDPacket(File.GetLastWriteTimeUtc(MOTD_FILE), line));
ctx.Connection.Send(new MOTDS2CPacket(File.GetLastWriteTimeUtc(MOTD_FILE), line));
}
ctx.Chat.HandleJoin(user, DefaultChannel, ctx.Connection, MaxMessageLength);

View file

@ -1,14 +1,10 @@
namespace SharpChat {
public class PacketHandlerContext {
namespace SharpChat.PacketsC2S {
public class C2SPacketHandlerContext {
public string Text { get; }
public ChatContext Chat { get; }
public ConnectionInfo Connection { get; }
public PacketHandlerContext(
string text,
ChatContext chat,
ConnectionInfo connection
) {
public C2SPacketHandlerContext(string text, ChatContext chat, ConnectionInfo connection) {
Text = text;
Chat = chat;
Connection = connection;

View file

@ -0,0 +1,6 @@
namespace SharpChat.PacketsC2S {
public interface IC2SPacketHandler {
bool IsMatch(C2SPacketHandlerContext ctx);
void Handle(C2SPacketHandlerContext ctx);
}
}

View file

@ -1,33 +1,33 @@
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketsS2C;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SharpChat.PacketHandlers {
public class PingHandler : IPacketHandler {
namespace SharpChat.PacketsC2S {
public class PingC2SPacketHandler : IC2SPacketHandler {
private readonly MisuzuClient Misuzu;
private readonly TimeSpan BumpInterval = TimeSpan.FromMinutes(1);
private DateTimeOffset LastBump = DateTimeOffset.MinValue;
public PingHandler(MisuzuClient msz) {
public PingC2SPacketHandler(MisuzuClient msz) {
Misuzu = msz;
}
public bool IsMatch(PacketHandlerContext ctx) {
public bool IsMatch(C2SPacketHandlerContext ctx) {
return ctx.CheckPacketId("0");
}
public void Handle(PacketHandlerContext ctx) {
public void Handle(C2SPacketHandlerContext ctx) {
string[] parts = ctx.SplitText(2);
if(!int.TryParse(parts.FirstOrDefault(), out int pTime))
return;
ctx.Connection.BumpPing();
ctx.Connection.Send(new PongPacket());
ctx.Connection.Send(new PongS2CPacket());
ctx.Chat.ContextAccess.Wait();
try {

View file

@ -1,32 +1,33 @@
using SharpChat.Config;
using SharpChat.Commands;
using SharpChat.Config;
using SharpChat.Events;
using System;
using System.Collections.Generic;
using System.Linq;
namespace SharpChat.PacketHandlers {
public class SendMessageHandler : IPacketHandler {
namespace SharpChat.PacketsC2S {
public class SendMessageC2SPacketHandler : IC2SPacketHandler {
private readonly CachedValue<int> MaxMessageLength;
private List<IUserCommand> Commands { get; } = new();
private List<ISockChatClientCommand> Commands { get; } = new();
public SendMessageHandler(CachedValue<int> maxMsgLength) {
public SendMessageC2SPacketHandler(CachedValue<int> maxMsgLength) {
MaxMessageLength = maxMsgLength;
}
public void AddCommand(IUserCommand command) {
public void AddCommand(ISockChatClientCommand command) {
Commands.Add(command);
}
public void AddCommands(IEnumerable<IUserCommand> commands) {
public void AddCommands(IEnumerable<ISockChatClientCommand> commands) {
Commands.AddRange(commands);
}
public bool IsMatch(PacketHandlerContext ctx) {
public bool IsMatch(C2SPacketHandlerContext ctx) {
return ctx.CheckPacketId("2");
}
public void Handle(PacketHandlerContext ctx) {
public void Handle(C2SPacketHandlerContext ctx) {
string[] args = ctx.SplitText(3);
UserInfo? user = ctx.Chat.Users.Get(ctx.Connection.UserId);
@ -63,11 +64,11 @@ namespace SharpChat.PacketHandlers {
#endif
if(messageText.StartsWith("/")) {
UserCommandContext context = new(messageText, ctx.Chat, user, ctx.Connection, channelInfo);
SockChatClientCommandContext context = new(messageText, ctx.Chat, user, ctx.Connection, channelInfo);
IUserCommand? command = null;
ISockChatClientCommand? command = null;
foreach(IUserCommand cmd in Commands)
foreach(ISockChatClientCommand cmd in Commands)
if(cmd.IsMatch(context)) {
command = cmd;
break;

View file

@ -1,7 +1,7 @@
using System;
namespace SharpChat.Packet {
public class AuthFailPacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class AuthFailS2CPacket : SockChatS2CPacket {
public enum FailReason {
AuthInvalid,
MaxSessions,
@ -12,11 +12,11 @@ namespace SharpChat.Packet {
private readonly FailReason Reason;
private readonly long Expires;
public AuthFailPacket(FailReason reason) {
public AuthFailS2CPacket(FailReason reason) {
Reason = reason;
}
public AuthFailPacket(DateTimeOffset expires) {
public AuthFailS2CPacket(DateTimeOffset expires) {
Reason = FailReason.Banned;
Expires = expires.Year >= 2100 ? -1 : expires.ToUnixTimeSeconds();
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class AuthSuccessPacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class AuthSuccessS2CPacket : SockChatS2CPacket {
private readonly long UserId;
private readonly string UserName;
private readonly Colour UserColour;
@ -8,7 +8,7 @@
private readonly string ChannelName;
private readonly int MaxMessageLength;
public AuthSuccessPacket(
public AuthSuccessS2CPacket(
long userId,
string userName,
Colour userColour,

View file

@ -1,10 +1,10 @@
using System.Text;
namespace SharpChat.Packet {
public class BanListResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class BanListResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string[] Bans;
public BanListResponsePacket(string[] bans) {
public BanListResponseS2CPacket(string[] bans) {
Bans = bans;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelCreateResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelCreateResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelCreateResponsePacket(string channelName) {
public ChannelCreateResponseS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,10 +1,10 @@
namespace SharpChat.Packet {
public class ChannelCreatePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelCreateS2CPacket : SockChatS2CPacket {
private readonly string ChannelName;
private readonly bool ChannelHasPassword;
private readonly bool ChannelIsTemporary;
public ChannelCreatePacket(
public ChannelCreateS2CPacket(
string channelName,
bool channelHasPassword,
bool channelIsTemporary

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelDeleteNotAllowedErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelDeleteNotAllowedErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelDeleteNotAllowedErrorPacket(string channelName) {
public ChannelDeleteNotAllowedErrorS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelDeleteResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelDeleteResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelDeleteResponsePacket(string channelName) {
public ChannelDeleteResponseS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelDeletePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelDeleteS2CPacket : SockChatS2CPacket {
private readonly string ChannelName;
public ChannelDeletePacket(string channelName) {
public ChannelDeleteS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class ChannelNameFormatErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelNameFormatErrorS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t1\finchan\t{1}\t10010",

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelNameInUseErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelNameInUseErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelNameInUseErrorPacket(string channelName) {
public ChannelNameInUseErrorS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelNotFoundErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelNotFoundErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelNotFoundErrorPacket(string channelName) {
public ChannelNotFoundErrorS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class ChannelPasswordChangedResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelPasswordChangedResponseS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t0\fcpwdchan\t{1}\t10010",

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelPasswordWrongErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelPasswordWrongErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelPasswordWrongErrorPacket(string channelName) {
public ChannelPasswordWrongErrorS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class ChannelRankChangedResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelRankChangedResponseS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t0\fcprivchan\t{1}\t10010",

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class ChannelRankTooHighErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelRankTooHighErrorS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t1\frankerr\t{1}\t10010",

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class ChannelRankTooLowErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelRankTooLowErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public ChannelRankTooLowErrorPacket(string channelName) {
public ChannelRankTooLowErrorS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,11 +1,11 @@
namespace SharpChat.Packet {
public class ChannelUpdatePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelUpdateS2CPacket : SockChatS2CPacket {
private readonly string ChannelNamePrevious;
private readonly string ChannelNameNew;
private readonly bool ChannelHasPassword;
private readonly bool ChannelIsTemporary;
public ChannelUpdatePacket(
public ChannelUpdateS2CPacket(
string channelNamePrevious,
string channelNameNew,
bool channelHasPassword,

View file

@ -1,12 +1,12 @@
using System.Text;
namespace SharpChat.Packet {
public class ChannelsPopulatePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class ChannelsPopulateS2CPacket : SockChatS2CPacket {
public record ListEntry(string Name, bool HasPassword, bool IsTemporary);
private readonly ListEntry[] Entries;
public ChannelsPopulatePacket(ListEntry[] entries) {
public ChannelsPopulateS2CPacket(ListEntry[] entries) {
Entries = entries;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class CommandFormatErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class CommandFormatErrorS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t1\fcmdna\t{1}\t10010",

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class CommandNotAllowedErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class CommandNotAllowedErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string CommandName;
public CommandNotAllowedErrorPacket(string commandName) {
public CommandNotAllowedErrorS2CPacket(string commandName) {
CommandName = commandName;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class ContextClearPacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class ContextClearS2CPacket : SockChatS2CPacket {
public enum ClearMode {
Messages = 0,
Users = 1,
@ -10,7 +10,7 @@
private readonly ClearMode Mode;
public ContextClearPacket(ClearMode mode) {
public ContextClearS2CPacket(ClearMode mode) {
Mode = mode;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class FloodWarningPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class FloodWarningS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t0\fflwarn\t{1}\t10010",

View file

@ -1,12 +1,12 @@
using System;
namespace SharpChat.Packet {
public class ForceDisconnectPacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class ForceDisconnectS2CPacket : SockChatS2CPacket {
private readonly long Expires;
public ForceDisconnectPacket() {}
public ForceDisconnectS2CPacket() { }
public ForceDisconnectPacket(DateTimeOffset expires) {
public ForceDisconnectS2CPacket(DateTimeOffset expires) {
Expires = expires.Year >= 2100 ? -1 : expires.ToUnixTimeSeconds();
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class KickBanNoRecordErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class KickBanNoRecordErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string TargetName;
public KickBanNoRecordErrorPacket(string targetName) {
public KickBanNoRecordErrorS2CPacket(string targetName) {
TargetName = targetName;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class KickBanNotAllowedErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class KickBanNotAllowedErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
public KickBanNotAllowedErrorPacket(string userName) {
public KickBanNotAllowedErrorS2CPacket(string userName) {
UserName = userName;
}

View file

@ -1,10 +1,10 @@
using System;
namespace SharpChat.Packet {
public class MOTDPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class MOTDS2CPacket : SockChatTimedS2CPacket {
private readonly string Body;
public MOTDPacket(DateTimeOffset timeStamp, string body) : base(timeStamp) {
public MOTDS2CPacket(DateTimeOffset timeStamp, string body) : base(timeStamp) {
Body = body;
}

View file

@ -1,7 +1,7 @@
using System;
namespace SharpChat.Packet {
public class MessageAddLogPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class MessageAddLogS2CPacket : SockChatTimedS2CPacket {
private readonly long UserId;
private readonly string UserName;
private readonly Colour UserColour;
@ -13,7 +13,7 @@ namespace SharpChat.Packet {
private readonly bool IsBroadcast; // this should be MessageBroadcastLogPacket
private readonly bool Notify;
public MessageAddLogPacket(
public MessageAddLogS2CPacket(
long messageId,
DateTimeOffset timeStamp,
long userId,

View file

@ -1,13 +1,13 @@
using System;
namespace SharpChat.Packet {
public class MessageAddPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class MessageAddS2CPacket : SockChatTimedS2CPacket {
private readonly long UserId;
private readonly string Body;
private readonly bool IsAction;
private readonly bool IsPrivate;
public MessageAddPacket(
public MessageAddS2CPacket(
long messageId,
DateTimeOffset timeStamp,
long userId,

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class MessageBroadcastPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class MessageBroadcastS2CPacket : SockChatTimedS2CPacket {
private readonly string Body;
public MessageBroadcastPacket(string body) {
public MessageBroadcastS2CPacket(string body) {
Body = body;
}

View file

@ -1,5 +1,5 @@
namespace SharpChat.Packet {
public class MessageDeleteNotAllowedErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class MessageDeleteNotAllowedErrorS2CPacket : SockChatTimedS2CPacket {
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t1\fdelerr\t{1}\t10010",

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class MessageDeletePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class MessageDeleteS2CPacket : SockChatS2CPacket {
private readonly long DeletedMessageId;
public MessageDeletePacket(long deletedMessageId) {
public MessageDeleteS2CPacket(long deletedMessageId) {
DeletedMessageId = deletedMessageId;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class PardonResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class PardonResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string Subject;
public PardonResponsePacket(string subject) {
public PardonResponseS2CPacket(string subject) {
Subject = subject;
}

View file

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

View file

@ -1,4 +1,4 @@
namespace SharpChat {
namespace SharpChat.PacketsS2C {
public abstract class SockChatS2CPacket {
protected readonly long MessageId;

View file

@ -1,6 +1,6 @@
using System;
namespace SharpChat {
namespace SharpChat.PacketsS2C {
public abstract class SockChatTimedS2CPacket : SockChatS2CPacket {
protected readonly DateTimeOffset TimeStamp;

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class UserChannelForceJoinPacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserChannelForceJoinS2CPacket : SockChatS2CPacket {
private readonly string ChannelName;
public UserChannelForceJoinPacket(string channelName) {
public UserChannelForceJoinS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,10 +1,10 @@
using System;
namespace SharpChat.Packet {
public class UserChannelJoinLogPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserChannelJoinLogS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
public UserChannelJoinLogPacket(
public UserChannelJoinLogS2CPacket(
long messageId,
DateTimeOffset timeStamp,
string userName

View file

@ -1,12 +1,12 @@
namespace SharpChat.Packet {
public class UserChannelJoinPacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserChannelJoinS2CPacket : SockChatS2CPacket {
private readonly long UserId;
private readonly string UserName;
private readonly Colour UserColour;
private readonly int UserRank;
private readonly UserPermissions UserPerms;
public UserChannelJoinPacket(
public UserChannelJoinS2CPacket(
long userId,
string userName,
Colour userColour,

View file

@ -1,10 +1,10 @@
using System;
namespace SharpChat.Packet {
public class UserChannelLeaveLogPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserChannelLeaveLogS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
public UserChannelLeaveLogPacket(
public UserChannelLeaveLogS2CPacket(
long messageId,
DateTimeOffset timeStamp,
string userName

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class UserChannelLeavePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserChannelLeaveS2CPacket : SockChatS2CPacket {
private readonly long UserId;
public UserChannelLeavePacket(long userId) {
public UserChannelLeaveS2CPacket(long userId) {
UserId = userId;
}

View file

@ -1,10 +1,10 @@
using System;
namespace SharpChat.Packet {
public class UserConnectLogPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserConnectLogS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
public UserConnectLogPacket(
public UserConnectLogS2CPacket(
long messageId,
DateTimeOffset timeStamp,
string userName

View file

@ -1,12 +1,12 @@
namespace SharpChat.Packet {
public class UserConnectPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserConnectS2CPacket : SockChatTimedS2CPacket {
private readonly long UserId;
private readonly string UserName;
private readonly Colour UserColour;
private readonly int UserRank;
private readonly UserPermissions UserPerms;
public UserConnectPacket(
public UserConnectS2CPacket(
long userId,
string userName,
Colour userColour,

View file

@ -1,11 +1,11 @@
using System;
namespace SharpChat.Packet {
public class UserDisconnectLogPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserDisconnectLogS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
private readonly UserDisconnectReason Reason;
public UserDisconnectLogPacket(
public UserDisconnectLogS2CPacket(
long messageId,
DateTimeOffset timeStamp,
string userName,

View file

@ -1,10 +1,10 @@
namespace SharpChat.Packet {
public class UserDisconnectPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserDisconnectS2CPacket : SockChatTimedS2CPacket {
private readonly long UserId;
private readonly string UserName;
private readonly UserDisconnectReason Reason;
public UserDisconnectPacket(
public UserDisconnectS2CPacket(
long userId,
string userName,
UserDisconnectReason reason

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class UserNameInUseErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserNameInUseErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
public UserNameInUseErrorPacket(string userName) {
public UserNameInUseErrorS2CPacket(string userName) {
UserName = userName;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class UserNotFoundErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserNotFoundErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
public UserNotFoundErrorPacket(string userName) {
public UserNotFoundErrorS2CPacket(string userName) {
UserName = userName;
}

View file

@ -1,9 +1,9 @@
namespace SharpChat.Packet {
public class UserUpdateNotificationPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserUpdateNotificationS2CPacket : SockChatTimedS2CPacket {
private readonly string PreviousName;
private readonly string NewName;
public UserUpdateNotificationPacket(string previousName, string newName) {
public UserUpdateNotificationS2CPacket(string previousName, string newName) {
PreviousName = previousName;
NewName = newName;
}

View file

@ -1,12 +1,12 @@
namespace SharpChat.Packet {
public class UserUpdatePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class UserUpdateS2CPacket : SockChatS2CPacket {
private readonly long UserId;
private readonly string UserName;
private readonly Colour UserColour;
private readonly int UserRank;
private readonly UserPermissions UserPerms;
public UserUpdatePacket(
public UserUpdateS2CPacket(
long userId,
string userName,
Colour userColour,

View file

@ -1,12 +1,12 @@
using System.Text;
namespace SharpChat.Packet {
public class UsersPopulatePacket : SockChatS2CPacket {
namespace SharpChat.PacketsS2C {
public class UsersPopulateS2CPacket : SockChatS2CPacket {
public record ListEntry(long Id, string Name, Colour Colour, int Rank, UserPermissions Perms, bool Visible);
private readonly ListEntry[] Entries;
public UsersPopulatePacket(ListEntry[] entries) {
public UsersPopulateS2CPacket(ListEntry[] entries) {
Entries = entries;
}

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet {
public class WhoChannelNotFoundErrorPacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class WhoChannelNotFoundErrorS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
public WhoChannelNotFoundErrorPacket(string channelName) {
public WhoChannelNotFoundErrorS2CPacket(string channelName) {
ChannelName = channelName;
}

View file

@ -1,13 +1,13 @@
using System;
using System.Text;
namespace SharpChat.Packet {
public class WhoChannelResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class WhoChannelResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string ChannelName;
private readonly string[] Users;
private readonly string SelfName;
public WhoChannelResponsePacket(string channelName, string[] users, string selfName) {
public WhoChannelResponseS2CPacket(string channelName, string[] users, string selfName) {
ChannelName = channelName;
Users = users;
SelfName = selfName;

View file

@ -1,12 +1,12 @@
using System;
using System.Text;
namespace SharpChat.Packet {
public class WhoServerResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class WhoServerResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string[] Users;
private readonly string SelfName;
public WhoServerResponsePacket(string[] users, string selfName) {
public WhoServerResponseS2CPacket(string[] users, string selfName) {
Users = users;
SelfName = selfName;
}

View file

@ -1,9 +1,9 @@
namespace SharpChat.Packet {
public class WhoisResponsePacket : SockChatTimedS2CPacket {
namespace SharpChat.PacketsS2C {
public class WhoisResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string UserName;
private readonly string RemoteAddress;
public WhoisResponsePacket(string userName, string remoteAddress) {
public WhoisResponseS2CPacket(string userName, string remoteAddress) {
UserName = userName;
RemoteAddress = remoteAddress;
}

View file

@ -17,7 +17,8 @@ namespace SharpChat {
Console.WriteLine(@" \__ \/ __ \/ __ `/ ___/ __ \/ / / __ \/ __ `/ __/");
Console.WriteLine(@" ___/ / / / / /_/ / / / /_/ / /___/ / / / /_/ / /_ ");
Console.WriteLine(@"/____/_/ /_/\__,_/_/ / .___/\____/_/ /_/\__,_/\__/ ");
/**/Console.Write(@" /__/");
/**/
Console.Write(@" /__/");
if(BuildInfo.IsDebugBuild) {
Console.WriteLine();
Console.Write(@"== ");
@ -37,7 +38,8 @@ namespace SharpChat {
};
Console.CancelKeyPress += cancelKeyPressHandler;
if(hasCancelled) return;
if(hasCancelled)
return;
string configFile = CONFIG;
@ -47,18 +49,21 @@ namespace SharpChat {
using IConfig config = new StreamConfig(configFile);
if(hasCancelled) return;
if(hasCancelled)
return;
using HttpClient httpClient = new(new HttpClientHandler() {
UseProxy = false,
});
httpClient.DefaultRequestHeaders.Add("User-Agent", BuildInfo.ProgramName);
if(hasCancelled) return;
if(hasCancelled)
return;
MisuzuClient msz = new(httpClient, config.ScopeTo("msz"));
if(hasCancelled) return;
if(hasCancelled)
return;
IEventStorage evtStore;
if(string.IsNullOrWhiteSpace(config.SafeReadValue("mariadb:host", string.Empty))) {
@ -69,7 +74,8 @@ namespace SharpChat {
mdbes.RunMigrations();
}
if(hasCancelled) return;
if(hasCancelled)
return;
using SockChatServer scs = new(httpClient, msz, evtStore, config.ScopeTo("chat"));
scs.Listen(mre);

View file

@ -117,7 +117,8 @@ namespace SharpChat {
}
private void OnClientConnect(ISocket clientSocket) {
if(clientSocket == null) return; // socket closed
if(clientSocket == null)
return; // socket closed
FleckLog.Debug(string.Format("Client connected from {0}:{1}", clientSocket.RemoteIpAddress, clientSocket.RemotePort.ToString()));
ListenForClients();

View file

@ -3,8 +3,8 @@ using SharpChat.Commands;
using SharpChat.Config;
using SharpChat.EventStorage;
using SharpChat.Misuzu;
using SharpChat.Packet;
using SharpChat.PacketHandlers;
using SharpChat.PacketsS2C;
using SharpChat.PacketsC2S;
using System;
using System.Collections.Generic;
using System.Linq;
@ -28,9 +28,9 @@ namespace SharpChat {
private readonly CachedValue<int> MaxConnections;
private readonly CachedValue<int> FloodKickLength;
private readonly List<IPacketHandler> GuestHandlers = new();
private readonly List<IPacketHandler> AuthedHandlers = new();
private readonly SendMessageHandler SendMessageHandler;
private readonly List<IC2SPacketHandler> GuestHandlers = new();
private readonly List<IC2SPacketHandler> AuthedHandlers = new();
private readonly SendMessageC2SPacketHandler SendMessageHandler;
private bool IsShuttingDown = false;
private bool IsRestarting = false;
@ -70,7 +70,7 @@ namespace SharpChat {
if(Context.Channels.PublicCount < 1)
Context.Channels.Add(new ChannelInfo("Default"));
GuestHandlers.Add(new AuthHandler(
GuestHandlers.Add(new AuthC2SPacketHandler(
started,
Misuzu,
Context.Channels.MainChannel,
@ -78,12 +78,12 @@ namespace SharpChat {
MaxConnections
));
AuthedHandlers.AddRange(new IPacketHandler[] {
new PingHandler(Misuzu),
SendMessageHandler = new SendMessageHandler(MaxMessageLength),
AuthedHandlers.AddRange(new IC2SPacketHandler[] {
new PingC2SPacketHandler(Misuzu),
SendMessageHandler = new SendMessageC2SPacketHandler(MaxMessageLength),
});
SendMessageHandler.AddCommands(new IUserCommand[] {
SendMessageHandler.AddCommands(new ISockChatClientCommand[] {
new UserAFKCommand(),
new UserNickCommand(),
new MessageWhisperCommand(),
@ -197,7 +197,7 @@ namespace SharpChat {
UserInfo? userInfo = Context.Users.Get(banUserId);
if(userInfo != null) {
if(banDuration == TimeSpan.MinValue) {
Context.SendTo(userInfo, new FloodWarningPacket());
Context.SendTo(userInfo, new FloodWarningS2CPacket());
} else {
Context.BanUser(userInfo, banDuration, UserDisconnectReason.Flood);
@ -218,8 +218,8 @@ namespace SharpChat {
}
}
PacketHandlerContext context = new(msg, Context, conn);
IPacketHandler? handler = conn.UserId > 0
C2SPacketHandlerContext context = new(msg, Context, conn);
IC2SPacketHandler? handler = conn.UserId > 0
? AuthedHandlers.FirstOrDefault(h => h.IsMatch(context))
: GuestHandlers.FirstOrDefault(h => h.IsMatch(context));

View file

@ -3,24 +3,24 @@
namespace SharpChat {
[Flags]
public enum UserPermissions : int {
KickUser = 0x00000001,
BanUser = 0x00000002,
KickUser = 0x00000001,
BanUser = 0x00000002,
//SilenceUser = 0x00000004,
Broadcast = 0x00000008,
SetOwnNickname = 0x00000010,
SetOthersNickname = 0x00000020,
CreateChannel = 0x00000040,
DeleteChannel = 0x00010000,
Broadcast = 0x00000008,
SetOwnNickname = 0x00000010,
SetOthersNickname = 0x00000020,
CreateChannel = 0x00000040,
DeleteChannel = 0x00010000,
SetChannelPermanent = 0x00000080,
SetChannelPassword = 0x00000100,
SetChannelPassword = 0x00000100,
SetChannelHierarchy = 0x00000200,
JoinAnyChannel = 0x00020000,
SendMessage = 0x00000400,
DeleteOwnMessage = 0x00000800,
DeleteAnyMessage = 0x00001000,
EditOwnMessage = 0x00002000,
EditAnyMessage = 0x00004000,
SeeIPAddress = 0x00008000,
ViewLogs = 0x00040000,
JoinAnyChannel = 0x00020000,
SendMessage = 0x00000400,
DeleteOwnMessage = 0x00000800,
DeleteAnyMessage = 0x00001000,
EditOwnMessage = 0x00002000,
EditAnyMessage = 0x00004000,
SeeIPAddress = 0x00008000,
ViewLogs = 0x00040000,
}
}