using MySqlConnector; using SharpChat.Messages; using System.Text; using System.Text.Json; namespace SharpChat.MariaDB; public partial class MariaDBMessageStorage(string connString) : MessageStorage { private string ConnectionString { get; } = connString ?? throw new ArgumentNullException(nameof(connString)); 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, MessageFlags flags = MessageFlags.None ) { await RunCommand( "INSERT INTO `sqc_events` (`event_id`, `event_created`, `event_type`, `event_target`, `event_flags`, `event_data`" + ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`)" + " VALUES (@id, NOW(), @type, @target, @flags, @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("flags", (byte)flags), 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", ToStoredPermissions(senderPerms)) ); } public async Task<Message?> GetMessage(long seqId) { try { using MySqlDataReader? reader = await RunQuery( "SELECT `event_id`, `event_type`, `event_flags`, `event_data`, `event_target`" + ", `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", seqId) ); if(reader is null) return null; while(reader.Read()) { Message evt = ReadEvent(reader); if(evt != null) return evt; } } catch(MySqlException ex) { Logger.Write(ex); } return null; } private static Message ReadEvent(MySqlDataReader reader) { return new Message( reader.GetInt64("event_id"), Encoding.ASCII.GetString((byte[])reader["event_type"]), reader.IsDBNull(reader.GetOrdinal("event_sender")) ? null : reader.GetInt64("event_sender").ToString(), 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"), FromMessagePermissions((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_target")) ? null : Encoding.ASCII.GetString((byte[])reader["event_target"]), JsonDocument.Parse(Encoding.ASCII.GetString((byte[])reader["event_data"])), (MessageFlags)reader.GetByte("event_flags") ); } public async Task<IEnumerable<Message>> GetMessages(string channelName, int amount = 20, int offset = 0) { List<Message> events = []; try { using MySqlDataReader? reader = await RunQuery( "SELECT `event_id`, `event_type`, `event_flags`, `event_data`, `event_target`" + ", `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_target` = @target OR `event_target` IS NULL)" + " AND `event_id` > @offset" + " ORDER BY `event_id` DESC" + " LIMIT @amount", new MySqlParameter("target", channelName), new MySqlParameter("amount", amount), new MySqlParameter("offset", offset) ); if(reader is null) return events; while(reader.Read()) { Message evt = ReadEvent(reader); if(evt != null) events.Add(evt); } } catch(MySqlException ex) { Logger.Write(ex); } events.Reverse(); return events; } public async Task DeleteMessage(Message evt) { await RunCommand( "UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL", new MySqlParameter("id", evt.Id) ); } }