using MySqlConnector; using SharpChat.Events; using System; using System.Collections.Generic; using System.Text; using System.Text.Json; namespace SharpChat.EventStorage { public partial class MariaDBEventStorage : IEventStorage { private string ConnectionString { get; } public MariaDBEventStorage(string connString) { ConnectionString = connString ?? throw new ArgumentNullException(nameof(connString)); } public void AddEvent(IChatEvent evt) { if(evt == null) throw new ArgumentNullException(nameof(evt)); if(evt.SequenceId < 1) evt.SequenceId = SharpId.Next(); 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, FROM_UNIXTIME(@created), @type, @target, @flags, @data" + ", @sender, @sender_name, @sender_colour, @sender_rank, @sender_nick, @sender_perms)", new MySqlParameter("id", evt.SequenceId), new MySqlParameter("created", evt.DateTime.ToUnixTimeSeconds()), new MySqlParameter("type", evt.GetType().FullName), new MySqlParameter("target", evt.ChannelName), new MySqlParameter("flags", (byte)evt.Flags), new MySqlParameter("data", JsonSerializer.SerializeToUtf8Bytes(evt, evt.GetType())), new MySqlParameter("sender", evt.Sender?.UserId < 1 ? null : (long?)evt.Sender.UserId), new MySqlParameter("sender_name", evt.Sender?.UserName), new MySqlParameter("sender_colour", evt.Sender?.Colour.ToMisuzu()), new MySqlParameter("sender_rank", evt.Sender?.Rank), new MySqlParameter("sender_nick", evt.Sender?.NickName), new MySqlParameter("sender_perms", evt.Sender?.Permissions) ); } public IChatEvent GetEvent(long seqId) { try { using MySqlDataReader reader = 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`" + " FROM `sqc_events`" + " WHERE `event_id` = @id", new MySqlParameter("id", seqId) ); while(reader.Read()) { IChatEvent evt = ReadEvent(reader); if(evt != null) return evt; } } catch(MySqlException ex) { Logger.Write(ex); } return null; } private static IChatEvent ReadEvent(MySqlDataReader reader) { Type evtType = Type.GetType(Encoding.ASCII.GetString((byte[])reader["event_type"])); IChatEvent evt = JsonSerializer.Deserialize(Encoding.ASCII.GetString((byte[])reader["event_data"]), evtType) as IChatEvent; evt.SequenceId = reader.GetInt64("event_id"); evt.ChannelName = Encoding.ASCII.GetString((byte[])reader["event_target"]); evt.Flags = (ChatMessageFlags)reader.GetByte("event_flags"); evt.DateTime = DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created")); if(!reader.IsDBNull(reader.GetOrdinal("event_sender"))) { evt.Sender = new ChatUser( reader.GetInt64("event_sender"), reader.GetString("event_sender_name"), ChatColour.FromMisuzu(reader.GetInt32("event_sender_colour")), reader.GetInt32("event_sender_rank"), (ChatUserPermissions)reader.GetInt32("event_sender_perms"), reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick") ); } return evt; } public IEnumerable GetChannelEventLog(string channelName, int amount = 20, int offset = 0) { List events = new(); try { using MySqlDataReader reader = 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`" + " FROM `sqc_events`" + " WHERE `event_deleted` IS NULL AND `event_target` = @target" + " AND `event_id` > @offset" + " ORDER BY `event_id` DESC" + " LIMIT @amount", new MySqlParameter("target", channelName), new MySqlParameter("amount", amount), new MySqlParameter("offset", offset) ); while(reader.Read()) { IChatEvent evt = ReadEvent(reader); if(evt != null) events.Add(evt); } } catch(MySqlException ex) { Logger.Write(ex); } events.Reverse(); return events; } public void RemoveEvent(IChatEvent evt) { if(evt == null) throw new ArgumentNullException(nameof(evt)); RunCommand( "UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL", new MySqlParameter("id", evt.SequenceId) ); } } }