Split some packets out of LegacyCommandResponse.

This commit is contained in:
flash 2024-05-13 20:55:54 +00:00
parent 8cc00fe1a8
commit 907711e753
12 changed files with 104 additions and 71 deletions

View file

@ -28,7 +28,7 @@ namespace SharpChat {
public void DispatchEvent(IChatEvent eventInfo) {
if(eventInfo is MessageCreateEvent mce) {
if(mce.IsBroadcast) {
Send(new LegacyCommandResponse(LCR.BROADCAST, false, mce.MessageText));
Send(new BroadcastPacket(mce.MessageText));
} else if(mce.IsPrivate) {
// The channel name returned by GetDMChannelName should not be exposed to the user, instead @<Target User> should be displayed
// e.g. nook sees @Arysil and Arysil sees @nook
@ -311,7 +311,7 @@ namespace SharpChat {
SendTo(chan, new UserChannelJoinPacket(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
Events.AddEvent("chan:join", user, oldChan, flags: StoredEventFlags.Log);
SendTo(user, new ContextClearPacket(ContextClearMode.MessagesUsers));
SendTo(user, new ContextClearPacket(ContextClearPacket.ClearMode.MessagesUsers));
SendTo(user, new ContextUsersPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
user => new ContextUsersPacket.ListEntry(user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions, true)
).OrderByDescending(u => u.Rank).ToArray()));

View file

@ -1,35 +1,35 @@
using System;
namespace SharpChat.Packet {
public enum AuthFailReason {
AuthInvalid,
MaxSessions,
Banned,
Null,
}
public class AuthFailPacket : ServerPacket {
private readonly AuthFailReason Reason;
public enum FailReason {
AuthInvalid,
MaxSessions,
Banned,
Null,
}
private readonly FailReason Reason;
private readonly DateTimeOffset Expires;
public AuthFailPacket(AuthFailReason reason) {
public AuthFailPacket(FailReason reason) {
Reason = reason;
}
public AuthFailPacket(DateTimeOffset expires) {
Reason = AuthFailReason.Banned;
Reason = FailReason.Banned;
Expires = expires;
}
public override string Pack() {
string packet = string.Format("1\tn\t{0}fail", Reason switch {
AuthFailReason.AuthInvalid => "auth",
AuthFailReason.MaxSessions => "sock",
AuthFailReason.Banned => "join",
FailReason.AuthInvalid => "auth",
FailReason.MaxSessions => "sock",
FailReason.Banned => "join",
_ => "user",
});
if(Reason == AuthFailReason.Banned)
if(Reason == FailReason.Banned)
packet += string.Format("\t{0}", Expires.Year >= 2100 ? -1 : Expires.ToUnixTimeSeconds());
return packet;

View file

@ -0,0 +1,22 @@
using System;
namespace SharpChat.Packet {
public class BroadcastPacket : ServerPacket {
private readonly long Timestamp;
private readonly string Body;
public BroadcastPacket(string body) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Body = body;
}
public override string Pack() {
return string.Format(
"2\t{0}\t-1\t0\fsay\f{1}\t{2}\t10010",
Timestamp,
SharpUtil.Sanitise(Body),
SequenceId
);
}
}
}

View file

@ -24,7 +24,7 @@ namespace SharpChat.Packet {
}
public override string Pack() {
string body = Body.Replace("<", "&lt;").Replace(">", "&gt;").Replace("\n", " <br/> ").Replace("\t", " ");
string body = SharpUtil.Sanitise(Body);
if(IsAction)
body = string.Format("<i>{0}</i>", body);

View file

@ -1,13 +1,13 @@
namespace SharpChat.Packet {
public class ChatMessageDeletePacket : ServerPacket {
private readonly long EventId;
private readonly long MessageId;
public ChatMessageDeletePacket(long eventId) {
EventId = eventId;
public ChatMessageDeletePacket(long msgId) {
MessageId = msgId;
}
public override string Pack() {
return string.Format("6\t{0}", EventId);
return string.Format("6\t{0}", MessageId);
}
}
}

View file

@ -1,16 +1,16 @@
namespace SharpChat.Packet {
public enum ContextClearMode {
Messages = 0,
Users = 1,
Channels = 2,
MessagesUsers = 3,
MessagesUsersChannels = 4,
}
public class ContextClearPacket : ServerPacket {
private readonly ContextClearMode Mode;
public enum ClearMode {
Messages = 0,
Users = 1,
Channels = 2,
MessagesUsers = 3,
MessagesUsersChannels = 4,
}
public ContextClearPacket(ContextClearMode mode) {
private readonly ClearMode Mode;
public ContextClearPacket(ClearMode mode) {
Mode = mode;
}

View file

@ -49,7 +49,7 @@ namespace SharpChat.Packet {
if(isBroadcast)
sb.Append("0\fsay\f");
string body = Event.Data.RootElement.GetProperty("text").GetString()?.Replace("<", "&lt;").Replace(">", "&gt;").Replace("\n", " <br/> ").Replace("\t", " ") ?? string.Empty;
string body = SharpUtil.Sanitise(Event.Data.RootElement.GetProperty("text").GetString());
if(isAction)
body = string.Format("<i>{0}</i>", body);

View file

@ -20,34 +20,17 @@ namespace SharpChat.Packet {
public override string Pack() {
StringBuilder sb = new();
if(StringId == LCR.WELCOME)
sb.AppendFormat(
"7\t1\t{0}\t-1\tChatBot\tinherit\t\t",
DateTimeOffset.Now.ToUnixTimeSeconds()
);
else
sb.AppendFormat(
"2\t{0}\t-1\t",
DateTimeOffset.Now.ToUnixTimeSeconds()
);
sb.AppendFormat(
"{0}\f{1}",
"2\t{0}\t-1\t{1}\f{2}",
DateTimeOffset.Now.ToUnixTimeSeconds(),
IsError ? 1 : 0,
StringId == LCR.WELCOME ? LCR.BROADCAST : StringId
StringId
);
foreach(object arg in Arguments)
sb.AppendFormat("\f{0}", arg);
sb.Append('\t');
if(StringId == LCR.WELCOME)
sb.AppendFormat("{0}\t0", StringId);
else
sb.Append(SequenceId);
sb.Append("\t10010");
sb.AppendFormat("\t{0}\t10010", SequenceId);
return sb.ToString();
}
@ -55,12 +38,8 @@ namespace SharpChat.Packet {
// Abbreviated class name because otherwise shit gets wide
public static class LCR {
public const string GENERIC_ERROR = "generr";
public const string COMMAND_NOT_FOUND = "nocmd";
public const string COMMAND_NOT_ALLOWED = "cmdna";
public const string COMMAND_FORMAT_ERROR = "cmderr";
public const string WELCOME = "welcome";
public const string BROADCAST = "say";
public const string IP_ADDRESS = "ipaddr";
public const string USER_NOT_FOUND = "usernf";
public const string NAME_IN_USE = "nameinuse";

View file

@ -0,0 +1,20 @@
using System;
namespace SharpChat.Packet {
public class MOTDPacket : ServerPacket {
private readonly long Timestamp;
private readonly string Body;
public MOTDPacket(string body) {
Timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
Body = body;
}
public override string Pack() {
return string.Format(
"7\t1\t{0}\t-1\tChatBot\tinherit\t\t0\fsay\f{1}\twelcome\t0\t10010",
Timestamp, SharpUtil.Sanitise(Body)
);
}
}
}

View file

@ -35,14 +35,14 @@ namespace SharpChat.PacketHandlers {
string? authMethod = args.ElementAtOrDefault(1);
if(string.IsNullOrWhiteSpace(authMethod)) {
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose();
return;
}
string? authToken = args.ElementAtOrDefault(2);
if(string.IsNullOrWhiteSpace(authToken)) {
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose();
return;
}
@ -61,7 +61,7 @@ namespace SharpChat.PacketHandlers {
fai = await Misuzu.AuthVerifyAsync(authMethod, authToken, ipAddr);
} catch(Exception ex) {
Logger.Write($"<{ctx.Connection.Id}> Failed to authenticate: {ex}");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose();
#if DEBUG
throw;
@ -72,14 +72,14 @@ namespace SharpChat.PacketHandlers {
if(fai == null) {
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: <null>");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Null));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null));
ctx.Connection.Dispose();
return;
}
if(!fai.Success) {
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: {fai.Reason}");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose();
return;
}
@ -89,7 +89,7 @@ namespace SharpChat.PacketHandlers {
fbi = await Misuzu.CheckBanAsync(fai.UserId.ToString(), ipAddr);
} catch(Exception ex) {
Logger.Write($"<{ctx.Connection.Id}> Failed auth ban check: {ex}");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.AuthInvalid));
ctx.Connection.Dispose();
#if DEBUG
throw;
@ -100,7 +100,7 @@ namespace SharpChat.PacketHandlers {
if(fbi == null) {
Logger.Debug($"<{ctx.Connection.Id}> Ban check fail: <null>");
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.Null));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.Null));
ctx.Connection.Dispose();
return;
}
@ -137,21 +137,21 @@ namespace SharpChat.PacketHandlers {
// Enforce a maximum amount of connections per user
if(ctx.Chat.Connections.Count(conn => conn.User == user) >= MaxConnections) {
ctx.Connection.Send(new AuthFailPacket(AuthFailReason.MaxSessions));
ctx.Connection.Send(new AuthFailPacket(AuthFailPacket.FailReason.MaxSessions));
ctx.Connection.Dispose();
return;
}
ctx.Connection.BumpPing();
ctx.Connection.User = user;
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, $"Welcome to Flashii Chat, {user.UserName}!"));
ctx.Connection.Send(new MOTDPacket($"Welcome to Flashii Chat, {user.UserName}!"));
if(File.Exists("welcome.txt")) {
IEnumerable<string> lines = File.ReadAllLines("welcome.txt").Where(x => !string.IsNullOrWhiteSpace(x));
string? line = lines.ElementAtOrDefault(RNG.Next(lines.Count()));
if(!string.IsNullOrWhiteSpace(line))
ctx.Connection.Send(new LegacyCommandResponse(LCR.WELCOME, false, line));
ctx.Connection.Send(new MOTDPacket(line));
}
ctx.Chat.HandleJoin(user, DefaultChannel, ctx.Connection, MaxMessageLength);

View file

@ -6,9 +6,11 @@ namespace SharpChat {
private const long EPOCH = 1588377600000;
private static int Counter = 0;
public static long Next()
=> ((DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH) << 8)
| (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF);
public static long Next() {
long num = DateTimeOffset.Now.ToUnixTimeMilliseconds() - EPOCH;
num <<= 8;
num |= (ushort)(Interlocked.Increment(ref Counter) & 0xFFFF);
return num;
}
}
}

10
SharpChat/SharpUtil.cs Normal file
View file

@ -0,0 +1,10 @@
namespace SharpChat {
public static class SharpUtil {
public static string Sanitise(string? body) {
if(string.IsNullOrEmpty(body))
return string.Empty;
return body.Replace("<", "&lt;").Replace(">", "&gt;").Replace("\n", " <br/> ").Replace("\t", " ");
}
}
}