Removed external pack methods.

These do need to be reimploded at some point probably, but this at least gets them out of common code.
This commit is contained in:
flash 2025-04-25 21:22:25 +00:00
parent 3fc94c425e
commit 9f283e48fe
Signed by: flash
GPG key ID: 2C9C2C574D47FE3E
13 changed files with 200 additions and 103 deletions

View file

@ -1,8 +1,4 @@
using System;
using System.Linq;
using System.Text;
namespace SharpChat {
namespace SharpChat {
public class ChatChannel(
string name,
string password = "",
@ -19,18 +15,6 @@ namespace SharpChat {
public bool HasPassword
=> !string.IsNullOrWhiteSpace(Password);
public string Pack() {
StringBuilder sb = new();
sb.Append(Name);
sb.Append('\t');
sb.Append(string.IsNullOrEmpty(Password) ? '0' : '1');
sb.Append('\t');
sb.Append(IsTemporary ? '1' : '0');
return sb.ToString();
}
public bool NameEquals(string name) {
return string.Equals(name, Name, StringComparison.InvariantCultureIgnoreCase);
}

View file

@ -187,7 +187,7 @@ namespace SharpChat {
if(!string.IsNullOrWhiteSpace(previousName))
SendToUserChannels(user, new CommandResponseS2CPacket(RandomSnowflake.Next(), LCR.NICKNAME_CHANGE, false, previousName, user.LegacyNameWithStatus));
SendToUserChannels(user, new UserUpdateS2CPacket(user));
SendToUserChannels(user, new UserUpdateS2CPacket(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
}
}
@ -209,17 +209,38 @@ namespace SharpChat {
public void HandleJoin(ChatUser user, ChatChannel chan, ChatConnection conn, int maxMsgLength) {
if(!IsInChannel(user, chan)) {
long msgId = RandomSnowflake.Next();
SendTo(chan, new UserConnectS2CPacket(msgId, DateTimeOffset.Now, user));
SendTo(chan, new UserConnectS2CPacket(msgId, DateTimeOffset.Now, user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
Events.AddEvent(msgId, "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
}
conn.Send(new AuthSuccessS2CPacket(user, chan, maxMsgLength));
conn.Send(new ContextUsersS2CPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)));
conn.Send(new AuthSuccessS2CPacket(
user.UserId,
user.LegacyNameWithStatus,
user.Colour,
user.Rank,
user.Permissions,
chan.Name,
maxMsgLength
));
conn.Send(new ContextUsersS2CPacket(
GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)
.Select(u => new ContextUsersS2CPacket.Entry(
u.UserId,
u.LegacyNameWithStatus,
u.Colour,
u.Rank,
u.Permissions,
true
))
));
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
conn.Send(new ContextMessageS2CPacket(msg));
conn.Send(new ContextChannelsS2CPacket(Channels.Where(c => c.Rank <= user.Rank)));
conn.Send(new ContextChannelsS2CPacket(
Channels.Where(c => c.Rank <= user.Rank)
.Select(c => new ContextChannelsS2CPacket.Entry(c.Name, c.HasPassword, c.IsTemporary))
));
Users.Add(user);
@ -280,11 +301,21 @@ namespace SharpChat {
Events.AddEvent(leaveId, "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
long joinId = RandomSnowflake.Next();
SendTo(chan, new UserChannelJoinS2CPacket(joinId, user));
Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
SendTo(chan, new UserChannelJoinS2CPacket(joinId, user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.LegacyName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
SendTo(user, new ContextClearS2CPacket(ContextClearMode.MessagesUsers));
SendTo(user, new ContextUsersS2CPacket(GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)));
SendTo(user, new ContextUsersS2CPacket(
GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)
.Select(u => new ContextUsersS2CPacket.Entry(
u.UserId,
u.LegacyNameWithStatus,
u.Colour,
u.Rank,
u.Permissions,
true
))
));
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
SendTo(user, new ContextMessageS2CPacket(msg));
@ -364,9 +395,8 @@ namespace SharpChat {
channel.Password = password;
// TODO: Users that no longer have access to the channel/gained access to the channel by the hierarchy change should receive delete and create packets respectively
foreach(ChatUser user in Users.Where(u => u.Rank >= channel.Rank)) {
SendTo(user, new ChannelUpdateS2CPacket(channel.Name, channel));
}
foreach(ChatUser user in Users.Where(u => u.Rank >= channel.Rank))
SendTo(user, new ChannelUpdateS2CPacket(channel.Name, channel.Name, channel.HasPassword, channel.IsTemporary));
}
public void RemoveChannel(ChatChannel channel) {

View file

@ -53,30 +53,6 @@ namespace SharpChat {
return strict ? perms == perm : perms > 0;
}
public string Pack() {
StringBuilder sb = new();
sb.Append(UserId);
sb.Append('\t');
sb.Append(LegacyNameWithStatus);
sb.Append('\t');
sb.Append(Colour);
sb.Append('\t');
sb.Append(Rank);
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(Can(ChatUserPermissions.CreateChannel | ChatUserPermissions.SetChannelPermanent, true) ? '2' : (
Can(ChatUserPermissions.CreateChannel) ? '1' : '0'
));
return sb.ToString();
}
public bool NameEquals(string name) {
return string.Equals(name, UserName, StringComparison.InvariantCultureIgnoreCase)
|| string.Equals(name, NickName, StringComparison.InvariantCultureIgnoreCase)

View file

@ -53,7 +53,7 @@ namespace SharpChat.Commands {
ctx.Chat.Channels.Add(createChan);
foreach(ChatUser ccu in ctx.Chat.Users.Where(u => u.Rank >= ctx.Channel.Rank))
ctx.Chat.SendTo(ccu, new ChannelCreateS2CPacket(ctx.Channel));
ctx.Chat.SendTo(ccu, new ChannelCreateS2CPacket(createChan.Name, createChan.HasPassword, createChan.IsTemporary));
ctx.Chat.SwitchChannel(ctx.User, createChan, createChan.Password);
ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.CHANNEL_CREATED, false, createChan.Name));

View file

@ -2,21 +2,35 @@
namespace SharpChat.S2CPackets {
public class AuthSuccessS2CPacket(
ChatUser user,
ChatChannel channel,
long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms,
string channelName,
int maxMsgLength
) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
public string Pack() {
StringBuilder sb = new();
sb.Append('1');
sb.Append("\ty\t");
sb.Append(User.Pack());
sb.Append("1\ty\t");
sb.Append(userId);
sb.Append('\t');
sb.Append(Channel.Name);
sb.Append(userName);
sb.Append('\t');
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
sb.Append(channelName);
sb.Append('\t');
sb.Append(maxMsgLength);

View file

@ -1,17 +1,20 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class ChannelCreateS2CPacket(ChatChannel channel) : S2CPacket {
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
public class ChannelCreateS2CPacket(
string name,
bool hasPassword,
bool isTemporary
) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('4');
sb.Append("4\t0\t");
sb.Append(name);
sb.Append('\t');
sb.Append('0');
sb.Append(hasPassword ? '1' : '0');
sb.Append('\t');
sb.Append(Channel.Pack());
sb.Append(isTemporary ? '1' : '0');
return sb.ToString();
}

View file

@ -1,10 +1,12 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class ChannelUpdateS2CPacket(string previousName, ChatChannel channel) : S2CPacket {
public string PreviousName { get; private set; } = previousName ?? throw new ArgumentNullException(nameof(previousName));
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
public class ChannelUpdateS2CPacket(
string previousName,
string newName,
bool hasPassword,
bool isTemporary
) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
@ -12,9 +14,13 @@ namespace SharpChat.S2CPackets {
sb.Append('\t');
sb.Append('1');
sb.Append('\t');
sb.Append(PreviousName);
sb.Append(previousName);
sb.Append('\t');
sb.Append(Channel.Pack());
sb.Append(newName);
sb.Append('\t');
sb.Append(hasPassword ? '1' : '0');
sb.Append('\t');
sb.Append(isTemporary ? '1' : '0');
return sb.ToString();
}

View file

@ -1,8 +1,8 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class ContextChannelsS2CPacket(IEnumerable<ChatChannel> channels) : S2CPacket {
public IEnumerable<ChatChannel> Channels { get; private set; } = channels?.Where(c => c != null) ?? throw new ArgumentNullException(nameof(channels));
public class ContextChannelsS2CPacket(IEnumerable<ContextChannelsS2CPacket.Entry> entries) : S2CPacket {
public record Entry(string name, bool hasPassword, bool isTemporary);
public string Pack() {
StringBuilder sb = new();
@ -11,11 +11,15 @@ namespace SharpChat.S2CPackets {
sb.Append('\t');
sb.Append('2');
sb.Append('\t');
sb.Append(Channels.Count());
sb.Append(entries.Count());
foreach(ChatChannel channel in Channels) {
foreach(Entry entry in entries) {
sb.Append('\t');
sb.Append(channel.Pack());
sb.Append(entry.name);
sb.Append('\t');
sb.Append(entry.hasPassword ? '1' : '0');
sb.Append('\t');
sb.Append(entry.isTemporary ? '1' : '0');
}
return sb.ToString();

View file

@ -29,7 +29,21 @@ namespace SharpChat.S2CPackets
sb.Append(V1_CHATBOT);
sb.Append("0\fsay\f");
} else {
sb.Append(Event.Sender.Pack());
sb.Append(Event.Sender.UserId);
sb.Append('\t');
sb.Append(Event.Sender.LegacyNameWithStatus);
sb.Append('\t');
sb.Append(Event.Sender.Colour);
sb.Append('\t');
sb.Append(Event.Sender.Rank);
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(Event.Sender.Permissions.HasFlag(ChatUserPermissions.CreateChannel) ? (Event.Sender.Permissions.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
}

View file

@ -1,8 +1,8 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class ContextUsersS2CPacket(IEnumerable<ChatUser> users) : S2CPacket {
public IEnumerable<ChatUser> Users { get; private set; } = users?.Where(u => u != null) ?? throw new ArgumentNullException(nameof(users));
public class ContextUsersS2CPacket(IEnumerable<ContextUsersS2CPacket.Entry> entries) : S2CPacket {
public record Entry(long id, string name, ChatColour colour, int rank, ChatUserPermissions perms, bool visible);
public string Pack() {
StringBuilder sb = new();
@ -11,13 +11,27 @@ namespace SharpChat.S2CPackets {
sb.Append('\t');
sb.Append('0');
sb.Append('\t');
sb.Append(Users.Count());
sb.Append(entries.Count());
foreach(ChatUser user in Users) {
foreach(Entry entry in entries) {
sb.Append('\t');
sb.Append(user.Pack());
sb.Append(entry.id);
sb.Append('\t');
sb.Append('1'); // visibility flag
sb.Append(entry.name);
sb.Append('\t');
sb.Append(entry.colour);
sb.Append('\t');
sb.Append(entry.rank);
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(entry.perms.HasFlag(ChatUserPermissions.CreateChannel) ? (entry.perms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
sb.Append(entry.visible ? '1' : '0');
}
return sb.ToString();

View file

@ -1,17 +1,33 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class UserChannelJoinS2CPacket(long msgId, ChatUser user) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public class UserChannelJoinS2CPacket(
long msgId,
long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms
) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('5');
sb.Append("5\t0\t");
sb.Append(userId);
sb.Append('\t');
sb.Append('0');
sb.Append(userName);
sb.Append('\t');
sb.Append(User.Pack());
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
sb.Append(msgId);

View file

@ -1,17 +1,36 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class UserConnectS2CPacket(long msgId, DateTimeOffset joined, ChatUser user) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public class UserConnectS2CPacket(
long msgId,
DateTimeOffset joined,
long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms
) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('1');
sb.Append('\t');
sb.Append("1\t");
sb.Append(joined.ToUnixTimeSeconds());
sb.Append('\t');
sb.Append(User.Pack());
sb.Append(userId);
sb.Append('\t');
sb.Append(userName);
sb.Append('\t');
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
sb.Append('\t');
sb.Append(msgId);

View file

@ -1,15 +1,32 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class UserUpdateS2CPacket(ChatUser user) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public class UserUpdateS2CPacket(
long userId,
string userName,
ChatColour userColour,
int userRank,
ChatUserPermissions userPerms
) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append("10");
sb.Append("10\t");
sb.Append(userId);
sb.Append('\t');
sb.Append(User.Pack());
sb.Append(userName);
sb.Append('\t');
sb.Append(userColour);
sb.Append('\t');
sb.Append(userRank);
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.KickUser) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.ViewLogs) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.SetOwnNickname) ? '1' : '0');
sb.Append(' ');
sb.Append(userPerms.HasFlag(ChatUserPermissions.CreateChannel) ? (userPerms.HasFlag(ChatUserPermissions.SetChannelPermanent) ? '2' : '1') : '0');
return sb.ToString();
}