diff --git a/SharpChat.SockChat/Commands/UserAFKCommand.cs b/SharpChat.SockChat/Commands/UserAFKCommand.cs index b90ef31..f5ce5de 100644 --- a/SharpChat.SockChat/Commands/UserAFKCommand.cs +++ b/SharpChat.SockChat/Commands/UserAFKCommand.cs @@ -1,4 +1,5 @@ -using System.Linq; +using SharpChat.Events; +using System.Linq; namespace SharpChat.SockChat.Commands { public class UserAFKCommand : ISockChatClientCommand { @@ -19,10 +20,10 @@ namespace SharpChat.SockChat.Commands { statusText = statusText[..MAX_LENGTH].Trim(); } - ctx.Chat.UpdateUser( + ctx.Chat.Events.Dispatch( + "user:status", ctx.User, - status: UserStatus.Away, - statusText: statusText + new UserStatusUpdateEventData(UserStatus.Away, statusText) ); } } diff --git a/SharpChat.SockChat/Commands/UserNickCommand.cs b/SharpChat.SockChat/Commands/UserNickCommand.cs index cdde2b1..5a563e8 100644 --- a/SharpChat.SockChat/Commands/UserNickCommand.cs +++ b/SharpChat.SockChat/Commands/UserNickCommand.cs @@ -1,4 +1,5 @@ -using SharpChat.SockChat.PacketsS2C; +using SharpChat.Events; +using SharpChat.SockChat.PacketsS2C; using System.Linq; namespace SharpChat.SockChat.Commands { @@ -39,16 +40,22 @@ namespace SharpChat.SockChat.Commands { nickStr = string.Empty; else if(nickStr.Length > 15) nickStr = nickStr[..15]; - else if(string.IsNullOrEmpty(nickStr)) - nickStr = string.Empty; - if(!string.IsNullOrWhiteSpace(nickStr) && ctx.Chat.Users.Get(name: nickStr, nameTarget: UsersContext.NameTarget.UserAndNickName) != null) { + if(string.IsNullOrWhiteSpace(nickStr)) + nickStr = string.Empty; + else if(ctx.Chat.Users.Get(name: nickStr, nameTarget: UsersContext.NameTarget.UserAndNickName) != null) { ctx.Chat.SendTo(ctx.User, new UserNameInUseErrorS2CPacket(nickStr)); return; } - string? previousName = targetUser == ctx.User ? (targetUser.NickName ?? targetUser.UserName) : null; - ctx.Chat.UpdateUser(targetUser, nickName: nickStr, silent: previousName == null); + ctx.Chat.Events.Dispatch( + "user:update", + targetUser, + new UserUpdateEventData( + nickName: nickStr, + notify: targetUser.UserId == ctx.User.UserId + ) + ); } } } diff --git a/SharpChat.SockChat/Commands/WhoCommand.cs b/SharpChat.SockChat/Commands/WhoCommand.cs index 474234b..157736f 100644 --- a/SharpChat.SockChat/Commands/WhoCommand.cs +++ b/SharpChat.SockChat/Commands/WhoCommand.cs @@ -12,7 +12,7 @@ namespace SharpChat.SockChat.Commands { if(string.IsNullOrEmpty(channelName)) { ctx.Chat.SendTo(ctx.User, new WhoServerResponseS2CPacket( - ctx.Chat.Users.All.Select(u => SockChatUtility.GetUserNameWithStatus(u)).ToArray(), + ctx.Chat.Users.All.Select(u => SockChatUtility.GetUserName(u, ctx.Chat.UserStatuses.Get(u))).ToArray(), SockChatUtility.GetUserName(ctx.User) )); return; @@ -32,8 +32,8 @@ namespace SharpChat.SockChat.Commands { ctx.Chat.SendTo(ctx.User, new WhoChannelResponseS2CPacket( channel.Name, - ctx.Chat.GetChannelUsers(channel).Select(user => SockChatUtility.GetUserNameWithStatus(user)).ToArray(), - SockChatUtility.GetUserNameWithStatus(ctx.User) + ctx.Chat.GetChannelUsers(channel).Select(user => SockChatUtility.GetUserName(user, ctx.Chat.UserStatuses.Get(user))).ToArray(), + SockChatUtility.GetUserName(ctx.User, ctx.Chat.UserStatuses.Get(ctx.User)) )); } } diff --git a/SharpChat.SockChat/PacketsC2S/AuthC2SPacketHandler.cs b/SharpChat.SockChat/PacketsC2S/AuthC2SPacketHandler.cs index 5ec01e9..0027d04 100644 --- a/SharpChat.SockChat/PacketsC2S/AuthC2SPacketHandler.cs +++ b/SharpChat.SockChat/PacketsC2S/AuthC2SPacketHandler.cs @@ -1,4 +1,5 @@ using SharpChat.Config; +using SharpChat.Events; using SharpChat.Misuzu; using SharpChat.SockChat.PacketsS2C; using System; @@ -121,7 +122,7 @@ namespace SharpChat.SockChat.PacketsC2S { try { UserInfo? user = ctx.Chat.Users.Get(fai.UserId); - if(user == null) + if(user == null) { user = new UserInfo( fai.UserId, fai.UserName ?? string.Empty, @@ -130,15 +131,26 @@ namespace SharpChat.SockChat.PacketsC2S { fai.Permissions, isSuper: fai.IsSuper ); - else - ctx.Chat.UpdateUser( - user, - userName: fai.UserName, - colour: fai.Colour, - rank: fai.Rank, - perms: fai.Permissions, - isSuper: fai.IsSuper - ); + } else { + string? updName = !user.UserName.Equals(fai.UserName) ? fai.UserName : null; + int? updColour = (updColour = fai.Colour.ToMisuzu()) != user.Colour.ToMisuzu() ? updColour : null; + int? updRank = user.Rank != fai.Rank ? fai.Rank : null; + UserPermissions? updPerms = user.Permissions != fai.Permissions ? fai.Permissions : null; + bool? updSuper = user.IsSuper != fai.IsSuper ? fai.IsSuper : null; + + if(updName != null || updColour != null || updRank != null || updPerms != null || updSuper != null) + ctx.Chat.Events.Dispatch( + "user:update", + user, + new UserUpdateEventData( + name: updName, + colour: updColour, + rank: updRank, + perms: updPerms, + isSuper: updSuper + ) + ); + } // Enforce a maximum amount of connections per user if(ctx.Chat.Connections.GetCountForUser(user) >= MaxConnections) { diff --git a/SharpChat.SockChat/PacketsC2S/PingC2SPacketHandler.cs b/SharpChat.SockChat/PacketsC2S/PingC2SPacketHandler.cs index 5ce6f08..003f512 100644 --- a/SharpChat.SockChat/PacketsC2S/PingC2SPacketHandler.cs +++ b/SharpChat.SockChat/PacketsC2S/PingC2SPacketHandler.cs @@ -35,7 +35,7 @@ namespace SharpChat.SockChat.PacketsC2S { List<(string, string)> bumpList = new(); foreach(UserInfo userInfo in ctx.Chat.Users.All) { - if(userInfo.Status != UserStatus.Online) + if(ctx.Chat.UserStatuses.GetStatus(userInfo) != UserStatus.Online) continue; string[] remoteAddrs = ctx.Chat.Connections.GetUserRemoteAddresses(userInfo); diff --git a/SharpChat.SockChat/PacketsC2S/SendMessageC2SPacketHandler.cs b/SharpChat.SockChat/PacketsC2S/SendMessageC2SPacketHandler.cs index 1960980..6434db4 100644 --- a/SharpChat.SockChat/PacketsC2S/SendMessageC2SPacketHandler.cs +++ b/SharpChat.SockChat/PacketsC2S/SendMessageC2SPacketHandler.cs @@ -49,8 +49,12 @@ namespace SharpChat.SockChat.PacketsC2S { if(channelInfo == null) return; - if(user.Status != UserStatus.Online) - ctx.Chat.UpdateUser(user, status: UserStatus.Online); + if(ctx.Chat.UserStatuses.GetStatus(user) != UserStatus.Online) + ctx.Chat.Events.Dispatch( + "user:status", + user, + new UserStatusUpdateEventData(UserStatus.Online) + ); int maxMsgLength = MaxMessageLength; if(messageText.Length > maxMsgLength) diff --git a/SharpChat.SockChat/PacketsS2C/UserNickChangeLogS2CPacket.cs b/SharpChat.SockChat/PacketsS2C/UserNickChangeLogS2CPacket.cs new file mode 100644 index 0000000..dab9037 --- /dev/null +++ b/SharpChat.SockChat/PacketsS2C/UserNickChangeLogS2CPacket.cs @@ -0,0 +1,32 @@ +using System; + +namespace SharpChat.SockChat.PacketsS2C { + public class UserNickChangeLogS2CPacket : ISockChatS2CPacket { + private readonly long MessageId; + private readonly DateTimeOffset TimeStamp; + private readonly string PrevName; + private readonly string NewName; + + public UserNickChangeLogS2CPacket( + long messageId, + DateTimeOffset timeStamp, + string prevName, + string newName + ) { + MessageId = messageId; + TimeStamp = timeStamp; + PrevName = prevName; + NewName = newName; + } + + public string Pack() { + return string.Format( + "7\t1\t{0}\t-1\tChatBot\tinherit\t\t0\fnick\f{1}\f{2}\t{3}\t0\t10010", + TimeStamp.ToUnixTimeSeconds(), + PrevName, + NewName, + MessageId + ); + } + } +} diff --git a/SharpChat.SockChat/PacketsS2C/UserUpdateNotificationS2CPacket.cs b/SharpChat.SockChat/PacketsS2C/UserNickChangeS2CPacket.cs similarity index 54% rename from SharpChat.SockChat/PacketsS2C/UserUpdateNotificationS2CPacket.cs rename to SharpChat.SockChat/PacketsS2C/UserNickChangeS2CPacket.cs index 700eccb..db83ff7 100644 --- a/SharpChat.SockChat/PacketsS2C/UserUpdateNotificationS2CPacket.cs +++ b/SharpChat.SockChat/PacketsS2C/UserNickChangeS2CPacket.cs @@ -1,16 +1,21 @@ using System; namespace SharpChat.SockChat.PacketsS2C { - public class UserUpdateNotificationS2CPacket : ISockChatS2CPacket { + public class UserNickChangeS2CPacket : ISockChatS2CPacket { private readonly long MessageId; private readonly DateTimeOffset TimeStamp; - private readonly string PreviousName; + private readonly string PrevName; private readonly string NewName; - public UserUpdateNotificationS2CPacket(string previousName, string newName) { - MessageId = SharpId.Next(); - TimeStamp = DateTimeOffset.UtcNow; - PreviousName = previousName; + public UserNickChangeS2CPacket( + long messageId, + DateTimeOffset timeStamp, + string prevName, + string newName + ) { + MessageId = messageId; + TimeStamp = timeStamp; + PrevName = prevName; NewName = newName; } @@ -18,7 +23,7 @@ namespace SharpChat.SockChat.PacketsS2C { return string.Format( "2\t{0}\t-1\t0\fnick\f{1}\f{2}\t{3}\t10010", TimeStamp.ToUnixTimeSeconds(), - PreviousName, + PrevName, NewName, MessageId ); diff --git a/SharpChat.SockChat/SockChatContext.cs b/SharpChat.SockChat/SockChatContext.cs index e681295..8e5d9e5 100644 --- a/SharpChat.SockChat/SockChatContext.cs +++ b/SharpChat.SockChat/SockChatContext.cs @@ -11,11 +11,12 @@ namespace SharpChat { public class SockChatContext : IChatEventHandler { public readonly SemaphoreSlim ContextAccess = new(1, 1); - public ChannelsContext Channels { get; } = new(); - public ConnectionsContext Connections { get; } = new(); - public UsersContext Users { get; } = new(); public IEventStorage EventStorage { get; } public ChatEventDispatcher Events { get; } = new(); + public ConnectionsContext Connections { get; } = new(); + public ChannelsContext Channels { get; } = new(); + public UsersContext Users { get; } = new(); + public UserStatusContext UserStatuses { get; } = new(); public ChannelsUsersContext ChannelsUsers { get; } = new(); public Dictionary UserRateLimiters { get; } = new(); @@ -28,6 +29,7 @@ namespace SharpChat { public void HandleEvent(ChatEventInfo info) { // user status should be stored outside of the UserInfo class so we don't need to do this: UserInfo? userInfo = Users.Get(info.SenderId); + UserStatusInfo userStatusInfo = UserStatuses.Get(info.SenderId); if(!string.IsNullOrWhiteSpace(info.ChannelName)) ChannelsUsers.SetUserLastChannel(info.SenderId, info.ChannelName); @@ -40,7 +42,7 @@ namespace SharpChat { info.Id, info.Created, info.SenderId, - userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo), + SockChatUtility.GetUserName(info, userStatusInfo), info.SenderColour, info.SenderRank, info.SenderPerms @@ -49,7 +51,8 @@ namespace SharpChat { case "user:disconnect": if(userInfo != null) - UpdateUser(userInfo, status: UserStatus.Offline); + Events.Dispatch("user:status", userInfo, new UserStatusUpdateEventData(UserStatus.Offline)); + UserStatuses.Clear(info.SenderId); Users.Remove(info.SenderId); ChannelInfo[] channels = Channels.GetMany(ChannelsUsers.GetUserChannelNames(info.SenderId)); @@ -60,7 +63,7 @@ namespace SharpChat { info.Id, info.Created, info.SenderId, - userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo), + SockChatUtility.GetUserName(info, userStatusInfo), info.Data is UserDisconnectEventData userDisconnect ? userDisconnect.Reason : UserDisconnectReason.Leave ); @@ -73,6 +76,86 @@ namespace SharpChat { } break; + case "user:status": + if(info.Data is not UserStatusUpdateEventData userStatusUpdate) + break; + + if(userStatusInfo.Status == userStatusUpdate.Status + && userStatusInfo.Text.Equals(userStatusUpdate.Text)) + break; + + userStatusInfo = UserStatuses.Set( + info.SenderId, + userStatusUpdate.Status, + userStatusUpdate.Text ?? string.Empty + ); + + SendToUserChannels(info.SenderId, new UserUpdateS2CPacket( + info.SenderId, + SockChatUtility.GetUserName(info, userStatusInfo), + info.SenderColour, + info.SenderRank, + info.SenderPerms + )); + break; + + case "user:update": + if(info.Data is not UserUpdateEventData userUpdate || userInfo is null) + break; + + bool uuHasChanged = false; + string? uuPrevName = null; + + if(userUpdate.Name != null && !userUpdate.Name.Equals(userInfo.UserName)) { + userInfo.UserName = userUpdate.Name; + uuHasChanged = true; + } + + if(userUpdate.NickName != null && !userUpdate.NickName.Equals(userInfo.NickName)) { + if(userUpdate.Notify) + uuPrevName = string.IsNullOrWhiteSpace(userInfo.NickName) ? userInfo.UserName : userInfo.NickName; + + userInfo.NickName = userUpdate.NickName; + uuHasChanged = true; + } + + if(userUpdate.Colour.HasValue && userUpdate.Colour != userInfo.Colour.ToMisuzu()) { + userInfo.Colour = Colour.FromMisuzu(userUpdate.Colour.Value); + uuHasChanged = true; + } + + if(userUpdate.Rank != null && userUpdate.Rank != userInfo.Rank) { + userInfo.Rank = userUpdate.Rank.Value; + uuHasChanged = true; + } + + if(userUpdate.Perms.HasValue && userUpdate.Perms != userInfo.Permissions) { + userInfo.Permissions = userUpdate.Perms.Value; + uuHasChanged = true; + } + + if(userUpdate.IsSuper.HasValue && userUpdate.IsSuper != userInfo.IsSuper) + userInfo.IsSuper = userUpdate.IsSuper.Value; + + if(uuHasChanged) { + if(uuPrevName != null) + SendToUserChannels(info.SenderId, new UserNickChangeS2CPacket( + info.Id, + info.Created, + string.IsNullOrWhiteSpace(info.SenderNickName) ? uuPrevName : $"~{info.SenderNickName}", + SockChatUtility.GetUserName(userInfo, userStatusInfo) + )); + + SendToUserChannels(info.SenderId, new UserUpdateS2CPacket( + userInfo.UserId, + SockChatUtility.GetUserName(userInfo, userStatusInfo), + userInfo.Colour, + userInfo.Rank, + userInfo.Permissions + )); + } + break; + case "user:kickban": if(info.Data is not UserKickBanEventData userBaka) break; @@ -108,7 +191,7 @@ namespace SharpChat { case "chan:join": SendTo(info.ChannelName, new UserChannelJoinS2CPacket( info.SenderId, - userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo), + SockChatUtility.GetUserName(info, userStatusInfo), info.SenderColour, info.SenderRank, info.SenderPerms @@ -219,86 +302,10 @@ namespace SharpChat { } } - public ChannelInfo[] GetUserChannels(UserInfo user) { - return Channels.GetMany(ChannelsUsers.GetUserChannelNames(user)); - } - public UserInfo[] GetChannelUsers(ChannelInfo channel) { return Users.GetMany(ChannelsUsers.GetChannelUserIds(channel)); } - public void UpdateUser( - UserInfo user, - string? userName = null, - string? nickName = null, - Colour? colour = null, - UserStatus? status = null, - string? statusText = null, - int? rank = null, - UserPermissions? perms = null, - bool? isSuper = null, - bool silent = false - ) { - bool hasChanged = false; - string? previousName = null; - - if(userName != null && !user.UserName.Equals(userName)) { - user.UserName = userName; - hasChanged = true; - } - - if(nickName != null && !user.NickName.Equals(nickName)) { - if(!silent) - previousName = string.IsNullOrWhiteSpace(user.NickName) ? user.UserName : user.NickName; - - user.NickName = nickName; - hasChanged = true; - } - - if(colour.HasValue && !user.Colour.Equals(colour.Value)) { - user.Colour = colour.Value; - hasChanged = true; - } - - if(status.HasValue && user.Status != status.Value) { - user.Status = status.Value; - hasChanged = true; - } - - if(statusText != null && !user.StatusText.Equals(statusText)) { - user.StatusText = statusText; - hasChanged = true; - } - - if(rank != null && user.Rank != rank) { - user.Rank = (int)rank; - hasChanged = true; - } - - if(perms.HasValue && user.Permissions != perms) { - user.Permissions = perms.Value; - hasChanged = true; - } - - if(isSuper.HasValue && user.IsSuper != isSuper) { - user.IsSuper = isSuper.Value; - hasChanged = true; - } - - if(hasChanged) { - if(previousName != null) - SendToUserChannels(user, new UserUpdateNotificationS2CPacket(previousName, SockChatUtility.GetUserNameWithStatus(user))); - - SendToUserChannels(user, new UserUpdateS2CPacket( - user.UserId, - SockChatUtility.GetUserNameWithStatus(user), - user.Colour, - user.Rank, - user.Permissions - )); - } - } - public void HandleChannelEventLog(string channelName, Action handler) { foreach(ChatEventInfo info in EventStorage.GetChannelEventLog(channelName)) { switch(info.Type) { @@ -339,6 +346,16 @@ namespace SharpChat { )); break; + case "user:update": + if(info.Data is UserUpdateEventData userUpdate && userUpdate.Notify) + handler(new UserNickChangeLogS2CPacket( + info.Id, + info.Created, + info.SenderNickName == null ? info.SenderName : $"~{info.SenderNickName}", + userUpdate.NickName == null ? info.SenderName : $"~{userUpdate.NickName}" + )); + break; + case "chan:join": handler(new UserChannelJoinLogS2CPacket( info.Id, @@ -362,9 +379,11 @@ namespace SharpChat { if(!ChannelsUsers.Has(chan, user)) Events.Dispatch("user:connect", chan, user); + UserStatusInfo statusInfo = UserStatuses.Get(user); + conn.Send(new AuthSuccessS2CPacket( user.UserId, - SockChatUtility.GetUserNameWithStatus(user), + SockChatUtility.GetUserName(user, statusInfo), user.Colour, user.Rank, user.Permissions, @@ -374,7 +393,7 @@ namespace SharpChat { conn.Send(new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select( user => new UsersPopulateS2CPacket.ListEntry( user.UserId, - SockChatUtility.GetUserNameWithStatus(user), + SockChatUtility.GetUserName(user, statusInfo), user.Colour, user.Rank, user.Permissions, @@ -430,7 +449,7 @@ namespace SharpChat { SendTo(user, new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select( user => new UsersPopulateS2CPacket.ListEntry( user.UserId, - SockChatUtility.GetUserNameWithStatus(user), + SockChatUtility.GetUserName(user, UserStatuses.Get(user)), user.Colour, user.Rank, user.Permissions, @@ -494,7 +513,11 @@ namespace SharpChat { } public void SendToUserChannels(UserInfo user, ISockChatS2CPacket packet) { - ChannelInfo[] chans = GetUserChannels(user); + SendToUserChannels(user.UserId, packet); + } + + public void SendToUserChannels(long userId, ISockChatS2CPacket packet) { + ChannelInfo[] chans = Channels.GetMany(ChannelsUsers.GetUserChannelNames(userId)); string data = packet.Pack(); foreach(ChannelInfo chan in chans) SendTo(chan, data); diff --git a/SharpChat.SockChat/SockChatUtility.cs b/SharpChat.SockChat/SockChatUtility.cs index ac6c4d4..ae86fc0 100644 --- a/SharpChat.SockChat/SockChatUtility.cs +++ b/SharpChat.SockChat/SockChatUtility.cs @@ -21,25 +21,30 @@ namespace SharpChat.SockChat { return name.Length < 1 || ChannelName.IsMatch(name); } - public static string GetUserName(UserInfo info) { - return string.IsNullOrWhiteSpace(info.NickName) ? info.UserName : $"~{info.NickName}"; - } + public static string GetUserName(UserInfo info, UserStatusInfo? statusInfo = null) { + string name = string.IsNullOrWhiteSpace(info.NickName) ? info.UserName : $"~{info.NickName}"; - public static string GetUserNameWithStatus(UserInfo info) { - string name = GetUserName(info); - - if(info.Status == UserStatus.Away) + if(statusInfo?.Status == UserStatus.Away) name = string.Format( "<{0}>_{1}", - info.StatusText[..Math.Min(info.StatusText.Length, 5)].ToUpperInvariant(), + statusInfo.Text[..Math.Min(statusInfo.Text.Length, 5)].ToUpperInvariant(), name ); return name; } - public static string GetUserName(ChatEventInfo info) { - return string.IsNullOrWhiteSpace(info.SenderNickName) ? info.SenderName : $"~{info.SenderNickName}"; + public static string GetUserName(ChatEventInfo info, UserStatusInfo? statusInfo = null) { + string name = string.IsNullOrWhiteSpace(info.SenderNickName) ? info.SenderName : $"~{info.SenderNickName}"; + + if(statusInfo?.Status == UserStatus.Away) + name = string.Format( + "<{0}>_{1}", + statusInfo.Text[..Math.Min(statusInfo.Text.Length, 5)].ToUpperInvariant(), + name + ); + + return name; } public static (string, UsersContext.NameTarget) ExplodeUserName(string name) { diff --git a/SharpChatCommon/EventStorage/MariaDBEventStorage.cs b/SharpChatCommon/EventStorage/MariaDBEventStorage.cs index e2f3d4f..61f8b4d 100644 --- a/SharpChatCommon/EventStorage/MariaDBEventStorage.cs +++ b/SharpChatCommon/EventStorage/MariaDBEventStorage.cs @@ -3,7 +3,6 @@ using SharpChat.Events; using System; using System.Collections.Generic; using System.Reflection; -using System.Text; using System.Text.Json; namespace SharpChat.EventStorage { @@ -91,7 +90,7 @@ namespace SharpChat.EventStorage { reader.GetInt64("event_id"), eventType, DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")), - reader.GetString("event_channel"), + reader.IsDBNull(reader.GetOrdinal("event_channel")) ? string.Empty : reader.GetString("event_channel"), reader.IsDBNull(reader.GetOrdinal("event_sender")) ? -1 : reader.GetInt64("event_sender"), reader.IsDBNull(reader.GetOrdinal("event_sender_name")) ? string.Empty : reader.GetString("event_sender_name"), reader.IsDBNull(reader.GetOrdinal("event_sender_colour")) ? Colour.None : Colour.FromMisuzu(reader.GetInt32("event_sender_colour")), diff --git a/SharpChatCommon/Events/UserStatusUpdateEventData.cs b/SharpChatCommon/Events/UserStatusUpdateEventData.cs new file mode 100644 index 0000000..26d45c8 --- /dev/null +++ b/SharpChatCommon/Events/UserStatusUpdateEventData.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; + +namespace SharpChat.Events { + [ChatEventDataFor("user:status")] + public class UserStatusUpdateEventData : ChatEventData { + [JsonPropertyName("status")] + public UserStatus Status { get; } + + [JsonPropertyName("text")] + public string? Text { get; } + + public UserStatusUpdateEventData(UserStatus status, string? text = null) { + Status = status; + Text = string.IsNullOrWhiteSpace(text) ? null : text; + } + } +} diff --git a/SharpChatCommon/Events/UserUpdateEventData.cs b/SharpChatCommon/Events/UserUpdateEventData.cs new file mode 100644 index 0000000..594f8ef --- /dev/null +++ b/SharpChatCommon/Events/UserUpdateEventData.cs @@ -0,0 +1,45 @@ +using System.Text.Json.Serialization; + +namespace SharpChat.Events { + [ChatEventDataFor("user:update")] + public class UserUpdateEventData : ChatEventData { + [JsonPropertyName("notify")] + public bool Notify { get; } + + [JsonPropertyName("name")] + public string? Name { get; } + + [JsonPropertyName("colour")] + public int? Colour { get; } + + [JsonPropertyName("rank")] + public int? Rank { get; } + + [JsonPropertyName("perms")] + public UserPermissions? Perms { get; } + + [JsonPropertyName("nick")] + public string? NickName { get; } + + [JsonPropertyName("super")] + public bool? IsSuper { get; } + + public UserUpdateEventData( + string? name = null, + int? colour = null, + int? rank = null, + UserPermissions? perms = null, + string? nickName = null, + bool? isSuper = null, + bool notify = false + ) { + Notify = notify; + Name = name; + Colour = colour; + Rank = rank; + Perms = perms; + NickName = nickName; + IsSuper = isSuper; + } + } +} diff --git a/SharpChatCommon/UserInfo.cs b/SharpChatCommon/UserInfo.cs index 7b1a3a9..3e03a7e 100644 --- a/SharpChatCommon/UserInfo.cs +++ b/SharpChatCommon/UserInfo.cs @@ -11,8 +11,6 @@ public UserPermissions Permissions { get; set; } public bool IsSuper { get; set; } public string NickName { get; set; } - public UserStatus Status { get; set; } - public string StatusText { get; set; } public UserInfo( long userId, @@ -21,8 +19,6 @@ int rank, UserPermissions perms, string? nickName = null, - UserStatus status = UserStatus.Online, - string? statusText = null, bool isSuper = false ) { UserId = userId; @@ -31,8 +27,6 @@ Rank = rank; Permissions = perms; NickName = nickName ?? string.Empty; - Status = status; - StatusText = statusText ?? string.Empty; IsSuper = isSuper; } diff --git a/SharpChatCommon/UserStatus.cs b/SharpChatCommon/UserStatus.cs index 447333b..2ddc566 100644 --- a/SharpChatCommon/UserStatus.cs +++ b/SharpChatCommon/UserStatus.cs @@ -1,7 +1,8 @@ namespace SharpChat { - public enum UserStatus { - Online, - Away, - Offline, + public enum UserStatus : int { + Unknown = 0, + Online = 1, + Away = 2, + Offline = 3, } } diff --git a/SharpChatCommon/UserStatusContext.cs b/SharpChatCommon/UserStatusContext.cs new file mode 100644 index 0000000..7e395d8 --- /dev/null +++ b/SharpChatCommon/UserStatusContext.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; + +namespace SharpChat { + public class UserStatusContext { + private readonly Dictionary Statuses = new(); + + public UserStatusInfo Get(long userId) { + return Statuses.ContainsKey(userId) + ? Statuses[userId] + : UserStatusInfo.EmptyInstance; + } + + public UserStatusInfo Get(UserInfo userInfo) { + return Get(userInfo.UserId); + } + + public UserStatus GetStatus(long userId) { + return Get(userId).Status; + } + + public UserStatus GetStatus(UserInfo userInfo) { + return Get(userInfo.UserId).Status; + } + + public UserStatusInfo Set(long userId, UserStatus status, string text) { + UserStatusInfo statusInfo = new(status, text); + if(Statuses.ContainsKey(userId)) + Statuses[userId] = statusInfo; + else + Statuses.Add(userId, statusInfo); + + return statusInfo; + } + + public void Clear(long userId) { + Statuses.Remove(userId); + } + } +} diff --git a/SharpChatCommon/UserStatusInfo.cs b/SharpChatCommon/UserStatusInfo.cs new file mode 100644 index 0000000..0fd9999 --- /dev/null +++ b/SharpChatCommon/UserStatusInfo.cs @@ -0,0 +1,16 @@ +namespace SharpChat { + public class UserStatusInfo { + public UserStatus Status { get; } + public string Text { get; } + + public UserStatusInfo( + UserStatus status, + string text + ) { + Status = status; + Text = text; + } + + public static readonly UserStatusInfo EmptyInstance = new(UserStatus.Unknown, string.Empty); + } +} diff --git a/SharpChatCommon/UsersContext.cs b/SharpChatCommon/UsersContext.cs index a69bbf5..17e6179 100644 --- a/SharpChatCommon/UsersContext.cs +++ b/SharpChatCommon/UsersContext.cs @@ -1,5 +1,4 @@ -using SharpChat.SockChat; -using System; +using System; using System.Collections.Generic; using System.Linq;