Events system overhaul.
This commit is contained in:
parent
454a460441
commit
5daad52aba
|
@ -1,5 +1,4 @@
|
|||
using SharpChat.Events;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.SockChat.Commands {
|
||||
|
@ -17,14 +16,7 @@ namespace SharpChat.SockChat.Commands {
|
|||
if(string.IsNullOrWhiteSpace(actionStr))
|
||||
return;
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
ctx.Channel,
|
||||
ctx.User,
|
||||
DateTimeOffset.Now,
|
||||
actionStr,
|
||||
false, true, false
|
||||
));
|
||||
ctx.Chat.Events.Dispatch("msg:add", ctx.Channel, ctx.User, new MessageAddEventData(actionStr, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using SharpChat.Events;
|
||||
using SharpChat.SockChat.PacketsS2C;
|
||||
using System;
|
||||
|
||||
namespace SharpChat.SockChat.Commands {
|
||||
public class MessageBroadcastCommand : ISockChatClientCommand {
|
||||
|
@ -15,14 +14,11 @@ namespace SharpChat.SockChat.Commands {
|
|||
return;
|
||||
}
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
string.Empty,
|
||||
ctx.Chat.Events.Dispatch(
|
||||
"msg:add",
|
||||
ctx.User,
|
||||
DateTimeOffset.Now,
|
||||
string.Join(' ', ctx.Args),
|
||||
false, false, true
|
||||
));
|
||||
new MessageAddEventData(string.Join(' ', ctx.Args))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using SharpChat.EventStorage;
|
||||
using SharpChat.Events;
|
||||
using SharpChat.SockChat.PacketsS2C;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -21,20 +21,22 @@ namespace SharpChat.SockChat.Commands {
|
|||
|
||||
string? firstArg = ctx.Args.FirstOrDefault();
|
||||
|
||||
if(string.IsNullOrWhiteSpace(firstArg) || !firstArg.All(char.IsDigit) || !long.TryParse(firstArg, out long delSeqId)) {
|
||||
if(string.IsNullOrWhiteSpace(firstArg) || !firstArg.All(char.IsDigit) || !long.TryParse(firstArg, out long eventId)) {
|
||||
ctx.Chat.SendTo(ctx.User, new CommandFormatErrorS2CPacket());
|
||||
return;
|
||||
}
|
||||
|
||||
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
|
||||
ChatEventInfo? eventInfo = ctx.Chat.EventStorage.GetEvent(eventId);
|
||||
|
||||
if(delMsg == null || delMsg.Sender?.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender?.UserId != ctx.User.UserId)) {
|
||||
if(eventInfo == null
|
||||
|| !eventInfo.Type.Equals("msg:add")
|
||||
|| eventInfo.SenderRank > ctx.User.Rank
|
||||
|| (!deleteAnyMessage && eventInfo.SenderId != ctx.User.UserId)) {
|
||||
ctx.Chat.SendTo(ctx.User, new MessageDeleteNotAllowedErrorS2CPacket());
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.Chat.Events.RemoveEvent(delMsg);
|
||||
ctx.Chat.Send(new MessageDeleteS2CPacket(delMsg.Id));
|
||||
ctx.Chat.Events.Dispatch("msg:delete", eventInfo.ChannelName, ctx.User, new MessageDeleteEventData(eventInfo.Id.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using SharpChat.Events;
|
||||
using SharpChat.SockChat.PacketsS2C;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace SharpChat.SockChat.Commands {
|
||||
|
@ -28,14 +27,12 @@ namespace SharpChat.SockChat.Commands {
|
|||
if(whisperUser == ctx.User)
|
||||
return;
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
ctx.Chat.Events.Dispatch(
|
||||
"msg:add",
|
||||
UserInfo.GetDMChannelName(ctx.User, whisperUser),
|
||||
ctx.User,
|
||||
DateTimeOffset.Now,
|
||||
string.Join(' ', ctx.Args.Skip(1)),
|
||||
true, false, false
|
||||
));
|
||||
new MessageAddEventData(string.Join(' ', ctx.Args.Skip(1)))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using SharpChat.Config;
|
||||
using SharpChat.Events;
|
||||
using SharpChat.SockChat.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
|
@ -80,14 +79,7 @@ namespace SharpChat.SockChat.PacketsC2S {
|
|||
}
|
||||
}
|
||||
|
||||
ctx.Chat.DispatchEvent(new MessageCreateEvent(
|
||||
SharpId.Next(),
|
||||
channelInfo,
|
||||
user,
|
||||
DateTimeOffset.Now,
|
||||
messageText,
|
||||
false, false, false
|
||||
));
|
||||
ctx.Chat.Events.Dispatch("msg:add", channelInfo, user, new MessageAddEventData(messageText));
|
||||
} finally {
|
||||
ctx.Chat.ContextAccess.Release();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
namespace SharpChat.SockChat.PacketsS2C {
|
||||
public class MessageDeleteS2CPacket : ISockChatS2CPacket {
|
||||
private readonly long DeletedMessageId;
|
||||
private readonly string DeletedMessageId;
|
||||
|
||||
public MessageDeleteS2CPacket(long deletedMessageId) {
|
||||
public MessageDeleteS2CPacket(string deletedMessageId) {
|
||||
DeletedMessageId = deletedMessageId;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,79 +5,133 @@ using SharpChat.SockChat.PacketsS2C;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
namespace SharpChat {
|
||||
public class SockChatContext {
|
||||
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 Events { get; }
|
||||
public IEventStorage EventStorage { get; }
|
||||
public ChatEventDispatcher Events { get; } = new();
|
||||
public ChannelsUsersContext ChannelsUsers { get; } = new();
|
||||
public Dictionary<long, RateLimiter> UserRateLimiters { get; } = new();
|
||||
|
||||
public SockChatContext(IEventStorage evtStore) {
|
||||
Events = evtStore;
|
||||
EventStorage = evtStore;
|
||||
Events.Subscribe(evtStore);
|
||||
Events.Subscribe(this);
|
||||
}
|
||||
|
||||
public void DispatchEvent(IChatEvent eventInfo) {
|
||||
if(eventInfo is MessageCreateEvent mce) {
|
||||
if(mce.IsBroadcast) {
|
||||
Send(new MessageBroadcastS2CPacket(mce.MessageId, mce.MessageCreated, 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
|
||||
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);
|
||||
|
||||
// this entire routine is garbage, channels should probably in the db
|
||||
if(mce.ChannelName?.StartsWith("@") != true)
|
||||
return;
|
||||
switch(info.Type) {
|
||||
case "user:connect":
|
||||
SendTo(info.ChannelName, new UserConnectS2CPacket(
|
||||
info.Id,
|
||||
info.Created,
|
||||
info.SenderId,
|
||||
userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo),
|
||||
info.SenderColour,
|
||||
info.SenderRank,
|
||||
info.SenderPerms
|
||||
));
|
||||
break;
|
||||
|
||||
long[] targetIds = mce.ChannelName[1..].Split('-', 3).Select(u => long.TryParse(u, out long up) ? up : -1).ToArray();
|
||||
case "user:disconnect":
|
||||
SendTo(info.ChannelName, new UserDisconnectS2CPacket(
|
||||
info.Id,
|
||||
info.Created,
|
||||
info.SenderId,
|
||||
userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo),
|
||||
info.Data is UserDisconnectEventData userDisconnect ? userDisconnect.Reason : UserDisconnectReason.Leave
|
||||
));
|
||||
break;
|
||||
|
||||
case "chan:join":
|
||||
SendTo(info.ChannelName, new UserChannelJoinS2CPacket(
|
||||
info.SenderId,
|
||||
userInfo == null ? SockChatUtility.GetUserName(info) : SockChatUtility.GetUserNameWithStatus(userInfo),
|
||||
info.SenderColour,
|
||||
info.SenderRank,
|
||||
info.SenderPerms
|
||||
));
|
||||
break;
|
||||
|
||||
case "chan:leave":
|
||||
SendTo(info.ChannelName, new UserChannelLeaveS2CPacket(info.SenderId));
|
||||
break;
|
||||
|
||||
case "msg:delete":
|
||||
if(info.Data is not MessageDeleteEventData msgDelete)
|
||||
break;
|
||||
|
||||
MessageDeleteS2CPacket msgDelPacket = new(msgDelete.MessageId);
|
||||
|
||||
if(info.IsBroadcast) {
|
||||
Send(msgDelPacket);
|
||||
} else if(info.ChannelName.StartsWith('@')) {
|
||||
long[] targetIds = info.ChannelName[1..].Split('-', 3).Select(u => long.TryParse(u, out long up) ? up : -1).ToArray();
|
||||
if(targetIds.Length != 2)
|
||||
return;
|
||||
|
||||
UserInfo[] users = Users.GetMany(targetIds);
|
||||
UserInfo? target = users.FirstOrDefault(u => u.UserId != mce.SenderId);
|
||||
UserInfo? target = users.FirstOrDefault(u => u.UserId != info.SenderId);
|
||||
if(target == null)
|
||||
return;
|
||||
|
||||
foreach(UserInfo user in users)
|
||||
SendTo(user, msgDelPacket);
|
||||
} else {
|
||||
SendTo(info.ChannelName, msgDelPacket);
|
||||
}
|
||||
break;
|
||||
|
||||
case "msg:add":
|
||||
if(info.Data is not MessageAddEventData msgAdd)
|
||||
break;
|
||||
|
||||
if(info.IsBroadcast) {
|
||||
Send(new MessageBroadcastS2CPacket(info.Id, info.Created, msgAdd.Text));
|
||||
} else if(info.ChannelName.StartsWith('@')) {
|
||||
// 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
|
||||
|
||||
long[] targetIds = info.ChannelName[1..].Split('-', 3).Select(u => long.TryParse(u, out long up) ? up : -1).ToArray();
|
||||
if(targetIds.Length != 2)
|
||||
return;
|
||||
|
||||
UserInfo[] users = Users.GetMany(targetIds);
|
||||
UserInfo? target = users.FirstOrDefault(u => u.UserId != info.SenderId);
|
||||
if(target == null)
|
||||
return;
|
||||
|
||||
foreach(UserInfo user in users)
|
||||
SendTo(user, new MessageAddS2CPacket(
|
||||
mce.MessageId,
|
||||
info.Id,
|
||||
DateTimeOffset.Now,
|
||||
mce.SenderId,
|
||||
mce.SenderId == user.UserId ? $"{SockChatUtility.GetUserName(target)} {mce.MessageText}" : mce.MessageText,
|
||||
mce.IsAction,
|
||||
info.SenderId,
|
||||
info.SenderId == user.UserId ? $"{SockChatUtility.GetUserName(target)} {msgAdd.Text}" : msgAdd.Text,
|
||||
msgAdd.IsAction,
|
||||
true
|
||||
));
|
||||
} else {
|
||||
ChannelInfo? channel = Channels.Get(mce.ChannelName, SockChatUtility.SanitiseChannelName);
|
||||
ChannelInfo? channel = Channels.Get(info.ChannelName, SockChatUtility.SanitiseChannelName);
|
||||
if(channel != null)
|
||||
SendTo(channel, new MessageAddS2CPacket(
|
||||
mce.MessageId,
|
||||
info.Id,
|
||||
DateTimeOffset.Now,
|
||||
mce.SenderId,
|
||||
mce.MessageText,
|
||||
mce.IsAction,
|
||||
info.SenderId,
|
||||
msgAdd.Text,
|
||||
msgAdd.IsAction,
|
||||
false
|
||||
));
|
||||
}
|
||||
|
||||
object msgData = mce.IsAction
|
||||
? new { text = mce.MessageText, action = true }
|
||||
: new { text = mce.MessageText };
|
||||
|
||||
Events.AddEvent(
|
||||
mce.MessageId,
|
||||
"msg:add",
|
||||
mce.IsBroadcast ? null : mce.ChannelName,
|
||||
mce.SenderId, mce.SenderName, mce.SenderColour, mce.SenderRank, mce.SenderNickName, mce.SenderPerms,
|
||||
msgData
|
||||
);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,105 +261,81 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public void HandleChannelEventLog(string channelName, Action<ISockChatS2CPacket> handler) {
|
||||
foreach(StoredEventInfo msg in Events.GetChannelEventLog(channelName)) {
|
||||
ISockChatS2CPacket packet;
|
||||
foreach(ChatEventInfo info in EventStorage.GetChannelEventLog(channelName)) {
|
||||
ISockChatS2CPacket? packet;
|
||||
|
||||
switch(msg.Type) {
|
||||
switch(info.Type) {
|
||||
case "msg:add":
|
||||
string maText = string.Empty;
|
||||
if(msg.Data.RootElement.TryGetProperty("text", out JsonElement maTextElem))
|
||||
maText = maTextElem.ToString();
|
||||
|
||||
bool maAction = false;
|
||||
if(msg.Data.RootElement.TryGetProperty("action", out JsonElement maIsActionElem))
|
||||
maAction = maIsActionElem.ValueKind == JsonValueKind.True;
|
||||
|
||||
if(info.Data is MessageAddEventData messageAdd) {
|
||||
maText = messageAdd.Text;
|
||||
maAction = messageAdd.IsAction;
|
||||
}
|
||||
|
||||
packet = new MessageAddLogS2CPacket(
|
||||
msg.Id,
|
||||
msg.Created,
|
||||
msg.Sender?.UserId ?? -1,
|
||||
msg.Sender == null ? "ChatBot" : SockChatUtility.GetUserName(msg.Sender),
|
||||
msg.Sender?.Colour ?? Colour.None,
|
||||
msg.Sender?.Rank ?? 0,
|
||||
msg.Sender?.Permissions ?? 0,
|
||||
info.Id,
|
||||
info.Created,
|
||||
info.SenderId,
|
||||
info.SenderName,
|
||||
info.SenderColour,
|
||||
info.SenderRank,
|
||||
info.SenderPerms,
|
||||
maText,
|
||||
maAction,
|
||||
msg.ChannelName?.StartsWith('@') == true,
|
||||
msg.ChannelName == null,
|
||||
info.ChannelName.StartsWith('@'),
|
||||
info.IsBroadcast,
|
||||
false
|
||||
);
|
||||
break;
|
||||
|
||||
case "user:connect":
|
||||
packet = new UserConnectLogS2CPacket(
|
||||
msg.Id,
|
||||
msg.Created,
|
||||
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
|
||||
info.Id,
|
||||
info.Created,
|
||||
SockChatUtility.GetUserName(info)
|
||||
);
|
||||
break;
|
||||
|
||||
case "user:disconnect":
|
||||
UserDisconnectReason udReason = 0;
|
||||
if(msg.Data.RootElement.TryGetProperty("reason", out JsonElement udElem) && udElem.TryGetByte(out byte udReasonRaw))
|
||||
udReason = (UserDisconnectReason)udReasonRaw;
|
||||
|
||||
packet = new UserDisconnectLogS2CPacket(
|
||||
msg.Id,
|
||||
msg.Created,
|
||||
msg.Sender == null ? string.Empty : SockChatUtility.GetUserNameWithStatus(msg.Sender),
|
||||
udReason
|
||||
info.Id,
|
||||
info.Created,
|
||||
SockChatUtility.GetUserName(info),
|
||||
info.Data is UserDisconnectEventData userDisconnect ? userDisconnect.Reason : UserDisconnectReason.Leave
|
||||
);
|
||||
break;
|
||||
|
||||
case "chan:join":
|
||||
packet = new UserChannelJoinLogS2CPacket(
|
||||
msg.Id,
|
||||
msg.Created,
|
||||
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
|
||||
info.Id,
|
||||
info.Created,
|
||||
SockChatUtility.GetUserName(info)
|
||||
);
|
||||
break;
|
||||
|
||||
case "chan:leave":
|
||||
packet = new UserChannelLeaveLogS2CPacket(
|
||||
msg.Id,
|
||||
msg.Created,
|
||||
msg.Sender == null ? string.Empty : SockChatUtility.GetUserName(msg.Sender)
|
||||
info.Id,
|
||||
info.Created,
|
||||
SockChatUtility.GetUserName(info)
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception($"Unsupported backlog type: {msg.Type}");
|
||||
packet = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if(packet != null)
|
||||
handler(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public void HandleJoin(UserInfo user, ChannelInfo chan, SockChatConnectionInfo conn, int maxMsgLength) {
|
||||
if(!ChannelsUsers.Has(chan, user)) {
|
||||
long eventId = SharpId.Next();
|
||||
SendTo(chan, new UserConnectS2CPacket(
|
||||
eventId,
|
||||
DateTimeOffset.UtcNow,
|
||||
user.UserId,
|
||||
SockChatUtility.GetUserNameWithStatus(user),
|
||||
user.Colour,
|
||||
user.Rank,
|
||||
user.Permissions
|
||||
));
|
||||
Events.AddEvent(
|
||||
eventId,
|
||||
"user:connect",
|
||||
chan.Name,
|
||||
user.UserId,
|
||||
user.UserName,
|
||||
user.Colour,
|
||||
user.Rank,
|
||||
user.NickName,
|
||||
user.Permissions,
|
||||
null
|
||||
);
|
||||
}
|
||||
if(!ChannelsUsers.Has(chan, user))
|
||||
Events.Dispatch("user:connect", chan, user);
|
||||
|
||||
conn.Send(new AuthSuccessS2CPacket(
|
||||
user.UserId,
|
||||
|
@ -347,26 +377,7 @@ namespace SharpChat {
|
|||
ChannelsUsers.DeleteUser(user);
|
||||
|
||||
foreach(ChannelInfo chan in channels) {
|
||||
long eventId = SharpId.Next();
|
||||
SendTo(chan, new UserDisconnectS2CPacket(
|
||||
eventId,
|
||||
DateTimeOffset.UtcNow,
|
||||
user.UserId,
|
||||
SockChatUtility.GetUserNameWithStatus(user),
|
||||
reason
|
||||
));
|
||||
Events.AddEvent(
|
||||
eventId,
|
||||
"user:disconnect",
|
||||
chan.Name,
|
||||
user.UserId,
|
||||
user.UserName,
|
||||
user.Colour,
|
||||
user.Rank,
|
||||
user.NickName,
|
||||
user.Permissions,
|
||||
new { reason = (int)reason }
|
||||
);
|
||||
Events.Dispatch("user:disconnect", chan, user, new UserDisconnectEventData(reason));
|
||||
|
||||
if(chan.IsTemporary && chan.IsOwner(user))
|
||||
RemoveChannel(chan);
|
||||
|
@ -397,45 +408,13 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public void ForceChannelSwitch(UserInfo user, ChannelInfo chan) {
|
||||
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||
ChannelInfo? oldChan = Channels.Get(ChannelsUsers.GetUserLastChannel(user));
|
||||
|
||||
if(oldChan != null) {
|
||||
SendTo(oldChan, new UserChannelLeaveS2CPacket(user.UserId));
|
||||
Events.AddEvent(
|
||||
SharpId.Next(),
|
||||
"chan:leave",
|
||||
oldChan.Name,
|
||||
user.UserId,
|
||||
user.UserName,
|
||||
user.Colour,
|
||||
user.Rank,
|
||||
user.NickName,
|
||||
user.Permissions,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
SendTo(chan, new UserChannelJoinS2CPacket(
|
||||
user.UserId,
|
||||
SockChatUtility.GetUserNameWithStatus(user),
|
||||
user.Colour,
|
||||
user.Rank,
|
||||
user.Permissions
|
||||
));
|
||||
|
||||
if(oldChan != null)
|
||||
Events.AddEvent(
|
||||
SharpId.Next(),
|
||||
"chan:join",
|
||||
oldChan.Name,
|
||||
user.UserId,
|
||||
user.UserName,
|
||||
user.Colour,
|
||||
user.Rank,
|
||||
user.NickName,
|
||||
user.Permissions,
|
||||
null
|
||||
);
|
||||
Events.Dispatch("chan:leave", now, oldChan, user);
|
||||
|
||||
Events.Dispatch("chan:join", now, chan, user);
|
||||
|
||||
SendTo(user, new ContextClearS2CPacket(ContextClearS2CPacket.ClearMode.MessagesUsers));
|
||||
SendTo(user, new UsersPopulateS2CPacket(GetChannelUsers(chan).Except(new[] { user }).Select(
|
||||
|
@ -481,7 +460,15 @@ namespace SharpChat {
|
|||
}
|
||||
|
||||
public void SendTo(ChannelInfo channel, string packet) {
|
||||
long[] userIds = ChannelsUsers.GetChannelUserIds(channel);
|
||||
SendTo(channel.Name, packet);
|
||||
}
|
||||
|
||||
public void SendTo(string channelName, ISockChatS2CPacket packet) {
|
||||
SendTo(channelName, packet.Pack());
|
||||
}
|
||||
|
||||
public void SendTo(string channelName, string packet) {
|
||||
long[] userIds = ChannelsUsers.GetChannelUserIds(channelName);
|
||||
foreach(long userId in userIds)
|
||||
Connections.WithUser(userId, conn => {
|
||||
if(conn is SockChatConnectionInfo scConn)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using SharpChat.Events;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SharpChat.SockChat {
|
||||
|
@ -37,6 +38,10 @@ namespace SharpChat.SockChat {
|
|||
return name;
|
||||
}
|
||||
|
||||
public static string GetUserName(ChatEventInfo info) {
|
||||
return string.IsNullOrWhiteSpace(info.SenderNickName) ? info.SenderName : $"~{info.SenderNickName}";
|
||||
}
|
||||
|
||||
public static (string, UsersContext.NameTarget) ExplodeUserName(string name) {
|
||||
UsersContext.NameTarget target = UsersContext.NameTarget.UserName;
|
||||
|
||||
|
|
|
@ -1,22 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
using SharpChat.Events;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
public interface IEventStorage {
|
||||
void AddEvent(
|
||||
long id,
|
||||
string type,
|
||||
string? channelName,
|
||||
long senderId,
|
||||
string? senderName,
|
||||
Colour senderColour,
|
||||
int senderRank,
|
||||
string? senderNick,
|
||||
UserPermissions senderPerms,
|
||||
object? data = null
|
||||
);
|
||||
|
||||
void RemoveEvent(StoredEventInfo evt);
|
||||
StoredEventInfo? GetEvent(long seqId);
|
||||
IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int startAt = 0);
|
||||
public interface IEventStorage : IChatEventHandler {
|
||||
ChatEventInfo? GetEvent(long eventId);
|
||||
IEnumerable<ChatEventInfo> GetChannelEventLog(string channelName, int amount = 20, int startAt = 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using MySqlConnector;
|
||||
using SharpChat.Events;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
|
@ -8,41 +10,58 @@ namespace SharpChat.EventStorage {
|
|||
public partial class MariaDBEventStorage : IEventStorage {
|
||||
private string ConnectionString { get; }
|
||||
|
||||
private readonly JsonSerializerOptions jsonOpts = new() {
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault,
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, Type> EventDataTypes = new();
|
||||
|
||||
static MariaDBEventStorage() {
|
||||
foreach(Type type in Assembly.GetExecutingAssembly().GetTypes()) {
|
||||
ChatEventDataForAttribute? forAttr = type.GetCustomAttribute<ChatEventDataForAttribute>();
|
||||
if(forAttr == null)
|
||||
continue;
|
||||
if(EventDataTypes.ContainsKey(forAttr.EventName))
|
||||
throw new InvalidOperationException($"Attempted to register more than one data type for {forAttr.EventName}!");
|
||||
|
||||
EventDataTypes.Add(forAttr.EventName, type);
|
||||
}
|
||||
}
|
||||
|
||||
public MariaDBEventStorage(string connString) {
|
||||
ConnectionString = connString;
|
||||
}
|
||||
|
||||
public void AddEvent(
|
||||
long id,
|
||||
string type,
|
||||
string? channelName,
|
||||
long senderId,
|
||||
string? senderName,
|
||||
Colour senderColour,
|
||||
int senderRank,
|
||||
string? senderNick,
|
||||
UserPermissions senderPerms,
|
||||
object? data = null
|
||||
) {
|
||||
public void HandleEvent(ChatEventInfo info) {
|
||||
MySqlParameter dataParam = new("data", MySqlDbType.Blob) {
|
||||
Value = JsonSerializer.SerializeToUtf8Bytes(info.Data, info.Data.GetType(), jsonOpts)
|
||||
};
|
||||
|
||||
RunCommand(
|
||||
"INSERT INTO `sqc_events` (`event_id`, `event_created`, `event_type`, `event_target`, `event_data`"
|
||||
+ ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`)"
|
||||
+ " VALUES (@id, NOW(), @type, @target, @data"
|
||||
+ ", @sender, @sender_name, @sender_colour, @sender_rank, @sender_nick, @sender_perms)",
|
||||
new MySqlParameter("id", id),
|
||||
new MySqlParameter("type", type),
|
||||
new MySqlParameter("target", string.IsNullOrWhiteSpace(channelName) ? null : channelName),
|
||||
new MySqlParameter("data", data == null ? "{}" : JsonSerializer.SerializeToUtf8Bytes(data)),
|
||||
new MySqlParameter("sender", senderId < 1 ? null : senderId),
|
||||
new MySqlParameter("sender_name", senderName),
|
||||
new MySqlParameter("sender_colour", senderColour.ToMisuzu()),
|
||||
new MySqlParameter("sender_rank", senderRank),
|
||||
new MySqlParameter("sender_nick", string.IsNullOrWhiteSpace(senderNick) ? null : senderNick),
|
||||
new MySqlParameter("sender_perms", senderPerms)
|
||||
new MySqlParameter("id", info.Id),
|
||||
new MySqlParameter("type", info.Type),
|
||||
new MySqlParameter("target", string.IsNullOrWhiteSpace(info.ChannelName) ? null : info.ChannelName),
|
||||
dataParam,
|
||||
new MySqlParameter("sender", info.SenderId < 1 ? null : info.SenderId),
|
||||
new MySqlParameter("sender_name", info.SenderName),
|
||||
new MySqlParameter("sender_colour", info.SenderColour.ToMisuzu()),
|
||||
new MySqlParameter("sender_rank", info.SenderRank),
|
||||
new MySqlParameter("sender_nick", info.SenderNickName),
|
||||
new MySqlParameter("sender_perms", info.SenderPerms)
|
||||
);
|
||||
|
||||
if(info.Type.Equals("msg:delete") && info.Data is MessageDeleteEventData msgDelete)
|
||||
RunCommand(
|
||||
"UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL",
|
||||
new MySqlParameter("id", msgDelete.MessageId)
|
||||
);
|
||||
}
|
||||
|
||||
public StoredEventInfo? GetEvent(long seqId) {
|
||||
public ChatEventInfo? GetEvent(long eventId) {
|
||||
try {
|
||||
using MySqlDataReader? reader = RunQuery(
|
||||
"SELECT `event_id`, `event_type`, `event_data`, `event_target`"
|
||||
|
@ -51,12 +70,12 @@ namespace SharpChat.EventStorage {
|
|||
+ ", UNIX_TIMESTAMP(`event_deleted`) AS `event_deleted`"
|
||||
+ " FROM `sqc_events`"
|
||||
+ " WHERE `event_id` = @id",
|
||||
new MySqlParameter("id", seqId)
|
||||
new MySqlParameter("id", eventId)
|
||||
);
|
||||
|
||||
if(reader != null)
|
||||
while(reader.Read()) {
|
||||
StoredEventInfo evt = ReadEvent(reader);
|
||||
ChatEventInfo evt = ReadEvent(reader);
|
||||
if(evt != null)
|
||||
return evt;
|
||||
}
|
||||
|
@ -67,27 +86,29 @@ namespace SharpChat.EventStorage {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static StoredEventInfo ReadEvent(MySqlDataReader reader) {
|
||||
return new StoredEventInfo(
|
||||
private static ChatEventInfo ReadEvent(MySqlDataReader reader) {
|
||||
string eventType = Encoding.ASCII.GetString((byte[])reader["event_type"]);
|
||||
ChatEventData eventData = EventDataTypes.ContainsKey(eventType)
|
||||
? (ChatEventData)(JsonSerializer.Deserialize((byte[])reader["event_data"], EventDataTypes[eventType]) ?? ChatEventData.EmptyInstance)
|
||||
: ChatEventData.EmptyInstance;
|
||||
|
||||
return new ChatEventInfo(
|
||||
reader.GetInt64("event_id"),
|
||||
Encoding.ASCII.GetString((byte[])reader["event_type"]),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_sender")) ? null : new UserInfo(
|
||||
reader.GetInt64("event_sender"),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_sender_name")) ? string.Empty : reader.GetString("event_sender_name"),
|
||||
Colour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
||||
reader.GetInt32("event_sender_rank"),
|
||||
(UserPermissions)reader.GetInt32("event_sender_perms"),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick")
|
||||
),
|
||||
eventType,
|
||||
DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_deleted")) ? null : DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_deleted")),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_target")) ? null : Encoding.ASCII.GetString((byte[])reader["event_target"]),
|
||||
JsonDocument.Parse(Encoding.ASCII.GetString((byte[])reader["event_data"]))
|
||||
reader.IsDBNull(reader.GetOrdinal("event_target")) ? string.Empty : Encoding.ASCII.GetString((byte[])reader["event_target"]),
|
||||
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")),
|
||||
reader.GetInt32("event_sender_rank"),
|
||||
reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick"),
|
||||
(UserPermissions)reader.GetInt32("event_sender_perms"),
|
||||
eventData
|
||||
);
|
||||
}
|
||||
|
||||
public IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int startAt = 0) {
|
||||
List<StoredEventInfo> events = new();
|
||||
public IEnumerable<ChatEventInfo> GetChannelEventLog(string channelName, int amount = 20, int startAt = 0) {
|
||||
List<ChatEventInfo> events = new();
|
||||
|
||||
try {
|
||||
using MySqlDataReader? reader = RunQuery(
|
||||
|
@ -107,7 +128,7 @@ namespace SharpChat.EventStorage {
|
|||
|
||||
if(reader != null)
|
||||
while(reader.Read()) {
|
||||
StoredEventInfo evt = ReadEvent(reader);
|
||||
ChatEventInfo evt = ReadEvent(reader);
|
||||
if(evt != null)
|
||||
events.Add(evt);
|
||||
}
|
||||
|
@ -119,12 +140,5 @@ namespace SharpChat.EventStorage {
|
|||
|
||||
return events;
|
||||
}
|
||||
|
||||
public void RemoveEvent(StoredEventInfo evt) {
|
||||
RunCommand(
|
||||
"UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL",
|
||||
new MySqlParameter("id", evt.Id)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
public class StoredEventInfo {
|
||||
public long Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
public UserInfo? Sender { get; set; }
|
||||
public DateTimeOffset Created { get; set; }
|
||||
public DateTimeOffset? Deleted { get; set; }
|
||||
public string? ChannelName { get; set; }
|
||||
public JsonDocument Data { get; set; }
|
||||
|
||||
public StoredEventInfo(
|
||||
long id,
|
||||
string type,
|
||||
UserInfo? sender,
|
||||
DateTimeOffset created,
|
||||
DateTimeOffset? deleted,
|
||||
string? channelName,
|
||||
JsonDocument data
|
||||
) {
|
||||
Id = id;
|
||||
Type = type;
|
||||
Sender = sender;
|
||||
Created = created;
|
||||
Deleted = deleted;
|
||||
ChannelName = channelName;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,46 +1,24 @@
|
|||
using System;
|
||||
using SharpChat.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SharpChat.EventStorage {
|
||||
public class VirtualEventStorage : IEventStorage {
|
||||
private readonly Dictionary<long, StoredEventInfo> Events = new();
|
||||
private readonly Dictionary<string, ChatEventInfo> Events = new();
|
||||
|
||||
public void AddEvent(
|
||||
long id,
|
||||
string type,
|
||||
string? channelName,
|
||||
long senderId,
|
||||
string? senderName,
|
||||
Colour senderColour,
|
||||
int senderRank,
|
||||
string? senderNick,
|
||||
UserPermissions senderPerms,
|
||||
object? data = null
|
||||
) {
|
||||
// VES is meant as an emergency fallback but this is something else
|
||||
JsonDocument hack = JsonDocument.Parse(data == null ? "{}" : JsonSerializer.Serialize(data));
|
||||
Events.Add(id, new(id, type, senderId < 1 ? null : new UserInfo(
|
||||
senderId,
|
||||
senderName ?? string.Empty,
|
||||
senderColour,
|
||||
senderRank,
|
||||
senderPerms,
|
||||
senderNick
|
||||
), DateTimeOffset.Now, null, channelName, hack));
|
||||
public void HandleEvent(ChatEventInfo info) {
|
||||
Events.Add(info.Id.ToString(), info);
|
||||
|
||||
if(info.Type.Equals("msg:delete") && info.Data is MessageDeleteEventData msgDelete)
|
||||
Events.Remove(msgDelete.MessageId);
|
||||
}
|
||||
|
||||
public StoredEventInfo? GetEvent(long seqId) {
|
||||
return Events.TryGetValue(seqId, out StoredEventInfo? evt) ? evt : null;
|
||||
public ChatEventInfo? GetEvent(long eventId) {
|
||||
return Events.TryGetValue(eventId.ToString(), out ChatEventInfo? evt) ? evt : null;
|
||||
}
|
||||
|
||||
public void RemoveEvent(StoredEventInfo evt) {
|
||||
Events.Remove(evt.Id);
|
||||
}
|
||||
|
||||
public IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int startAt = 0) {
|
||||
IEnumerable<StoredEventInfo> subset = Events.Values.Where(ev => ev.ChannelName == channelName);
|
||||
public IEnumerable<ChatEventInfo> GetChannelEventLog(string channelName, int amount = 20, int startAt = 0) {
|
||||
IEnumerable<ChatEventInfo> subset = Events.Values.Where(ev => ev.ChannelName == channelName);
|
||||
|
||||
int start = subset.Count() - startAt - amount;
|
||||
if(start < 0) {
|
||||
|
|
8
SharpChatCommon/Events/ChatEventData.cs
Normal file
8
SharpChatCommon/Events/ChatEventData.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
public class ChatEventData {
|
||||
[JsonIgnore]
|
||||
public static readonly ChatEventData EmptyInstance = new();
|
||||
}
|
||||
}
|
12
SharpChatCommon/Events/ChatEventDataForAttribute.cs
Normal file
12
SharpChatCommon/Events/ChatEventDataForAttribute.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public class ChatEventDataForAttribute : Attribute {
|
||||
public string EventName { get; }
|
||||
|
||||
public ChatEventDataForAttribute(string eventName) {
|
||||
EventName = eventName;
|
||||
}
|
||||
}
|
||||
}
|
88
SharpChatCommon/Events/ChatEventDispatcher.cs
Normal file
88
SharpChatCommon/Events/ChatEventDispatcher.cs
Normal file
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
public class ChatEventDispatcher {
|
||||
private readonly object HandlersAccess = new();
|
||||
private readonly List<IChatEventHandler> Handlers = new();
|
||||
|
||||
public void Subscribe(IChatEventHandler handler) {
|
||||
lock(HandlersAccess)
|
||||
if(!Handlers.Contains(handler))
|
||||
Handlers.Add(handler);
|
||||
}
|
||||
|
||||
public void Unsubscribe(IChatEventHandler handler) {
|
||||
lock(HandlersAccess)
|
||||
Handlers.Remove(handler);
|
||||
}
|
||||
|
||||
public ChatEventInfo Dispatch(ChatEventInfo info) {
|
||||
lock(HandlersAccess)
|
||||
foreach(IChatEventHandler handler in Handlers)
|
||||
handler.HandleEvent(info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public ChatEventInfo Dispatch(
|
||||
string eventType,
|
||||
DateTimeOffset eventCreated,
|
||||
ChannelInfo channelInfo,
|
||||
UserInfo userInfo,
|
||||
ChatEventData? eventData = null
|
||||
) {
|
||||
return Dispatch(new ChatEventInfo(
|
||||
SharpId.Next(),
|
||||
eventType,
|
||||
eventCreated,
|
||||
channelInfo.Name,
|
||||
userInfo.UserId,
|
||||
userInfo.UserName,
|
||||
userInfo.Colour,
|
||||
userInfo.Rank,
|
||||
userInfo.NickName,
|
||||
userInfo.Permissions,
|
||||
eventData
|
||||
));
|
||||
}
|
||||
|
||||
public ChatEventInfo Dispatch(
|
||||
string eventType,
|
||||
string channelName,
|
||||
UserInfo userInfo,
|
||||
ChatEventData? eventData = null
|
||||
) {
|
||||
return Dispatch(new ChatEventInfo(
|
||||
SharpId.Next(),
|
||||
eventType,
|
||||
DateTimeOffset.UtcNow,
|
||||
channelName,
|
||||
userInfo.UserId,
|
||||
userInfo.UserName,
|
||||
userInfo.Colour,
|
||||
userInfo.Rank,
|
||||
userInfo.NickName,
|
||||
userInfo.Permissions,
|
||||
eventData
|
||||
));
|
||||
}
|
||||
|
||||
public ChatEventInfo Dispatch(
|
||||
string eventType,
|
||||
ChannelInfo channelInfo,
|
||||
UserInfo userInfo,
|
||||
ChatEventData? eventData = null
|
||||
) {
|
||||
return Dispatch(eventType, channelInfo.Name, userInfo, eventData);
|
||||
}
|
||||
|
||||
public ChatEventInfo Dispatch(
|
||||
string eventType,
|
||||
UserInfo userInfo,
|
||||
ChatEventData? eventData = null
|
||||
) {
|
||||
return Dispatch(eventType, string.Empty, userInfo, eventData);
|
||||
}
|
||||
}
|
||||
}
|
45
SharpChatCommon/Events/ChatEventInfo.cs
Normal file
45
SharpChatCommon/Events/ChatEventInfo.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
public class ChatEventInfo {
|
||||
public long Id { get; }
|
||||
public string Type { get; }
|
||||
public DateTimeOffset Created { get; }
|
||||
public string ChannelName { get; }
|
||||
public long SenderId { get; }
|
||||
public string SenderName { get; }
|
||||
public Colour SenderColour { get; }
|
||||
public int SenderRank { get; }
|
||||
public string? SenderNickName { get; }
|
||||
public UserPermissions SenderPerms { get; }
|
||||
public ChatEventData Data { get; }
|
||||
|
||||
public bool IsBroadcast => string.IsNullOrWhiteSpace(ChannelName);
|
||||
|
||||
public ChatEventInfo(
|
||||
long id,
|
||||
string type,
|
||||
DateTimeOffset created,
|
||||
string channelName,
|
||||
long senderId,
|
||||
string senderName,
|
||||
Colour senderColour,
|
||||
int senderRank,
|
||||
string? senderNickName,
|
||||
UserPermissions senderPerms,
|
||||
ChatEventData? data = null
|
||||
) {
|
||||
Id = id;
|
||||
Type = type;
|
||||
Created = created;
|
||||
ChannelName = channelName;
|
||||
SenderId = senderId;
|
||||
SenderName = senderName;
|
||||
SenderColour = senderColour;
|
||||
SenderRank = senderRank;
|
||||
SenderNickName = senderNickName;
|
||||
SenderPerms = senderPerms;
|
||||
Data = data ?? ChatEventData.EmptyInstance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
namespace SharpChat.Events {
|
||||
public interface IChatEvent {
|
||||
}
|
||||
}
|
5
SharpChatCommon/Events/IChatEventHandler.cs
Normal file
5
SharpChatCommon/Events/IChatEventHandler.cs
Normal file
|
@ -0,0 +1,5 @@
|
|||
namespace SharpChat.Events {
|
||||
public interface IChatEventHandler {
|
||||
void HandleEvent(ChatEventInfo info);
|
||||
}
|
||||
}
|
17
SharpChatCommon/Events/MessageAddEventData.cs
Normal file
17
SharpChatCommon/Events/MessageAddEventData.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
[ChatEventDataFor("msg:add")]
|
||||
public class MessageAddEventData : ChatEventData {
|
||||
[JsonPropertyName("text")]
|
||||
public string Text { get; }
|
||||
|
||||
[JsonPropertyName("action")]
|
||||
public bool IsAction { get; }
|
||||
|
||||
public MessageAddEventData(string text, bool isAction = false) {
|
||||
Text = text;
|
||||
IsAction = isAction;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
public class MessageCreateEvent : IChatEvent {
|
||||
public long MessageId { get; }
|
||||
public string? ChannelName { get; }
|
||||
public long SenderId { get; }
|
||||
public string? SenderName { get; }
|
||||
public Colour SenderColour { get; }
|
||||
public int SenderRank { get; }
|
||||
public string? SenderNickName { get; }
|
||||
public UserPermissions SenderPerms { get; }
|
||||
public DateTimeOffset MessageCreated { get; }
|
||||
public string MessageText { get; }
|
||||
public bool IsPrivate { get; }
|
||||
public bool IsAction { get; }
|
||||
public bool IsBroadcast { get; }
|
||||
|
||||
public MessageCreateEvent(
|
||||
long msgId,
|
||||
string? channelName,
|
||||
long senderId,
|
||||
string? senderName,
|
||||
Colour senderColour,
|
||||
int senderRank,
|
||||
string? senderNickName,
|
||||
UserPermissions senderPerms,
|
||||
DateTimeOffset msgCreated,
|
||||
string msgText,
|
||||
bool isPrivate,
|
||||
bool isAction,
|
||||
bool isBroadcast
|
||||
) {
|
||||
MessageId = msgId;
|
||||
ChannelName = channelName;
|
||||
SenderId = senderId;
|
||||
SenderName = senderName;
|
||||
SenderColour = senderColour;
|
||||
SenderRank = senderRank;
|
||||
SenderNickName = senderNickName;
|
||||
SenderPerms = senderPerms;
|
||||
MessageCreated = msgCreated;
|
||||
MessageText = msgText;
|
||||
IsPrivate = isPrivate;
|
||||
IsAction = isAction;
|
||||
IsBroadcast = isBroadcast;
|
||||
}
|
||||
|
||||
public MessageCreateEvent(
|
||||
long msgId,
|
||||
string? channelName,
|
||||
UserInfo? sender,
|
||||
DateTimeOffset msgCreated,
|
||||
string msgText,
|
||||
bool isPrivate,
|
||||
bool isAction,
|
||||
bool isBroadcast
|
||||
) : this(
|
||||
msgId,
|
||||
channelName,
|
||||
sender?.UserId ?? -1,
|
||||
sender?.UserName ?? null,
|
||||
sender?.Colour ?? Colour.None,
|
||||
sender?.Rank ?? 0,
|
||||
sender?.NickName ?? null,
|
||||
sender?.Permissions ?? 0,
|
||||
msgCreated,
|
||||
msgText,
|
||||
isPrivate,
|
||||
isAction,
|
||||
isBroadcast
|
||||
) { }
|
||||
|
||||
public MessageCreateEvent(
|
||||
long msgId,
|
||||
ChannelInfo channel,
|
||||
UserInfo sender,
|
||||
DateTimeOffset msgCreated,
|
||||
string msgText,
|
||||
bool isPrivate,
|
||||
bool isAction,
|
||||
bool isBroadcast
|
||||
) : this(
|
||||
msgId,
|
||||
channel?.Name ?? null,
|
||||
sender,
|
||||
msgCreated,
|
||||
msgText,
|
||||
isPrivate,
|
||||
isAction,
|
||||
isBroadcast
|
||||
) { }
|
||||
}
|
||||
}
|
13
SharpChatCommon/Events/MessageDeleteEventData.cs
Normal file
13
SharpChatCommon/Events/MessageDeleteEventData.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
[ChatEventDataFor("msg:delete")]
|
||||
public class MessageDeleteEventData : ChatEventData {
|
||||
[JsonPropertyName("msg")]
|
||||
public string MessageId { get; }
|
||||
|
||||
public MessageDeleteEventData(string messageId) {
|
||||
MessageId = messageId;
|
||||
}
|
||||
}
|
||||
}
|
13
SharpChatCommon/Events/UserDisconnectEventData.cs
Normal file
13
SharpChatCommon/Events/UserDisconnectEventData.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharpChat.Events {
|
||||
[ChatEventDataFor("user:disconnect")]
|
||||
public class UserDisconnectEventData : ChatEventData {
|
||||
[JsonPropertyName("reason")]
|
||||
public UserDisconnectReason Reason { get; }
|
||||
|
||||
public UserDisconnectEventData(UserDisconnectReason reason) {
|
||||
Reason = reason;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
namespace SharpChat {
|
||||
public enum UserDisconnectReason {
|
||||
Leave,
|
||||
TimeOut,
|
||||
Kicked,
|
||||
Flood,
|
||||
public enum UserDisconnectReason : int {
|
||||
Leave = 0,
|
||||
TimeOut = 1,
|
||||
Kicked = 2,
|
||||
Flood = 3,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue