Split status elements out of UserInfo and made user update event based.
This commit is contained in:
parent
2eae48325a
commit
86effa0452
|
@ -1,4 +1,5 @@
|
||||||
using System.Linq;
|
using SharpChat.Events;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace SharpChat.SockChat.Commands {
|
namespace SharpChat.SockChat.Commands {
|
||||||
public class UserAFKCommand : ISockChatClientCommand {
|
public class UserAFKCommand : ISockChatClientCommand {
|
||||||
|
@ -19,10 +20,10 @@ namespace SharpChat.SockChat.Commands {
|
||||||
statusText = statusText[..MAX_LENGTH].Trim();
|
statusText = statusText[..MAX_LENGTH].Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Chat.UpdateUser(
|
ctx.Chat.Events.Dispatch(
|
||||||
|
"user:status",
|
||||||
ctx.User,
|
ctx.User,
|
||||||
status: UserStatus.Away,
|
new UserStatusUpdateEventData(UserStatus.Away, statusText)
|
||||||
statusText: statusText
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using SharpChat.SockChat.PacketsS2C;
|
using SharpChat.Events;
|
||||||
|
using SharpChat.SockChat.PacketsS2C;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace SharpChat.SockChat.Commands {
|
namespace SharpChat.SockChat.Commands {
|
||||||
|
@ -39,16 +40,22 @@ namespace SharpChat.SockChat.Commands {
|
||||||
nickStr = string.Empty;
|
nickStr = string.Empty;
|
||||||
else if(nickStr.Length > 15)
|
else if(nickStr.Length > 15)
|
||||||
nickStr = nickStr[..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));
|
ctx.Chat.SendTo(ctx.User, new UserNameInUseErrorS2CPacket(nickStr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string? previousName = targetUser == ctx.User ? (targetUser.NickName ?? targetUser.UserName) : null;
|
ctx.Chat.Events.Dispatch(
|
||||||
ctx.Chat.UpdateUser(targetUser, nickName: nickStr, silent: previousName == null);
|
"user:update",
|
||||||
|
targetUser,
|
||||||
|
new UserUpdateEventData(
|
||||||
|
nickName: nickStr,
|
||||||
|
notify: targetUser.UserId == ctx.User.UserId
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace SharpChat.SockChat.Commands {
|
||||||
|
|
||||||
if(string.IsNullOrEmpty(channelName)) {
|
if(string.IsNullOrEmpty(channelName)) {
|
||||||
ctx.Chat.SendTo(ctx.User, new WhoServerResponseS2CPacket(
|
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)
|
SockChatUtility.GetUserName(ctx.User)
|
||||||
));
|
));
|
||||||
return;
|
return;
|
||||||
|
@ -32,8 +32,8 @@ namespace SharpChat.SockChat.Commands {
|
||||||
|
|
||||||
ctx.Chat.SendTo(ctx.User, new WhoChannelResponseS2CPacket(
|
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.GetUserName(user, ctx.Chat.UserStatuses.Get(user))).ToArray(),
|
||||||
SockChatUtility.GetUserNameWithStatus(ctx.User)
|
SockChatUtility.GetUserName(ctx.User, ctx.Chat.UserStatuses.Get(ctx.User))
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using SharpChat.Config;
|
using SharpChat.Config;
|
||||||
|
using SharpChat.Events;
|
||||||
using SharpChat.Misuzu;
|
using SharpChat.Misuzu;
|
||||||
using SharpChat.SockChat.PacketsS2C;
|
using SharpChat.SockChat.PacketsS2C;
|
||||||
using System;
|
using System;
|
||||||
|
@ -121,7 +122,7 @@ namespace SharpChat.SockChat.PacketsC2S {
|
||||||
try {
|
try {
|
||||||
UserInfo? user = ctx.Chat.Users.Get(fai.UserId);
|
UserInfo? user = ctx.Chat.Users.Get(fai.UserId);
|
||||||
|
|
||||||
if(user == null)
|
if(user == null) {
|
||||||
user = new UserInfo(
|
user = new UserInfo(
|
||||||
fai.UserId,
|
fai.UserId,
|
||||||
fai.UserName ?? string.Empty,
|
fai.UserName ?? string.Empty,
|
||||||
|
@ -130,15 +131,26 @@ namespace SharpChat.SockChat.PacketsC2S {
|
||||||
fai.Permissions,
|
fai.Permissions,
|
||||||
isSuper: fai.IsSuper
|
isSuper: fai.IsSuper
|
||||||
);
|
);
|
||||||
else
|
} else {
|
||||||
ctx.Chat.UpdateUser(
|
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,
|
user,
|
||||||
userName: fai.UserName,
|
new UserUpdateEventData(
|
||||||
colour: fai.Colour,
|
name: updName,
|
||||||
rank: fai.Rank,
|
colour: updColour,
|
||||||
perms: fai.Permissions,
|
rank: updRank,
|
||||||
isSuper: fai.IsSuper
|
perms: updPerms,
|
||||||
|
isSuper: updSuper
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// 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) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ namespace SharpChat.SockChat.PacketsC2S {
|
||||||
List<(string, string)> bumpList = new();
|
List<(string, string)> bumpList = new();
|
||||||
|
|
||||||
foreach(UserInfo userInfo in ctx.Chat.Users.All) {
|
foreach(UserInfo userInfo in ctx.Chat.Users.All) {
|
||||||
if(userInfo.Status != UserStatus.Online)
|
if(ctx.Chat.UserStatuses.GetStatus(userInfo) != UserStatus.Online)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
string[] remoteAddrs = ctx.Chat.Connections.GetUserRemoteAddresses(userInfo);
|
string[] remoteAddrs = ctx.Chat.Connections.GetUserRemoteAddresses(userInfo);
|
||||||
|
|
|
@ -49,8 +49,12 @@ namespace SharpChat.SockChat.PacketsC2S {
|
||||||
if(channelInfo == null)
|
if(channelInfo == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(user.Status != UserStatus.Online)
|
if(ctx.Chat.UserStatuses.GetStatus(user) != UserStatus.Online)
|
||||||
ctx.Chat.UpdateUser(user, status: UserStatus.Online);
|
ctx.Chat.Events.Dispatch(
|
||||||
|
"user:status",
|
||||||
|
user,
|
||||||
|
new UserStatusUpdateEventData(UserStatus.Online)
|
||||||
|
);
|
||||||
|
|
||||||
int maxMsgLength = MaxMessageLength;
|
int maxMsgLength = MaxMessageLength;
|
||||||
if(messageText.Length > maxMsgLength)
|
if(messageText.Length > maxMsgLength)
|
||||||
|
|
32
SharpChat.SockChat/PacketsS2C/UserNickChangeLogS2CPacket.cs
Normal file
32
SharpChat.SockChat/PacketsS2C/UserNickChangeLogS2CPacket.cs
Normal file
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,16 +1,21 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace SharpChat.SockChat.PacketsS2C {
|
namespace SharpChat.SockChat.PacketsS2C {
|
||||||
public class UserUpdateNotificationS2CPacket : ISockChatS2CPacket {
|
public class UserNickChangeS2CPacket : ISockChatS2CPacket {
|
||||||
private readonly long MessageId;
|
private readonly long MessageId;
|
||||||
private readonly DateTimeOffset TimeStamp;
|
private readonly DateTimeOffset TimeStamp;
|
||||||
private readonly string PreviousName;
|
private readonly string PrevName;
|
||||||
private readonly string NewName;
|
private readonly string NewName;
|
||||||
|
|
||||||
public UserUpdateNotificationS2CPacket(string previousName, string newName) {
|
public UserNickChangeS2CPacket(
|
||||||
MessageId = SharpId.Next();
|
long messageId,
|
||||||
TimeStamp = DateTimeOffset.UtcNow;
|
DateTimeOffset timeStamp,
|
||||||
PreviousName = previousName;
|
string prevName,
|
||||||
|
string newName
|
||||||
|
) {
|
||||||
|
MessageId = messageId;
|
||||||
|
TimeStamp = timeStamp;
|
||||||
|
PrevName = prevName;
|
||||||
NewName = newName;
|
NewName = newName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +23,7 @@ namespace SharpChat.SockChat.PacketsS2C {
|
||||||
return string.Format(
|
return string.Format(
|
||||||
"2\t{0}\t-1\t0\fnick\f{1}\f{2}\t{3}\t10010",
|
"2\t{0}\t-1\t0\fnick\f{1}\f{2}\t{3}\t10010",
|
||||||
TimeStamp.ToUnixTimeSeconds(),
|
TimeStamp.ToUnixTimeSeconds(),
|
||||||
PreviousName,
|
PrevName,
|
||||||
NewName,
|
NewName,
|
||||||
MessageId
|
MessageId
|
||||||
);
|
);
|
|
@ -11,11 +11,12 @@ namespace SharpChat {
|
||||||
public class SockChatContext : IChatEventHandler {
|
public class SockChatContext : IChatEventHandler {
|
||||||
public readonly SemaphoreSlim ContextAccess = new(1, 1);
|
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 IEventStorage EventStorage { get; }
|
||||||
public ChatEventDispatcher Events { get; } = new();
|
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 ChannelsUsersContext ChannelsUsers { get; } = new();
|
||||||
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = new();
|
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = new();
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ namespace SharpChat {
|
||||||
public void HandleEvent(ChatEventInfo info) {
|
public void HandleEvent(ChatEventInfo info) {
|
||||||
// user status should be stored outside of the UserInfo class so we don't need to do this:
|
// user status should be stored outside of the UserInfo class so we don't need to do this:
|
||||||
UserInfo? userInfo = Users.Get(info.SenderId);
|
UserInfo? userInfo = Users.Get(info.SenderId);
|
||||||
|
UserStatusInfo userStatusInfo = UserStatuses.Get(info.SenderId);
|
||||||
|
|
||||||
if(!string.IsNullOrWhiteSpace(info.ChannelName))
|
if(!string.IsNullOrWhiteSpace(info.ChannelName))
|
||||||
ChannelsUsers.SetUserLastChannel(info.SenderId, info.ChannelName);
|
ChannelsUsers.SetUserLastChannel(info.SenderId, info.ChannelName);
|
||||||
|
@ -40,7 +42,7 @@ namespace SharpChat {
|
||||||
info.Id,
|
info.Id,
|
||||||
info.Created,
|
info.Created,
|
||||||
info.SenderId,
|
info.SenderId,
|
||||||
userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo),
|
SockChatUtility.GetUserName(info, userStatusInfo),
|
||||||
info.SenderColour,
|
info.SenderColour,
|
||||||
info.SenderRank,
|
info.SenderRank,
|
||||||
info.SenderPerms
|
info.SenderPerms
|
||||||
|
@ -49,7 +51,8 @@ namespace SharpChat {
|
||||||
|
|
||||||
case "user:disconnect":
|
case "user:disconnect":
|
||||||
if(userInfo != null)
|
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);
|
Users.Remove(info.SenderId);
|
||||||
|
|
||||||
ChannelInfo[] channels = Channels.GetMany(ChannelsUsers.GetUserChannelNames(info.SenderId));
|
ChannelInfo[] channels = Channels.GetMany(ChannelsUsers.GetUserChannelNames(info.SenderId));
|
||||||
|
@ -60,7 +63,7 @@ namespace SharpChat {
|
||||||
info.Id,
|
info.Id,
|
||||||
info.Created,
|
info.Created,
|
||||||
info.SenderId,
|
info.SenderId,
|
||||||
userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo),
|
SockChatUtility.GetUserName(info, userStatusInfo),
|
||||||
info.Data is UserDisconnectEventData userDisconnect ? userDisconnect.Reason : UserDisconnectReason.Leave
|
info.Data is UserDisconnectEventData userDisconnect ? userDisconnect.Reason : UserDisconnectReason.Leave
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -73,6 +76,86 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
break;
|
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":
|
case "user:kickban":
|
||||||
if(info.Data is not UserKickBanEventData userBaka)
|
if(info.Data is not UserKickBanEventData userBaka)
|
||||||
break;
|
break;
|
||||||
|
@ -108,7 +191,7 @@ namespace SharpChat {
|
||||||
case "chan:join":
|
case "chan:join":
|
||||||
SendTo(info.ChannelName, new UserChannelJoinS2CPacket(
|
SendTo(info.ChannelName, new UserChannelJoinS2CPacket(
|
||||||
info.SenderId,
|
info.SenderId,
|
||||||
userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo),
|
SockChatUtility.GetUserName(info, userStatusInfo),
|
||||||
info.SenderColour,
|
info.SenderColour,
|
||||||
info.SenderRank,
|
info.SenderRank,
|
||||||
info.SenderPerms
|
info.SenderPerms
|
||||||
|
@ -219,86 +302,10 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChannelInfo[] GetUserChannels(UserInfo user) {
|
|
||||||
return Channels.GetMany(ChannelsUsers.GetUserChannelNames(user));
|
|
||||||
}
|
|
||||||
|
|
||||||
public UserInfo[] GetChannelUsers(ChannelInfo channel) {
|
public UserInfo[] GetChannelUsers(ChannelInfo channel) {
|
||||||
return Users.GetMany(ChannelsUsers.GetChannelUserIds(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<ISockChatS2CPacket> handler) {
|
public void HandleChannelEventLog(string channelName, Action<ISockChatS2CPacket> handler) {
|
||||||
foreach(ChatEventInfo info in EventStorage.GetChannelEventLog(channelName)) {
|
foreach(ChatEventInfo info in EventStorage.GetChannelEventLog(channelName)) {
|
||||||
switch(info.Type) {
|
switch(info.Type) {
|
||||||
|
@ -339,6 +346,16 @@ namespace SharpChat {
|
||||||
));
|
));
|
||||||
break;
|
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":
|
case "chan:join":
|
||||||
handler(new UserChannelJoinLogS2CPacket(
|
handler(new UserChannelJoinLogS2CPacket(
|
||||||
info.Id,
|
info.Id,
|
||||||
|
@ -362,9 +379,11 @@ namespace SharpChat {
|
||||||
if(!ChannelsUsers.Has(chan, user))
|
if(!ChannelsUsers.Has(chan, user))
|
||||||
Events.Dispatch("user:connect", chan, user);
|
Events.Dispatch("user:connect", chan, user);
|
||||||
|
|
||||||
|
UserStatusInfo statusInfo = UserStatuses.Get(user);
|
||||||
|
|
||||||
conn.Send(new AuthSuccessS2CPacket(
|
conn.Send(new AuthSuccessS2CPacket(
|
||||||
user.UserId,
|
user.UserId,
|
||||||
SockChatUtility.GetUserNameWithStatus(user),
|
SockChatUtility.GetUserName(user, statusInfo),
|
||||||
user.Colour,
|
user.Colour,
|
||||||
user.Rank,
|
user.Rank,
|
||||||
user.Permissions,
|
user.Permissions,
|
||||||
|
@ -374,7 +393,7 @@ namespace SharpChat {
|
||||||
conn.Send(new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
|
conn.Send(new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
|
||||||
user => new UsersPopulateS2CPacket.ListEntry(
|
user => new UsersPopulateS2CPacket.ListEntry(
|
||||||
user.UserId,
|
user.UserId,
|
||||||
SockChatUtility.GetUserNameWithStatus(user),
|
SockChatUtility.GetUserName(user, statusInfo),
|
||||||
user.Colour,
|
user.Colour,
|
||||||
user.Rank,
|
user.Rank,
|
||||||
user.Permissions,
|
user.Permissions,
|
||||||
|
@ -430,7 +449,7 @@ namespace SharpChat {
|
||||||
SendTo(user, new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
|
SendTo(user, new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
|
||||||
user => new UsersPopulateS2CPacket.ListEntry(
|
user => new UsersPopulateS2CPacket.ListEntry(
|
||||||
user.UserId,
|
user.UserId,
|
||||||
SockChatUtility.GetUserNameWithStatus(user),
|
SockChatUtility.GetUserName(user, UserStatuses.Get(user)),
|
||||||
user.Colour,
|
user.Colour,
|
||||||
user.Rank,
|
user.Rank,
|
||||||
user.Permissions,
|
user.Permissions,
|
||||||
|
@ -494,7 +513,11 @@ namespace SharpChat {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendToUserChannels(UserInfo user, ISockChatS2CPacket packet) {
|
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();
|
string data = packet.Pack();
|
||||||
foreach(ChannelInfo chan in chans)
|
foreach(ChannelInfo chan in chans)
|
||||||
SendTo(chan, data);
|
SendTo(chan, data);
|
||||||
|
|
|
@ -21,25 +21,30 @@ namespace SharpChat.SockChat {
|
||||||
return name.Length < 1 || ChannelName.IsMatch(name);
|
return name.Length < 1 || ChannelName.IsMatch(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetUserName(UserInfo info) {
|
public static string GetUserName(UserInfo info, UserStatusInfo? statusInfo = null) {
|
||||||
return string.IsNullOrWhiteSpace(info.NickName) ? info.UserName : $"~{info.NickName}";
|
string name = string.IsNullOrWhiteSpace(info.NickName) ? info.UserName : $"~{info.NickName}";
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetUserNameWithStatus(UserInfo info) {
|
if(statusInfo?.Status == UserStatus.Away)
|
||||||
string name = GetUserName(info);
|
|
||||||
|
|
||||||
if(info.Status == UserStatus.Away)
|
|
||||||
name = string.Format(
|
name = string.Format(
|
||||||
"<{0}>_{1}",
|
"<{0}>_{1}",
|
||||||
info.StatusText[..Math.Min(info.StatusText.Length, 5)].ToUpperInvariant(),
|
statusInfo.Text[..Math.Min(statusInfo.Text.Length, 5)].ToUpperInvariant(),
|
||||||
name
|
name
|
||||||
);
|
);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetUserName(ChatEventInfo info) {
|
public static string GetUserName(ChatEventInfo info, UserStatusInfo? statusInfo = null) {
|
||||||
return string.IsNullOrWhiteSpace(info.SenderNickName) ? info.SenderName : $"~{info.SenderNickName}";
|
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) {
|
public static (string, UsersContext.NameTarget) ExplodeUserName(string name) {
|
||||||
|
|
|
@ -3,7 +3,6 @@ using SharpChat.Events;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace SharpChat.EventStorage {
|
namespace SharpChat.EventStorage {
|
||||||
|
@ -91,7 +90,7 @@ namespace SharpChat.EventStorage {
|
||||||
reader.GetInt64("event_id"),
|
reader.GetInt64("event_id"),
|
||||||
eventType,
|
eventType,
|
||||||
DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")),
|
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")) ? -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_name")) ? string.Empty : reader.GetString("event_sender_name"),
|
||||||
reader.IsDBNull(reader.GetOrdinal("event_sender_colour")) ? Colour.None : Colour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
reader.IsDBNull(reader.GetOrdinal("event_sender_colour")) ? Colour.None : Colour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
||||||
|
|
17
SharpChatCommon/Events/UserStatusUpdateEventData.cs
Normal file
17
SharpChatCommon/Events/UserStatusUpdateEventData.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
SharpChatCommon/Events/UserUpdateEventData.cs
Normal file
45
SharpChatCommon/Events/UserUpdateEventData.cs
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,8 +11,6 @@
|
||||||
public UserPermissions Permissions { get; set; }
|
public UserPermissions Permissions { get; set; }
|
||||||
public bool IsSuper { get; set; }
|
public bool IsSuper { get; set; }
|
||||||
public string NickName { get; set; }
|
public string NickName { get; set; }
|
||||||
public UserStatus Status { get; set; }
|
|
||||||
public string StatusText { get; set; }
|
|
||||||
|
|
||||||
public UserInfo(
|
public UserInfo(
|
||||||
long userId,
|
long userId,
|
||||||
|
@ -21,8 +19,6 @@
|
||||||
int rank,
|
int rank,
|
||||||
UserPermissions perms,
|
UserPermissions perms,
|
||||||
string? nickName = null,
|
string? nickName = null,
|
||||||
UserStatus status = UserStatus.Online,
|
|
||||||
string? statusText = null,
|
|
||||||
bool isSuper = false
|
bool isSuper = false
|
||||||
) {
|
) {
|
||||||
UserId = userId;
|
UserId = userId;
|
||||||
|
@ -31,8 +27,6 @@
|
||||||
Rank = rank;
|
Rank = rank;
|
||||||
Permissions = perms;
|
Permissions = perms;
|
||||||
NickName = nickName ?? string.Empty;
|
NickName = nickName ?? string.Empty;
|
||||||
Status = status;
|
|
||||||
StatusText = statusText ?? string.Empty;
|
|
||||||
IsSuper = isSuper;
|
IsSuper = isSuper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
namespace SharpChat {
|
namespace SharpChat {
|
||||||
public enum UserStatus {
|
public enum UserStatus : int {
|
||||||
Online,
|
Unknown = 0,
|
||||||
Away,
|
Online = 1,
|
||||||
Offline,
|
Away = 2,
|
||||||
|
Offline = 3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
39
SharpChatCommon/UserStatusContext.cs
Normal file
39
SharpChatCommon/UserStatusContext.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SharpChat {
|
||||||
|
public class UserStatusContext {
|
||||||
|
private readonly Dictionary<long, UserStatusInfo> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
SharpChatCommon/UserStatusInfo.cs
Normal file
16
SharpChatCommon/UserStatusInfo.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
using SharpChat.SockChat;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue