2022-08-30 15:00:58 +00:00
|
|
|
|
using MySqlConnector;
|
2024-05-24 03:44:20 +00:00
|
|
|
|
using SharpChat.Events;
|
2022-08-30 15:00:58 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2024-05-24 03:44:20 +00:00
|
|
|
|
using System.Reflection;
|
2022-08-30 15:00:58 +00:00
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
2024-05-19 01:53:14 +00:00
|
|
|
|
namespace SharpChat.EventStorage {
|
2023-02-10 06:07:59 +00:00
|
|
|
|
public partial class MariaDBEventStorage : IEventStorage {
|
|
|
|
|
private string ConnectionString { get; }
|
2022-08-30 15:00:58 +00:00
|
|
|
|
|
2024-05-24 03:44:20 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 06:07:59 +00:00
|
|
|
|
public MariaDBEventStorage(string connString) {
|
2024-05-19 01:53:14 +00:00
|
|
|
|
ConnectionString = connString;
|
2022-08-30 15:00:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-24 03:44:20 +00:00
|
|
|
|
public void HandleEvent(ChatEventInfo info) {
|
2022-08-30 15:00:58 +00:00
|
|
|
|
RunCommand(
|
2024-05-24 16:01:11 +00:00
|
|
|
|
"INSERT INTO sqc_events (event_id, event_type, event_created, event_channel, event_data"
|
|
|
|
|
+ ", event_sender, event_sender_name, event_sender_colour, event_sender_rank, event_sender_nick, event_sender_perms"
|
|
|
|
|
+ ") VALUES (@id, @type, FROM_UNIXTIME(@created), @channel, @data"
|
|
|
|
|
+ ", @senderId, @senderName, @senderColour, @senderRank, @senderNickName, @senderPerms)",
|
2024-05-24 03:44:20 +00:00
|
|
|
|
new MySqlParameter("id", info.Id),
|
|
|
|
|
new MySqlParameter("type", info.Type),
|
2024-05-24 16:01:11 +00:00
|
|
|
|
new MySqlParameter("created", info.Created.ToUnixTimeSeconds()),
|
|
|
|
|
new MySqlParameter("channel", string.IsNullOrWhiteSpace(info.ChannelName) ? null : info.ChannelName),
|
|
|
|
|
new MySqlParameter("data", JsonSerializer.Serialize(info.Data, info.Data.GetType(), jsonOpts)),
|
|
|
|
|
new MySqlParameter("senderId", info.SenderId < 1 ? null : info.SenderId),
|
|
|
|
|
new MySqlParameter("senderName", info.SenderName),
|
|
|
|
|
new MySqlParameter("senderColour", info.SenderColour.ToMisuzu()),
|
|
|
|
|
new MySqlParameter("senderRank", info.SenderRank),
|
|
|
|
|
new MySqlParameter("senderNickName", string.IsNullOrWhiteSpace(info.SenderNickName) ? null : info.SenderNickName),
|
|
|
|
|
new MySqlParameter("senderPerms", info.SenderPerms)
|
2023-07-23 21:31:13 +00:00
|
|
|
|
);
|
2024-05-24 03:44:20 +00:00
|
|
|
|
|
|
|
|
|
if(info.Type.Equals("msg:delete") && info.Data is MessageDeleteEventData msgDelete)
|
|
|
|
|
RunCommand(
|
2024-05-24 16:01:11 +00:00
|
|
|
|
"UPDATE IGNORE sqc_events SET event_deleted = NOW() WHERE event_id = @id AND event_deleted IS NULL",
|
2024-05-24 03:44:20 +00:00
|
|
|
|
new MySqlParameter("id", msgDelete.MessageId)
|
|
|
|
|
);
|
2023-07-23 21:31:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-24 03:44:20 +00:00
|
|
|
|
public ChatEventInfo? GetEvent(long eventId) {
|
2023-02-10 06:07:59 +00:00
|
|
|
|
try {
|
2024-05-10 19:18:55 +00:00
|
|
|
|
using MySqlDataReader? reader = RunQuery(
|
2024-05-24 16:01:11 +00:00
|
|
|
|
"SELECT event_id, event_type, event_channel, event_data"
|
|
|
|
|
+ ", event_sender, event_sender_name, event_sender_colour, event_sender_rank, event_sender_nick, event_sender_perms"
|
|
|
|
|
+ ", UNIX_TIMESTAMP(event_created) AS event_created, UNIX_TIMESTAMP(event_deleted) AS event_deleted"
|
|
|
|
|
+ " FROM sqc_events WHERE event_id = @id",
|
2024-05-24 03:44:20 +00:00
|
|
|
|
new MySqlParameter("id", eventId)
|
2023-02-10 06:07:59 +00:00
|
|
|
|
);
|
|
|
|
|
|
2024-05-10 19:18:55 +00:00
|
|
|
|
if(reader != null)
|
|
|
|
|
while(reader.Read()) {
|
2024-05-24 03:44:20 +00:00
|
|
|
|
ChatEventInfo evt = ReadEvent(reader);
|
2024-05-10 19:18:55 +00:00
|
|
|
|
if(evt != null)
|
|
|
|
|
return evt;
|
|
|
|
|
}
|
2023-02-10 06:07:59 +00:00
|
|
|
|
} catch(MySqlException ex) {
|
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
2022-08-30 15:00:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-24 03:44:20 +00:00
|
|
|
|
private static ChatEventInfo ReadEvent(MySqlDataReader reader) {
|
2024-05-24 16:01:11 +00:00
|
|
|
|
string eventType = reader.GetString("event_type");
|
2024-05-24 03:44:20 +00:00
|
|
|
|
ChatEventData eventData = EventDataTypes.ContainsKey(eventType)
|
2024-05-24 16:01:11 +00:00
|
|
|
|
? (ChatEventData)(JsonSerializer.Deserialize(reader.GetString("event_data"), EventDataTypes[eventType]) ?? ChatEventData.EmptyInstance)
|
2024-05-24 03:44:20 +00:00
|
|
|
|
: ChatEventData.EmptyInstance;
|
|
|
|
|
|
|
|
|
|
return new ChatEventInfo(
|
2023-02-23 21:46:49 +00:00
|
|
|
|
reader.GetInt64("event_id"),
|
2024-05-24 03:44:20 +00:00
|
|
|
|
eventType,
|
2023-02-23 21:46:49 +00:00
|
|
|
|
DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")),
|
2024-05-24 19:17:12 +00:00
|
|
|
|
reader.IsDBNull(reader.GetOrdinal("event_channel")) ? string.Empty : reader.GetString("event_channel"),
|
2024-05-24 03:44:20 +00:00
|
|
|
|
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")),
|
2024-05-24 16:01:11 +00:00
|
|
|
|
reader.IsDBNull(reader.GetOrdinal("event_sender_rank")) ? 0 : reader.GetInt32("event_sender_rank"),
|
2024-05-24 03:44:20 +00:00
|
|
|
|
reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick"),
|
2024-05-24 16:01:11 +00:00
|
|
|
|
(UserPermissions)(reader.IsDBNull(reader.GetOrdinal("event_sender_perms")) ? 0 : reader.GetInt32("event_sender_perms")),
|
2024-05-24 03:44:20 +00:00
|
|
|
|
eventData
|
2023-02-23 21:46:49 +00:00
|
|
|
|
);
|
2022-08-30 15:00:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-24 16:01:11 +00:00
|
|
|
|
public IEnumerable<ChatEventInfo> GetChannelEventLog(string channelName, int amount = 20, int after = 0) {
|
2024-05-24 03:44:20 +00:00
|
|
|
|
List<ChatEventInfo> events = new();
|
2022-08-30 15:00:58 +00:00
|
|
|
|
|
|
|
|
|
try {
|
2024-05-10 19:18:55 +00:00
|
|
|
|
using MySqlDataReader? reader = RunQuery(
|
2024-05-24 16:01:11 +00:00
|
|
|
|
"SELECT event_id, event_type, event_channel, event_data"
|
|
|
|
|
+ ", event_sender, event_sender_name, event_sender_colour, event_sender_rank, event_sender_nick, event_sender_perms"
|
|
|
|
|
+ ", UNIX_TIMESTAMP(event_created) AS event_created"
|
|
|
|
|
+ " FROM sqc_events WHERE event_deleted IS NULL"
|
|
|
|
|
+ " AND (event_channel IS NULL OR event_channel = @channel)"
|
|
|
|
|
+ " AND event_id > @after"
|
|
|
|
|
+ " ORDER BY event_id DESC"
|
2023-02-08 03:17:07 +00:00
|
|
|
|
+ " LIMIT @amount",
|
2024-05-24 16:01:11 +00:00
|
|
|
|
new MySqlParameter("channel", channelName),
|
2023-02-08 03:17:07 +00:00
|
|
|
|
new MySqlParameter("amount", amount),
|
2024-05-24 16:01:11 +00:00
|
|
|
|
new MySqlParameter("after", after)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
);
|
|
|
|
|
|
2024-05-10 19:18:55 +00:00
|
|
|
|
if(reader != null)
|
|
|
|
|
while(reader.Read()) {
|
2024-05-24 03:44:20 +00:00
|
|
|
|
ChatEventInfo evt = ReadEvent(reader);
|
2024-05-10 19:18:55 +00:00
|
|
|
|
if(evt != null)
|
|
|
|
|
events.Add(evt);
|
|
|
|
|
}
|
2022-08-30 15:00:58 +00:00
|
|
|
|
} catch(MySqlException ex) {
|
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-10 06:18:38 +00:00
|
|
|
|
events.Reverse();
|
|
|
|
|
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|