Cleaned up S2C packet classes.

This commit is contained in:
flash 2025-04-25 22:14:48 +00:00
parent 9f283e48fe
commit b8ec381f3b
Signed by: flash
GPG key ID: 2C9C2C574D47FE3E
19 changed files with 130 additions and 203 deletions

View file

@ -23,14 +23,14 @@ namespace SharpChat.C2SPacketHandlers {
string? authMethod = args.ElementAtOrDefault(1);
if(string.IsNullOrWhiteSpace(authMethod)) {
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.AuthInvalid));
ctx.Connection.Dispose();
return;
}
string? authToken = args.ElementAtOrDefault(2);
if(string.IsNullOrWhiteSpace(authToken)) {
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.AuthInvalid));
ctx.Connection.Dispose();
return;
}
@ -49,7 +49,7 @@ namespace SharpChat.C2SPacketHandlers {
fai = await Misuzu.AuthVerifyAsync(authMethod, authToken, ipAddr);
} catch(Exception ex) {
Logger.Write($"<{ctx.Connection.Id}> Failed to authenticate: {ex}");
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.AuthInvalid));
ctx.Connection.Dispose();
#if DEBUG
throw;
@ -60,7 +60,7 @@ namespace SharpChat.C2SPacketHandlers {
if(fai?.Success != true) {
Logger.Debug($"<{ctx.Connection.Id}> Auth fail: {fai?.Reason ?? "unknown"}");
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.AuthInvalid));
ctx.Connection.Dispose();
return;
}
@ -70,7 +70,7 @@ namespace SharpChat.C2SPacketHandlers {
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 AuthFailS2CPacket(AuthFailReason.AuthInvalid));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.AuthInvalid));
ctx.Connection.Dispose();
#if DEBUG
throw;
@ -81,7 +81,7 @@ namespace SharpChat.C2SPacketHandlers {
if(fbi?.IsBanned == true && !fbi.HasExpired) {
Logger.Write($"<{ctx.Connection.Id}> User is banned.");
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailReason.Banned, fbi));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.Banned, fbi.IsPermanent ? DateTimeOffset.MaxValue : fbi.ExpiresAt));
ctx.Connection.Dispose();
return;
}
@ -109,7 +109,7 @@ namespace SharpChat.C2SPacketHandlers {
// Enforce a maximum amount of connections per user
if(ctx.Chat.Connections.Count(conn => conn.User == user) >= MaxConnections) {
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailReason.MaxSessions));
ctx.Connection.Send(new AuthFailS2CPacket(AuthFailS2CPacket.Reason.MaxSessions));
ctx.Connection.Dispose();
return;
}

View file

@ -93,7 +93,7 @@ namespace SharpChat {
foreach(ChatUser user in Users)
if(!Connections.Any(conn => conn.User == user)) {
HandleDisconnect(user, UserDisconnectReason.TimeOut);
HandleDisconnect(user, UserDisconnectS2CPacket.Reason.TimeOut);
Logger.Write($"Timed out {user} (no more connections).");
}
}
@ -191,12 +191,12 @@ namespace SharpChat {
}
}
public void BanUser(ChatUser user, TimeSpan duration, UserDisconnectReason reason = UserDisconnectReason.Kicked) {
public void BanUser(ChatUser user, TimeSpan duration, UserDisconnectS2CPacket.Reason reason = UserDisconnectS2CPacket.Reason.Kicked) {
if(duration > TimeSpan.Zero) {
DateTimeOffset expires = duration >= TimeSpan.MaxValue ? DateTimeOffset.MaxValue : DateTimeOffset.Now + duration;
SendTo(user, new ForceDisconnectS2CPacket(ForceDisconnectReason.Banned, expires));
SendTo(user, new ForceDisconnectS2CPacket(expires));
} else
SendTo(user, new ForceDisconnectS2CPacket(ForceDisconnectReason.Kicked));
SendTo(user, new ForceDisconnectS2CPacket());
foreach(ChatConnection conn in Connections)
if(conn.User == user)
@ -248,7 +248,7 @@ namespace SharpChat {
UserLastChannel[user.UserId] = chan;
}
public void HandleDisconnect(ChatUser user, UserDisconnectReason reason = UserDisconnectReason.Leave) {
public void HandleDisconnect(ChatUser user, UserDisconnectS2CPacket.Reason reason = UserDisconnectS2CPacket.Reason.Leave) {
UpdateUser(user, status: ChatUserStatus.Offline);
Users.Remove(user);
UserLastChannel.Remove(user.UserId);
@ -259,7 +259,7 @@ namespace SharpChat {
ChannelUsers.Remove(new ChannelUserAssoc(user.UserId, chan.Name));
long msgId = RandomSnowflake.Next();
SendTo(chan, new UserDisconnectS2CPacket(msgId, DateTimeOffset.Now, user, reason));
SendTo(chan, new UserDisconnectS2CPacket(msgId, DateTimeOffset.Now, user.UserId, user.LegacyNameWithStatus, reason));
Events.AddEvent(msgId, "user:disconnect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, new { reason = (int)reason }, StoredEventFlags.Log);
if(chan.IsTemporary && chan.IsOwner(user))
@ -297,14 +297,14 @@ namespace SharpChat {
ChatChannel oldChan = UserLastChannel[user.UserId];
long leaveId = RandomSnowflake.Next();
SendTo(oldChan, new UserChannelLeaveS2CPacket(leaveId, user));
SendTo(oldChan, new UserChannelLeaveS2CPacket(leaveId, user.UserId));
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.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 ContextClearS2CPacket(ContextClearS2CPacket.Mode.MessagesUsers));
SendTo(user, new ContextUsersS2CPacket(
GetChannelUsers(chan).Except([user]).OrderByDescending(u => u.Rank)
.Select(u => new ContextUsersS2CPacket.Entry(
@ -377,7 +377,7 @@ namespace SharpChat {
if(chan == null && !UserLastChannel.TryGetValue(user.UserId, out chan))
throw new ArgumentException("no channel???");
SendTo(user, new UserChannelForceJoinS2CPacket(chan));
SendTo(user, new UserChannelForceJoinS2CPacket(chan.Name));
}
public void UpdateChannel(ChatChannel channel, bool? temporary = null, int? hierarchy = null, string? password = null) {
@ -417,7 +417,7 @@ namespace SharpChat {
// Broadcast deletion of channel
foreach(ChatUser user in Users.Where(u => u.Rank >= channel.Rank))
SendTo(user, new ChannelDeleteS2CPacket(channel));
SendTo(user, new ChannelDeleteS2CPacket(channel.Name));
}
}
}

View file

@ -19,12 +19,18 @@ namespace SharpChat.Commands {
}
Task.Run(async () => {
MisuzuBanInfo[]? mbi = await Misuzu.GetBanListAsync();
if(mbi is null)
MisuzuBanInfo[]? mbis = await Misuzu.GetBanListAsync();
if(mbis is null)
ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.GENERIC_ERROR, true));
else
ctx.Chat.SendTo(ctx.User, new BanListS2CPacket(msgId, mbi));
ctx.Chat.SendTo(ctx.User, new BanListS2CPacket(
msgId,
mbis.Where(mbi => mbi.IsBanned && !mbi.HasExpired)
.Select(mbi => new BanListS2CPacket.Entry(
BanListS2CPacket.Type.UserName, // Misuzu currently only does username bans so we can just do this
mbi.UserName ?? $"({mbi.UserId})"
))
));
}).Wait();
}
}

View file

@ -1,52 +1,38 @@
using SharpChat.Misuzu;
using System.Text;
using System.Text;
namespace SharpChat.S2CPackets {
public enum AuthFailReason {
AuthInvalid,
MaxSessions,
Banned,
}
public class AuthFailS2CPacket : S2CPacket {
public AuthFailReason Reason { get; private set; }
public MisuzuBanInfo? BanInfo { get; private set; }
public AuthFailS2CPacket(AuthFailReason reason, MisuzuBanInfo? fbi = null) {
Reason = reason;
if(reason == AuthFailReason.Banned)
BanInfo = fbi ?? throw new ArgumentNullException(nameof(fbi));
public class AuthFailS2CPacket(
AuthFailS2CPacket.Reason reason,
DateTimeOffset? expiresAt = null
) : S2CPacket {
public enum Reason {
AuthInvalid,
MaxSessions,
Banned,
}
public string Pack() {
StringBuilder sb = new();
sb.Append('1');
sb.Append("\tn\t");
sb.Append("1\tn\t");
switch(Reason) {
case AuthFailReason.AuthInvalid:
switch(reason) {
case Reason.AuthInvalid:
default:
sb.Append("authfail");
break;
case AuthFailReason.MaxSessions:
case Reason.MaxSessions:
sb.Append("sockfail");
break;
case AuthFailReason.Banned:
sb.Append("joinfail");
case Reason.Banned:
sb.Append("joinfail\t");
if(expiresAt is null || expiresAt == DateTimeOffset.MaxValue)
sb.Append("-1");
else
sb.Append(expiresAt.Value.ToUnixTimeSeconds());
break;
}
if(Reason == AuthFailReason.Banned) {
sb.Append('\t');
if(BanInfo?.IsPermanent == true)
sb.Append("-1");
else
sb.Append(BanInfo?.ExpiresAt.ToUnixTimeSeconds() ?? 0);
}
return sb.ToString();
}
}

View file

@ -1,29 +1,28 @@
using SharpChat.Misuzu;
using System.Text;
using System.Text;
namespace SharpChat.S2CPackets {
public class BanListS2CPacket(
long msgId,
IEnumerable<MisuzuBanInfo> bans
IEnumerable<BanListS2CPacket.Entry> entries
) : S2CPacket {
public IEnumerable<MisuzuBanInfo> Bans { get; private set; } = bans ?? throw new ArgumentNullException(nameof(bans));
public enum Type {
UserName,
IPAddress,
}
public record Entry(Type type, string value);
public string Pack() {
StringBuilder sb = new();
sb.Append('2');
sb.Append('\t');
sb.Append("2\t");
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
sb.Append("\t-1\t0\fbanlist\f");
foreach(MisuzuBanInfo ban in Bans) {
string banStr = string.IsNullOrEmpty(ban.UserName) ? (ban.RemoteAddress ?? "::") : (ban.UserName ?? $"({ban.UserId})");
sb.AppendFormat(@"<a href=""javascript:void(0);"" onclick=""Chat.SendMessageWrapper('/unban '+ this.innerHTML);"">{0}</a>, ", banStr);
}
if(Bans.Any())
sb.Length -= 2;
sb.Append(string.Join(", ", entries.Select(entry => string.Format(
@"<a href=""javascript:void(0);"" onclick=""Chat.SendMessageWrapper('{0} '+ this.innerHTML);"">{1}</a>",
entry.type == Type.IPAddress ? "/unbanip" : "/unban",
entry.value
))));
sb.Append('\t');
sb.Append(msgId);
sb.Append("\t10010");

View file

@ -1,17 +1,14 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class ChannelDeleteS2CPacket(ChatChannel channel) : S2CPacket {
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
public class ChannelDeleteS2CPacket(
string channelName
) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('4');
sb.Append('\t');
sb.Append('2');
sb.Append('\t');
sb.Append(Channel.Name);
sb.Append("4\t2\t");
sb.Append(channelName);
return sb.ToString();
}

View file

@ -10,10 +10,7 @@ namespace SharpChat.S2CPackets {
public string Pack() {
StringBuilder sb = new();
sb.Append('4');
sb.Append('\t');
sb.Append('1');
sb.Append('\t');
sb.Append("4\t1\t");
sb.Append(previousName);
sb.Append('\t');
sb.Append(newName);

View file

@ -9,13 +9,10 @@ namespace SharpChat.S2CPackets {
bool isAction,
bool isPrivate
) : S2CPacket {
public string Text { get; } = text ?? throw new ArgumentNullException(nameof(text));
public string Pack() {
StringBuilder sb = new();
sb.Append('2');
sb.Append('\t');
sb.Append("2\t");
sb.Append(created.ToUnixTimeSeconds());
sb.Append('\t');
@ -27,7 +24,7 @@ namespace SharpChat.S2CPackets {
sb.Append("<i>");
sb.Append(
Text.Replace("<", "&lt;")
text.Replace("<", "&lt;")
.Replace(">", "&gt;")
.Replace("\n", " <br/> ")
.Replace("\t", " ")

View file

@ -5,8 +5,7 @@ namespace SharpChat.S2CPackets {
public string Pack() {
StringBuilder sb = new();
sb.Append('6');
sb.Append('\t');
sb.Append("6\t");
sb.Append(eventId);
return sb.ToString();

View file

@ -7,28 +7,22 @@ namespace SharpChat.S2CPackets {
bool isError = true,
params object[] args
) : S2CPacket {
public string StringId { get; private set; } = stringId ?? throw new ArgumentNullException(nameof(stringId));
public string Pack() {
StringBuilder sb = new();
if(StringId == LCR.WELCOME) {
sb.Append('7');
sb.Append('\t');
sb.Append('1');
sb.Append('\t');
if(stringId == LCR.WELCOME) {
sb.Append("7\t1\t");
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
sb.Append("\t-1\tChatBot\tinherit\t\t");
} else {
sb.Append('2');
sb.Append('\t');
sb.Append("2\t");
sb.Append(DateTimeOffset.Now.ToUnixTimeSeconds());
sb.Append("\t-1\t");
}
sb.Append(isError ? '1' : '0');
sb.Append('\f');
sb.Append(StringId == LCR.WELCOME ? LCR.BROADCAST : StringId);
sb.Append(stringId == LCR.WELCOME ? LCR.BROADCAST : stringId);
if(args.Length > 0)
foreach(object arg in args) {
@ -38,8 +32,8 @@ namespace SharpChat.S2CPackets {
sb.Append('\t');
if(StringId == LCR.WELCOME) {
sb.Append(StringId);
if(stringId == LCR.WELCOME) {
sb.Append(stringId);
sb.Append("\t0");
} else
sb.Append(msgId);

View file

@ -7,10 +7,7 @@ namespace SharpChat.S2CPackets {
public string Pack() {
StringBuilder sb = new();
sb.Append('7');
sb.Append('\t');
sb.Append('2');
sb.Append('\t');
sb.Append("7\t2\t");
sb.Append(entries.Count());
foreach(Entry entry in entries) {

View file

@ -1,20 +1,19 @@
using System.Text;
namespace SharpChat.S2CPackets {
public enum ContextClearMode {
Messages = 0,
Users = 1,
Channels = 2,
MessagesUsers = 3,
MessagesUsersChannels = 4,
}
public class ContextClearS2CPacket(ContextClearS2CPacket.Mode mode) : S2CPacket {
public enum Mode {
Messages = 0,
Users = 1,
Channels = 2,
MessagesUsers = 3,
MessagesUsersChannels = 4,
}
public class ContextClearS2CPacket(ContextClearMode mode) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('8');
sb.Append('\t');
sb.Append("8\t");
sb.Append((int)mode);
return sb.ToString();

View file

@ -6,8 +6,6 @@ namespace SharpChat.S2CPackets
public class ContextMessageS2CPacket(StoredEventInfo evt, bool notify = false) : S2CPacket {
public StoredEventInfo Event { get; private set; } = evt ?? throw new ArgumentNullException(nameof(evt));
private const string V1_CHATBOT = "-1\tChatBot\tinherit\t\t";
public string Pack() {
bool isAction = Event.Flags.HasFlag(StoredEventFlags.Action);
bool isBroadcast = Event.Flags.HasFlag(StoredEventFlags.Broadcast);
@ -15,10 +13,7 @@ namespace SharpChat.S2CPackets
StringBuilder sb = new();
sb.Append('7');
sb.Append('\t');
sb.Append('1');
sb.Append('\t');
sb.Append("7\t1\t");
sb.Append(Event.Created.ToUnixTimeSeconds());
sb.Append('\t');
@ -26,8 +21,7 @@ namespace SharpChat.S2CPackets
case "msg:add":
case "SharpChat.Events.ChatMessage":
if(isBroadcast || Event.Sender is null) {
sb.Append(V1_CHATBOT);
sb.Append("0\fsay\f");
sb.Append("-1\tChatBot\tinherit\t\t0\fsay\f");
} else {
sb.Append(Event.Sender.UserId);
sb.Append('\t');
@ -64,41 +58,37 @@ namespace SharpChat.S2CPackets
case "user:connect":
case "SharpChat.Events.UserConnectEvent":
sb.Append(V1_CHATBOT);
sb.Append("0\fjoin\f");
sb.Append("-1\tChatBot\tinherit\t\t0\fjoin\f");
sb.Append(Event.Sender?.LegacyName ?? "?????");
break;
case "chan:join":
case "SharpChat.Events.UserChannelJoinEvent":
sb.Append(V1_CHATBOT);
sb.Append("0\fjchan\f");
sb.Append("-1\tChatBot\tinherit\t\t0\fjchan\f");
sb.Append(Event.Sender?.LegacyName ?? "?????");
break;
case "chan:leave":
case "SharpChat.Events.UserChannelLeaveEvent":
sb.Append(V1_CHATBOT);
sb.Append("0\flchan\f");
sb.Append("-1\tChatBot\tinherit\t\t0\flchan\f");
sb.Append(Event.Sender?.LegacyName ?? "?????");
break;
case "user:disconnect":
case "SharpChat.Events.UserDisconnectEvent":
sb.Append(V1_CHATBOT);
sb.Append("0\f");
sb.Append("-1\tChatBot\tinherit\t\t0\f");
switch((UserDisconnectReason)Event.Data.RootElement.GetProperty("reason").GetByte()) {
case UserDisconnectReason.Flood:
switch((UserDisconnectS2CPacket.Reason)Event.Data.RootElement.GetProperty("reason").GetByte()) {
case UserDisconnectS2CPacket.Reason.Flood:
sb.Append("flood");
break;
case UserDisconnectReason.Kicked:
case UserDisconnectS2CPacket.Reason.Kicked:
sb.Append("kick");
break;
case UserDisconnectReason.TimeOut:
case UserDisconnectS2CPacket.Reason.TimeOut:
sb.Append("timeout");
break;
case UserDisconnectReason.Leave:
case UserDisconnectS2CPacket.Reason.Leave:
default:
sb.Append("leave");
break;

View file

@ -7,10 +7,7 @@ namespace SharpChat.S2CPackets {
public string Pack() {
StringBuilder sb = new();
sb.Append('7');
sb.Append('\t');
sb.Append('0');
sb.Append('\t');
sb.Append("7\t0\t");
sb.Append(entries.Count());
foreach(Entry entry in entries) {

View file

@ -1,40 +1,21 @@
using System.Text;
namespace SharpChat.S2CPackets {
public enum ForceDisconnectReason {
Kicked = 0,
Banned = 1,
}
public class ForceDisconnectS2CPacket : S2CPacket {
public ForceDisconnectReason Reason { get; private set; }
public DateTimeOffset Expires { get; private set; }
public ForceDisconnectS2CPacket(ForceDisconnectReason reason, DateTimeOffset? expires = null) {
Reason = reason;
if(reason == ForceDisconnectReason.Banned) {
if(!expires.HasValue)
throw new ArgumentNullException(nameof(expires));
Expires = expires.Value;
}
}
public class ForceDisconnectS2CPacket(DateTimeOffset? expires = null) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('9');
sb.Append('\t');
sb.Append((int)Reason);
sb.Append("9\t");
if(Reason == ForceDisconnectReason.Banned) {
sb.Append('\t');
if(Expires.Year >= 2100)
sb.Append("-1");
if(expires.HasValue && expires.Value > DateTimeOffset.UtcNow) {
sb.Append("1\t");
if(expires.Value < DateTimeOffset.MaxValue)
sb.Append(expires.Value.ToUnixTimeSeconds());
else
sb.Append(Expires.ToUnixTimeSeconds());
}
sb.Append("-1");
} else
sb.Append('0');
return sb.ToString();
}
}

View file

@ -1,17 +1,12 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class UserChannelForceJoinS2CPacket(ChatChannel channel) : S2CPacket {
public ChatChannel Channel { get; private set; } = channel ?? throw new ArgumentNullException(nameof(channel));
public class UserChannelForceJoinS2CPacket(string channelName) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('5');
sb.Append('\t');
sb.Append('2');
sb.Append('\t');
sb.Append(Channel.Name);
sb.Append("5\t2\t");
sb.Append(channelName);
return sb.ToString();
}

View file

@ -1,17 +1,12 @@
using System.Text;
namespace SharpChat.S2CPackets {
public class UserChannelLeaveS2CPacket(long msgId, ChatUser user) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public class UserChannelLeaveS2CPacket(long msgId, long userId) : S2CPacket {
public string Pack() {
StringBuilder sb = new();
sb.Append('5');
sb.Append('\t');
sb.Append('1');
sb.Append('\t');
sb.Append(User.UserId);
sb.Append("5\t1\t");
sb.Append(userId);
sb.Append('\t');
sb.Append(msgId);

View file

@ -1,43 +1,41 @@
using System.Text;
namespace SharpChat.S2CPackets {
public enum UserDisconnectReason {
Leave,
TimeOut,
Kicked,
Flood,
}
public class UserDisconnectS2CPacket(
long msgId,
DateTimeOffset disconnected,
ChatUser user,
UserDisconnectReason reason
long userId,
string userName,
UserDisconnectS2CPacket.Reason reason
) : S2CPacket {
public ChatUser User { get; private set; } = user ?? throw new ArgumentNullException(nameof(user));
public enum Reason {
Leave,
TimeOut,
Kicked,
Flood,
}
public string Pack() {
StringBuilder sb = new();
sb.Append('3');
sb.Append("3\t");
sb.Append(userId);
sb.Append('\t');
sb.Append(User.UserId);
sb.Append('\t');
sb.Append(User.LegacyNameWithStatus);
sb.Append(userName);
sb.Append('\t');
switch(reason) {
case UserDisconnectReason.Leave:
case Reason.Leave:
default:
sb.Append("leave");
break;
case UserDisconnectReason.TimeOut:
case Reason.TimeOut:
sb.Append("timeout");
break;
case UserDisconnectReason.Kicked:
case Reason.Kicked:
sb.Append("kick");
break;
case UserDisconnectReason.Flood:
case Reason.Flood:
sb.Append("flood");
break;
}

View file

@ -181,7 +181,7 @@ namespace SharpChat {
if(banDuration == TimeSpan.MinValue) {
Context.SendTo(conn.User, new CommandResponseS2CPacket(Context.RandomSnowflake.Next(), LCR.FLOOD_WARN, false));
} else {
Context.BanUser(conn.User, banDuration, UserDisconnectReason.Flood);
Context.BanUser(conn.User, banDuration, UserDisconnectS2CPacket.Reason.Flood);
if(banDuration > TimeSpan.Zero)
Misuzu.CreateBanAsync(