using MySqlConnector; using SharpChat.Messages; using System.Text.Json; namespace SharpChat.MariaDB; public class MariaDBMessageStorage(MariaDBStorage storage) : MessageStorage { public async Task LogMessage( long id, string type, string channelName, string senderId, string senderName, ColourInheritable senderColour, int senderRank, string senderNick, UserPermissions senderPerms, object? data = null ) { try { using MariaDBConnection conn = await storage.CreateConnection(); await conn.RunCommand( "INSERT INTO sqc_events (event_id, event_created, event_type, event_channel, event_data" + ", event_sender, event_sender_name, event_sender_colour, event_sender_rank, event_sender_nick, event_sender_perms)" + " VALUES (@id, NOW(), @type, @channel, @data" + ", @sender, @sender_name, @sender_colour, @sender_rank, @sender_nick, @sender_perms)", new MySqlParameter("id", id), new MySqlParameter("type", type), new MySqlParameter("channel", string.IsNullOrWhiteSpace(channelName) ? null : channelName), new MySqlParameter("data", data == null ? "{}" : JsonSerializer.SerializeToUtf8Bytes(data)), new MySqlParameter("sender", long.TryParse(senderId, out long senderId64) && senderId64 > 0 ? senderId64 : null), 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", MariaDBUserPermissionsConverter.To(senderPerms)) ); } catch(MySqlException ex) { Logger.Write(ex); } } public async Task DeleteMessage(Message msg) { try { using MariaDBConnection conn = await storage.CreateConnection(); await conn.RunCommand( "UPDATE IGNORE sqc_events SET event_deleted = NOW() WHERE event_id = @id AND event_deleted IS NULL", new MySqlParameter("id", msg.Id) ); } catch(MySqlException ex) { Logger.Write(ex); } } private static Message ReadMessage(MySqlDataReader reader) { using Stream data = reader.GetStream("event_data"); return new Message( reader.GetInt64("event_id"), reader.GetString("event_type"), reader.IsDBNull(reader.GetOrdinal("event_sender")) ? null : reader.GetString("event_sender"), reader.IsDBNull(reader.GetOrdinal("event_sender_name")) ? string.Empty : reader.GetString("event_sender_name"), ColourInheritable.FromMisuzu(reader.GetInt32("event_sender_colour")), reader.GetInt32("event_sender_rank"), MariaDBUserPermissionsConverter.From((MariaDBUserPermissions)reader.GetInt32("event_sender_perms")), reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? string.Empty : reader.GetString("event_sender_nick"), DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")), reader.IsDBNull(reader.GetOrdinal("event_deleted")) ? null : DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_deleted")), reader.IsDBNull(reader.GetOrdinal("event_channel")) ? null : reader.GetString("event_channel"), JsonDocument.Parse(data) ); } public async Task<Message?> GetMessage(long id) { try { using MariaDBConnection conn = await storage.CreateConnection(); using MySqlDataReader? reader = await conn.RunQuery( "SELECT event_id, event_type, event_data, event_channel" + ", 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", new MySqlParameter("id", id) ); if(reader is null) return null; while(reader.Read()) { Message evt = ReadMessage(reader); if(evt != null) return evt; } } catch(MySqlException ex) { Logger.Write(ex); } return null; } public async Task<IEnumerable<Message>> GetMessages(string channelName, int amount = 20, int offset = 0) { List<Message> msgs = []; try { using MariaDBConnection conn = await storage.CreateConnection(); using MySqlDataReader? reader = await conn.RunQuery( "SELECT event_id, event_type, event_data, event_channel" + ", 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_deleted IS NULL AND (event_channel = @channel OR event_channel IS NULL)" + " AND event_id > @offset" + " ORDER BY event_id DESC" + " LIMIT @amount", new MySqlParameter("channel", channelName), new MySqlParameter("amount", amount), new MySqlParameter("offset", offset) ); if(reader is null) return msgs; while(reader.Read()) { Message evt = ReadMessage(reader); if(evt != null) msgs.Add(evt); } } catch(MySqlException ex) { Logger.Write(ex); } msgs.Reverse(); return msgs; } }