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.Events;
using SharpChat.EventStorage; using SharpChat.EventStorage;
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -24,7 +24,7 @@ namespace SharpChat {
public void DispatchEvent(IChatEvent eventInfo) { public void DispatchEvent(IChatEvent eventInfo) {
if(eventInfo is MessageCreateEvent mce) { if(eventInfo is MessageCreateEvent mce) {
if(mce.IsBroadcast) { if(mce.IsBroadcast) {
Send(new MessageBroadcastPacket(mce.MessageText)); Send(new MessageBroadcastS2CPacket(mce.MessageText));
} else if(mce.IsPrivate) { } else if(mce.IsPrivate) {
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed // 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 // e.g. nook sees @Arysil and Arysil sees @nook
@ -43,7 +43,7 @@ namespace SharpChat {
return; return;
foreach(UserInfo user in users) foreach(UserInfo user in users)
SendTo(user, new MessageAddPacket( SendTo(user, new MessageAddS2CPacket(
mce.MessageId, mce.MessageId,
DateTimeOffset.Now, DateTimeOffset.Now,
mce.SenderId, mce.SenderId,
@ -54,7 +54,7 @@ namespace SharpChat {
} else { } else {
ChannelInfo? channel = Channels.Get(mce.ChannelName, SockChatUtility.SanitiseChannelName); ChannelInfo? channel = Channels.Get(mce.ChannelName, SockChatUtility.SanitiseChannelName);
if(channel != null) if(channel != null)
SendTo(channel, new MessageAddPacket( SendTo(channel, new MessageAddS2CPacket(
mce.MessageId, mce.MessageId,
DateTimeOffset.Now, DateTimeOffset.Now,
mce.SenderId, mce.SenderId,
@ -170,9 +170,9 @@ namespace SharpChat {
if(hasChanged) { if(hasChanged) {
if(previousName != null) 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, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
user.Colour, user.Colour,
@ -185,9 +185,9 @@ namespace SharpChat {
public void BanUser(UserInfo user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) { public void BanUser(UserInfo user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
if(duration > TimeSpan.Zero) { if(duration > TimeSpan.Zero) {
DateTimeOffset expires = duration >= TimeSpan.MaxValue ? DateTimeOffset.MaxValue : DateTimeOffset.Now + duration; DateTimeOffset expires = duration >= TimeSpan.MaxValue ? DateTimeOffset.MaxValue : DateTimeOffset.Now + duration;
SendTo(user, new ForceDisconnectPacket(expires)); SendTo(user, new ForceDisconnectS2CPacket(expires));
} else } else
SendTo(user, new ForceDisconnectPacket()); SendTo(user, new ForceDisconnectS2CPacket());
ConnectionInfo[] conns = Connections.GetUser(user); ConnectionInfo[] conns = Connections.GetUser(user);
foreach(ConnectionInfo conn in conns) { foreach(ConnectionInfo conn in conns) {
@ -203,7 +203,7 @@ namespace SharpChat {
public void HandleChannelEventLog(string channelName, Action<SockChatS2CPacket> handler) { public void HandleChannelEventLog(string channelName, Action<SockChatS2CPacket> handler) {
foreach(StoredEventInfo msg in Events.GetChannelEventLog(channelName)) foreach(StoredEventInfo msg in Events.GetChannelEventLog(channelName))
handler(msg.Type switch { handler(msg.Type switch {
"msg:add" => new MessageAddLogPacket( "msg:add" => new MessageAddLogS2CPacket(
msg.Id, msg.Id,
msg.Created, msg.Created,
msg.Sender?.UserId ?? -1, msg.Sender?.UserId ?? -1,
@ -217,23 +217,23 @@ namespace SharpChat {
msg.Flags.HasFlag(StoredEventFlags.Broadcast), msg.Flags.HasFlag(StoredEventFlags.Broadcast),
false false
), ),
"user:connect" => new UserConnectLogPacket( "user:connect" => new UserConnectLogS2CPacket(
msg.Id, msg.Id,
msg.Created, msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender) msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
), ),
"user:disconnect" => new UserDisconnectLogPacket( "user:disconnect" => new UserDisconnectLogS2CPacket(
msg.Id, msg.Id,
msg.Created, msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserNameWithStatus(msg.Sender), msg.Sender == null ? string.Empty : SockChatUtility.GetUserNameWithStatus(msg.Sender),
(UserDisconnectReason)msg.Data.RootElement.GetProperty("reason").GetByte() (UserDisconnectReason)msg.Data.RootElement.GetProperty("reason").GetByte()
), ),
"chan:join" => new UserChannelJoinLogPacket( "chan:join" => new UserChannelJoinLogS2CPacket(
msg.Id, msg.Id,
msg.Created, msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender) msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
), ),
"chan:leave" => new UserChannelLeaveLogPacket( "chan:leave" => new UserChannelLeaveLogS2CPacket(
msg.Id, msg.Id,
msg.Created, msg.Created,
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender) 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) { public void HandleJoin(UserInfo user, ChannelInfo chan, ConnectionInfo conn, int maxMsgLength) {
if(!ChannelsUsers.Has(chan, user)) { if(!ChannelsUsers.Has(chan, user)) {
SendTo(chan, new UserConnectPacket( SendTo(chan, new UserConnectS2CPacket(
user.UserId, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
user.Colour, user.Colour,
@ -254,7 +254,7 @@ namespace SharpChat {
Events.AddEvent("user:connect", user, chan, flags: StoredEventFlags.Log); Events.AddEvent("user:connect", user, chan, flags: StoredEventFlags.Log);
} }
conn.Send(new AuthSuccessPacket( conn.Send(new AuthSuccessS2CPacket(
user.UserId, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
user.Colour, user.Colour,
@ -263,8 +263,8 @@ namespace SharpChat {
chan.Name, chan.Name,
maxMsgLength maxMsgLength
)); ));
conn.Send(new UsersPopulatePacket(GetChannelUsers(chan).Except(new[] { user }).Select( conn.Send(new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulatePacket.ListEntry( user => new UsersPopulateS2CPacket.ListEntry(
user.UserId, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
user.Colour, user.Colour,
@ -276,8 +276,8 @@ namespace SharpChat {
HandleChannelEventLog(chan.Name, p => conn.Send(p)); HandleChannelEventLog(chan.Name, p => conn.Send(p));
conn.Send(new ChannelsPopulatePacket(Channels.GetMany(isPublic: true, minRank: user.Rank).Select( conn.Send(new ChannelsPopulateS2CPacket(Channels.GetMany(isPublic: true, minRank: user.Rank).Select(
channel => new ChannelsPopulatePacket.ListEntry(channel.Name, channel.HasPassword, channel.IsTemporary) channel => new ChannelsPopulateS2CPacket.ListEntry(channel.Name, channel.HasPassword, channel.IsTemporary)
).ToArray())); ).ToArray()));
if(Users.Get(userId: user.UserId) == null) if(Users.Get(userId: user.UserId) == null)
@ -294,7 +294,7 @@ namespace SharpChat {
ChannelsUsers.DeleteUser(user); ChannelsUsers.DeleteUser(user);
foreach(ChannelInfo chan in channels) { foreach(ChannelInfo chan in channels) {
SendTo(chan, new UserDisconnectPacket( SendTo(chan, new UserDisconnectS2CPacket(
user.UserId, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
reason reason
@ -314,13 +314,13 @@ namespace SharpChat {
if(!user.Permissions.HasFlag(UserPermissions.JoinAnyChannel) && chan.IsOwner(user)) { if(!user.Permissions.HasFlag(UserPermissions.JoinAnyChannel) && chan.IsOwner(user)) {
if(chan.Rank > user.Rank) { if(chan.Rank > user.Rank) {
SendTo(user, new ChannelRankTooLowErrorPacket(chan.Name)); SendTo(user, new ChannelRankTooLowErrorS2CPacket(chan.Name));
ForceChannel(user); ForceChannel(user);
return; return;
} }
if(!string.IsNullOrEmpty(chan.Password) && chan.Password.Equals(password)) { if(!string.IsNullOrEmpty(chan.Password) && chan.Password.Equals(password)) {
SendTo(user, new ChannelPasswordWrongErrorPacket(chan.Name)); SendTo(user, new ChannelPasswordWrongErrorS2CPacket(chan.Name));
ForceChannel(user); ForceChannel(user);
return; return;
} }
@ -333,11 +333,11 @@ namespace SharpChat {
ChannelInfo? oldChan = Channels.Get(ChannelsUsers.GetUserLastChannel(user)); ChannelInfo? oldChan = Channels.Get(ChannelsUsers.GetUserLastChannel(user));
if(oldChan != null) { if(oldChan != null) {
SendTo(oldChan, new UserChannelLeavePacket(user.UserId)); SendTo(oldChan, new UserChannelLeaveS2CPacket(user.UserId));
Events.AddEvent("chan:leave", user, oldChan, flags: StoredEventFlags.Log); Events.AddEvent("chan:leave", user, oldChan, flags: StoredEventFlags.Log);
} }
SendTo(chan, new UserChannelJoinPacket( SendTo(chan, new UserChannelJoinS2CPacket(
user.UserId, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
user.Colour, user.Colour,
@ -348,9 +348,9 @@ namespace SharpChat {
if(oldChan != null) if(oldChan != null)
Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log); Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log);
SendTo(user, new ContextClearPacket(ContextClearPacket.ClearMode.MessagesUsers)); SendTo(user, new ContextClearS2CPacket(ContextClearS2CPacket.ClearMode.MessagesUsers));
SendTo(user, new UsersPopulatePacket(GetChannelUsers(chan).Except(new[] { user }).Select( SendTo(user, new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new UsersPopulatePacket.ListEntry( user => new UsersPopulateS2CPacket.ListEntry(
user.UserId, user.UserId,
SockChatUtility.GetUserNameWithStatus(user), SockChatUtility.GetUserNameWithStatus(user),
user.Colour, user.Colour,
@ -401,7 +401,7 @@ namespace SharpChat {
public void ForceChannel(UserInfo user, ChannelInfo? chan = null) { public void ForceChannel(UserInfo user, ChannelInfo? chan = null) {
chan ??= Channels.Get(ChannelsUsers.GetUserLastChannel(user)); chan ??= Channels.Get(ChannelsUsers.GetUserLastChannel(user));
if(chan != null) if(chan != null)
SendTo(user, new UserChannelForceJoinPacket(chan.Name)); SendTo(user, new UserChannelForceJoinS2CPacket(chan.Name));
} }
public void UpdateChannel( 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 // 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. // 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)) 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) { public void RemoveChannel(ChannelInfo channel) {
@ -445,7 +445,7 @@ namespace SharpChat {
// Broadcast deletion of channel // Broadcast deletion of channel
foreach(UserInfo user in Users.GetMany(minRank: channel.Rank)) 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.Misuzu;
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class BanListCommand : IUserCommand { public class BanListCommand : ISockChatClientCommand {
private readonly MisuzuClient Misuzu; private readonly MisuzuClient Misuzu;
public BanListCommand(MisuzuClient msz) { public BanListCommand(MisuzuClient msz) {
Misuzu = msz; Misuzu = msz;
} }
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("bans") return ctx.NameEquals("bans")
|| ctx.NameEquals("banned"); || ctx.NameEquals("banned");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.KickUser) if(!ctx.User.Permissions.HasFlag(UserPermissions.KickUser)
&& !ctx.User.Permissions.HasFlag(UserPermissions.BanUser)) { && !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; return;
} }
Task.Run(async () => { Task.Run(async () => {
ctx.Chat.SendTo(ctx.User, new BanListResponsePacket( ctx.Chat.SendTo(ctx.User, new BanListResponseS2CPacket(
(await Misuzu.GetBanListAsync() ?? Array.Empty<MisuzuBanInfo>()).Select( (await Misuzu.GetBanListAsync() ?? Array.Empty<MisuzuBanInfo>()).Select(
ban => string.IsNullOrEmpty(ban.UserName) ? (string.IsNullOrEmpty(ban.RemoteAddress) ? string.Empty : ban.RemoteAddress) : ban.UserName ban => string.IsNullOrEmpty(ban.UserName) ? (string.IsNullOrEmpty(ban.RemoteAddress) ? string.Empty : ban.RemoteAddress) : ban.UserName
).ToArray() ).ToArray()

View file

@ -1,15 +1,15 @@
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System.Linq; using System.Linq;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class ChannelCreateCommand : IUserCommand { public class ChannelCreateCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("create"); return ctx.NameEquals("create");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.CreateChannel)) { 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; return;
} }
@ -17,7 +17,7 @@ namespace SharpChat.Commands {
bool createChanHasHierarchy; bool createChanHasHierarchy;
if(!ctx.Args.Any() || (createChanHasHierarchy = firstArg.All(char.IsDigit) && ctx.Args.Length < 2)) { 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; return;
} }
@ -27,19 +27,19 @@ namespace SharpChat.Commands {
createChanHierarchy = 0; createChanHierarchy = 0;
if(createChanHierarchy > ctx.User.Rank) { if(createChanHierarchy > ctx.User.Rank) {
ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorPacket()); ctx.Chat.SendTo(ctx.User, new ChannelRankTooHighErrorS2CPacket());
return; return;
} }
string createChanName = string.Join('_', ctx.Args.Skip(createChanHasHierarchy ? 1 : 0)); string createChanName = string.Join('_', ctx.Args.Skip(createChanHasHierarchy ? 1 : 0));
if(!SockChatUtility.CheckChannelName(createChanName)) { if(!SockChatUtility.CheckChannelName(createChanName)) {
ctx.Chat.SendTo(ctx.User, new ChannelNameFormatErrorPacket()); ctx.Chat.SendTo(ctx.User, new ChannelNameFormatErrorS2CPacket());
return; return;
} }
if(ctx.Chat.Channels.Get(createChanName, SockChatUtility.SanitiseChannelName) != null) { 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; return;
} }
@ -52,14 +52,14 @@ namespace SharpChat.Commands {
ctx.Chat.Channels.Add(createChan, sanitiseName: SockChatUtility.SanitiseChannelName); ctx.Chat.Channels.Add(createChan, sanitiseName: SockChatUtility.SanitiseChannelName);
foreach(UserInfo ccu in ctx.Chat.Users.GetMany(minRank: ctx.Channel.Rank)) 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.Name,
ctx.Channel.HasPassword, ctx.Channel.HasPassword,
ctx.Channel.IsTemporary ctx.Channel.IsTemporary
)); ));
ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password); 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; using System.Linq;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class ChannelDeleteCommand : IUserCommand { public class ChannelDeleteCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("delchan") || ( return ctx.NameEquals("delchan") || (
ctx.NameEquals("delete") ctx.NameEquals("delete")
&& ctx.Args.FirstOrDefault()?.All(char.IsDigit) == false && 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())) { if(!ctx.Args.Any() || string.IsNullOrWhiteSpace(ctx.Args.FirstOrDefault())) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket()); ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return; return;
} }
@ -20,17 +20,17 @@ namespace SharpChat.Commands {
ChannelInfo? delChan = ctx.Chat.Channels.Get(delChanName, SockChatUtility.SanitiseChannelName); ChannelInfo? delChan = ctx.Chat.Channels.Get(delChanName, SockChatUtility.SanitiseChannelName);
if(delChan == null) { if(delChan == null) {
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(delChanName)); ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorS2CPacket(delChanName));
return; return;
} }
if(!ctx.User.Permissions.HasFlag(UserPermissions.DeleteChannel) || !delChan.IsOwner(ctx.User)) { 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; return;
} }
ctx.Chat.RemoveChannel(delChan); 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; using System.Linq;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class ChannelJoinCommand : IUserCommand { public class ChannelJoinCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("join"); return ctx.NameEquals("join");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
string joinChanStr = ctx.Args.FirstOrDefault() ?? string.Empty; string joinChanStr = ctx.Args.FirstOrDefault() ?? string.Empty;
ChannelInfo? joinChan = ctx.Chat.Channels.Get(joinChanStr, SockChatUtility.SanitiseChannelName); ChannelInfo? joinChan = ctx.Chat.Channels.Get(joinChanStr, SockChatUtility.SanitiseChannelName);
if(joinChan == null) { if(joinChan == null) {
ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorPacket(joinChanStr)); ctx.Chat.SendTo(ctx.User, new ChannelNotFoundErrorS2CPacket(joinChanStr));
ctx.Chat.ForceChannel(ctx.User); ctx.Chat.ForceChannel(ctx.User);
return; return;
} }

View file

@ -1,15 +1,15 @@
using SharpChat.Packet; using SharpChat.PacketsS2C;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class ChannelPasswordCommand : IUserCommand { public class ChannelPasswordCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("pwd") return ctx.NameEquals("pwd")
|| ctx.NameEquals("password"); || 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)) { 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; return;
} }
@ -19,7 +19,7 @@ namespace SharpChat.Commands {
chanPass = string.Empty; chanPass = string.Empty;
ctx.Chat.UpdateChannel(ctx.Channel, password: chanPass); 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; using System.Linq;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class ChannelRankCommand : IUserCommand { public class ChannelRankCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("rank") return ctx.NameEquals("rank")
|| ctx.NameEquals("privilege") || ctx.NameEquals("privilege")
|| ctx.NameEquals("priv"); || 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)) { 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; return;
} }
if(!ctx.Args.Any() || !int.TryParse(ctx.Args.First(), out int chanHierarchy) || chanHierarchy > ctx.User.Rank) { 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; return;
} }
ctx.Chat.UpdateChannel(ctx.Channel, minRank: chanHierarchy); 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.Misuzu;
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class KickBanCommand : IUserCommand { public class KickBanCommand : ISockChatClientCommand {
private readonly MisuzuClient Misuzu; private readonly MisuzuClient Misuzu;
public KickBanCommand(MisuzuClient msz) { public KickBanCommand(MisuzuClient msz) {
Misuzu = msz; Misuzu = msz;
} }
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("kick") return ctx.NameEquals("kick")
|| ctx.NameEquals("ban"); || ctx.NameEquals("ban");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
bool isBanning = ctx.NameEquals("ban"); bool isBanning = ctx.NameEquals("ban");
if(!ctx.User.Permissions.HasFlag(isBanning ? UserPermissions.BanUser : UserPermissions.KickUser)) { 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; return;
} }
@ -32,19 +32,19 @@ namespace SharpChat.Commands {
(string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(banUserTarget); (string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(banUserTarget);
if(string.IsNullOrEmpty(name) || (banUser = ctx.Chat.Users.Get(name: name, nameTarget: target)) == null) { 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; return;
} }
if(!ctx.User.IsSuper && banUser.Rank >= ctx.User.Rank && banUser != ctx.User) { 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; return;
} }
TimeSpan duration = isBanning ? TimeSpan.MaxValue : TimeSpan.Zero; TimeSpan duration = isBanning ? TimeSpan.MaxValue : TimeSpan.Zero;
if(!string.IsNullOrWhiteSpace(banDurationStr) && double.TryParse(banDurationStr, out double durationSeconds)) { if(!string.IsNullOrWhiteSpace(banDurationStr) && double.TryParse(banDurationStr, out double durationSeconds)) {
if(durationSeconds < 0) { if(durationSeconds < 0) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket()); ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return; return;
} }
@ -64,7 +64,7 @@ namespace SharpChat.Commands {
MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId); MisuzuBanInfo? fbi = await Misuzu.CheckBanAsync(userId);
if(fbi != null && fbi.IsBanned && !fbi.HasExpired) { 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; return;
} }

View file

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

View file

@ -1,17 +1,17 @@
using SharpChat.Events; using SharpChat.Events;
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System; using System;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class MessageBroadcastCommand : IUserCommand { public class MessageBroadcastCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("say") return ctx.NameEquals("say")
|| ctx.NameEquals("broadcast"); || ctx.NameEquals("broadcast");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.Broadcast)) { 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; return;
} }

View file

@ -1,41 +1,40 @@
using SharpChat.EventStorage; using SharpChat.EventStorage;
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System.Linq; using System.Linq;
namespace SharpChat.Commands namespace SharpChat.Commands {
{ public class MessageDeleteCommand : ISockChatClientCommand {
public class MessageDeleteCommand : IUserCommand { public bool IsMatch(SockChatClientCommandContext ctx) {
public bool IsMatch(UserCommandContext ctx) {
return ctx.NameEquals("delmsg") || ( return ctx.NameEquals("delmsg") || (
ctx.NameEquals("delete") ctx.NameEquals("delete")
&& ctx.Args.FirstOrDefault()?.All(char.IsDigit) == true && 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); bool deleteAnyMessage = ctx.User.Permissions.HasFlag(UserPermissions.DeleteAnyMessage);
if(!deleteAnyMessage && !ctx.User.Permissions.HasFlag(UserPermissions.DeleteOwnMessage)) { 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; return;
} }
string? firstArg = ctx.Args.FirstOrDefault(); string? firstArg = ctx.Args.FirstOrDefault();
if(string.IsNullOrWhiteSpace(firstArg) || !firstArg.All(char.IsDigit) || !long.TryParse(firstArg, out long delSeqId)) { 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; return;
} }
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId); StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
if(delMsg == null || delMsg.Sender?.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender?.UserId != ctx.User.UserId)) { if(delMsg == 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; return;
} }
ctx.Chat.Events.RemoveEvent(delMsg); 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.Events;
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System; using System;
using System.Linq; using System.Linq;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class MessageWhisperCommand : IUserCommand { public class MessageWhisperCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("whisper") return ctx.NameEquals("whisper")
|| ctx.NameEquals("msg"); || ctx.NameEquals("msg");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
if(ctx.Args.Length < 2) { if(ctx.Args.Length < 2) {
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorPacket()); ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
return; return;
} }
@ -21,7 +21,7 @@ namespace SharpChat.Commands {
UserInfo? whisperUser = ctx.Chat.Users.Get(name: name, nameTarget: target); UserInfo? whisperUser = ctx.Chat.Users.Get(name: name, nameTarget: target);
if(whisperUser == null) { if(whisperUser == null) {
ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorPacket(whisperUserStr)); ctx.Chat.SendTo(ctx.User, new UserNotFoundErrorS2CPacket(whisperUserStr));
return; return;
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,16 +1,16 @@
using SharpChat.Packet; using SharpChat.PacketsS2C;
using System.Linq; using System.Linq;
namespace SharpChat.Commands { namespace SharpChat.Commands {
public class WhoisCommand : IUserCommand { public class WhoisCommand : ISockChatClientCommand {
public bool IsMatch(UserCommandContext ctx) { public bool IsMatch(SockChatClientCommandContext ctx) {
return ctx.NameEquals("ip") return ctx.NameEquals("ip")
|| ctx.NameEquals("whois"); || ctx.NameEquals("whois");
} }
public void Dispatch(UserCommandContext ctx) { public void Dispatch(SockChatClientCommandContext ctx) {
if(!ctx.User.Permissions.HasFlag(UserPermissions.SeeIPAddress)) { 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; return;
} }
@ -19,12 +19,12 @@ namespace SharpChat.Commands {
(string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(ipUserStr); (string name, UsersContext.NameTarget target) = SockChatUtility.ExplodeUserName(ipUserStr);
if(string.IsNullOrWhiteSpace(name) || (ipUser = ctx.Chat.Users.Get(name: name, nameTarget: target)) == null) { 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; return;
} }
foreach(string remoteAddr in ctx.Chat.Connections.GetUserRemoteAddresses(ipUser)) 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 Fleck;
using SharpChat.PacketsS2C;
using System; using System;
using System.Net; using System.Net;

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,8 +1,8 @@
namespace SharpChat.Packet { namespace SharpChat.PacketsS2C {
public class PardonResponsePacket : SockChatTimedS2CPacket { public class PardonResponseS2CPacket : SockChatTimedS2CPacket {
private readonly string Subject; private readonly string Subject;
public PardonResponsePacket(string subject) { public PardonResponseS2CPacket(string subject) {
Subject = 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 { public abstract class SockChatS2CPacket {
protected readonly long MessageId; protected readonly long MessageId;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -117,7 +117,8 @@ namespace SharpChat {
} }
private void OnClientConnect(ISocket clientSocket) { 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())); FleckLog.Debug(string.Format("Client connected from {0}:{1}", clientSocket.RemoteIpAddress, clientSocket.RemotePort.ToString()));
ListenForClients(); ListenForClients();

View file

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

View file

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