2022-08-30 15:00:58 +00:00
|
|
|
|
using MySqlConnector;
|
|
|
|
|
using SharpChat.Events;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
|
|
|
|
namespace SharpChat {
|
|
|
|
|
public static partial class Database {
|
|
|
|
|
private static string ConnectionString = null;
|
|
|
|
|
|
|
|
|
|
public static bool HasDatabase
|
|
|
|
|
=> !string.IsNullOrWhiteSpace(ConnectionString);
|
|
|
|
|
|
|
|
|
|
public static void ReadConfig() {
|
2023-02-08 03:17:07 +00:00
|
|
|
|
if(!File.Exists("mariadb.txt"))
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return;
|
2023-02-08 03:17:07 +00:00
|
|
|
|
string[] config = File.ReadAllLines("mariadb.txt");
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(config.Length < 4)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return;
|
|
|
|
|
Init(config[0], config[1], config[2], config[3]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Init(string host, string username, string password, string database) {
|
|
|
|
|
ConnectionString = new MySqlConnectionStringBuilder {
|
|
|
|
|
Server = host,
|
|
|
|
|
UserID = username,
|
|
|
|
|
Password = password,
|
|
|
|
|
Database = database,
|
|
|
|
|
OldGuids = false,
|
|
|
|
|
TreatTinyAsBoolean = false,
|
2023-02-08 03:17:07 +00:00
|
|
|
|
CharacterSet = "utf8mb4",
|
2022-08-30 15:00:58 +00:00
|
|
|
|
SslMode = MySqlSslMode.None,
|
|
|
|
|
ForceSynchronous = true,
|
|
|
|
|
ConnectionTimeout = 5,
|
|
|
|
|
}.ToString();
|
|
|
|
|
RunMigrations();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Deinit() {
|
|
|
|
|
ConnectionString = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static MySqlConnection GetConnection() {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(!HasDatabase)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return null;
|
|
|
|
|
|
2023-02-07 15:01:56 +00:00
|
|
|
|
MySqlConnection conn = new(ConnectionString);
|
2022-08-30 15:00:58 +00:00
|
|
|
|
conn.Open();
|
|
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int RunCommand(string command, params MySqlParameter[] parameters) {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(!HasDatabase)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
using MySqlConnection conn = GetConnection();
|
|
|
|
|
using MySqlCommand cmd = conn.CreateCommand();
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(parameters?.Length > 0)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
cmd.Parameters.AddRange(parameters);
|
|
|
|
|
cmd.CommandText = command;
|
|
|
|
|
return cmd.ExecuteNonQuery();
|
2023-02-07 15:01:56 +00:00
|
|
|
|
} catch(MySqlException ex) {
|
2022-08-30 15:00:58 +00:00
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static MySqlDataReader RunQuery(string command, params MySqlParameter[] parameters) {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(!HasDatabase)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
MySqlConnection conn = GetConnection();
|
|
|
|
|
MySqlCommand cmd = conn.CreateCommand();
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(parameters?.Length > 0)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
cmd.Parameters.AddRange(parameters);
|
|
|
|
|
cmd.CommandText = command;
|
|
|
|
|
return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
|
|
|
|
|
} catch(MySqlException ex) {
|
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static object RunQueryValue(string command, params MySqlParameter[] parameters) {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(!HasDatabase)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
using MySqlConnection conn = GetConnection();
|
|
|
|
|
using MySqlCommand cmd = conn.CreateCommand();
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(parameters?.Length > 0)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
cmd.Parameters.AddRange(parameters);
|
|
|
|
|
cmd.CommandText = command;
|
|
|
|
|
cmd.Prepare();
|
|
|
|
|
return cmd.ExecuteScalar();
|
|
|
|
|
} catch(MySqlException ex) {
|
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private const long ID_EPOCH = 1588377600000;
|
|
|
|
|
private static int IdCounter = 0;
|
|
|
|
|
|
|
|
|
|
public static long GenerateId() {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(IdCounter > 200)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
IdCounter = 0;
|
|
|
|
|
|
|
|
|
|
long id = 0;
|
|
|
|
|
id |= (DateTimeOffset.Now.ToUnixTimeMilliseconds() - ID_EPOCH) << 8;
|
|
|
|
|
id |= (ushort)(++IdCounter);
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LogEvent(IChatEvent evt) {
|
|
|
|
|
if(evt.SequenceId < 1)
|
|
|
|
|
evt.SequenceId = GenerateId();
|
|
|
|
|
|
|
|
|
|
RunCommand(
|
2023-02-08 03:17:07 +00:00
|
|
|
|
"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.Target.TargetName),
|
|
|
|
|
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)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void DeleteEvent(IChatEvent evt) {
|
|
|
|
|
RunCommand(
|
2023-02-08 03:17:07 +00:00
|
|
|
|
"UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL",
|
|
|
|
|
new MySqlParameter("id", evt.SequenceId)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static IChatEvent ReadEvent(MySqlDataReader reader, IPacketTarget target = null) {
|
2023-02-08 03:17:07 +00:00
|
|
|
|
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");
|
2022-08-30 15:00:58 +00:00
|
|
|
|
evt.Target = target;
|
2023-02-08 03:17:07 +00:00
|
|
|
|
evt.TargetName = target?.TargetName ?? Encoding.ASCII.GetString((byte[])reader["event_target"]);
|
|
|
|
|
evt.Flags = (ChatMessageFlags)reader.GetByte("event_flags");
|
|
|
|
|
evt.DateTime = DateTimeOffset.FromUnixTimeSeconds(reader.GetInt32("event_created"));
|
2022-08-30 15:00:58 +00:00
|
|
|
|
|
2023-02-08 03:17:07 +00:00
|
|
|
|
if(!reader.IsDBNull(reader.GetOrdinal("event_sender"))) {
|
2022-08-30 15:00:58 +00:00
|
|
|
|
evt.Sender = new BasicUser {
|
2023-02-08 03:17:07 +00:00
|
|
|
|
UserId = reader.GetInt64("event_sender"),
|
|
|
|
|
Username = reader.GetString("event_sender_name"),
|
|
|
|
|
Colour = ChatColour.FromMisuzu(reader.GetInt32("event_sender_colour")),
|
|
|
|
|
Rank = reader.GetInt32("event_sender_rank"),
|
|
|
|
|
Nickname = reader.IsDBNull(reader.GetOrdinal("event_sender_nick")) ? null : reader.GetString("event_sender_nick"),
|
|
|
|
|
Permissions = (ChatUserPermissions)reader.GetInt32("event_sender_perms")
|
2022-08-30 15:00:58 +00:00
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return evt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IEnumerable<IChatEvent> GetEvents(IPacketTarget target, int amount, int offset) {
|
2023-02-07 15:01:56 +00:00
|
|
|
|
List<IChatEvent> events = new();
|
2022-08-30 15:00:58 +00:00
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
using MySqlDataReader reader = RunQuery(
|
2023-02-08 03:17:07 +00:00
|
|
|
|
"SELECT `event_id`, `event_type`, `event_flags`, `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_target` = @target"
|
|
|
|
|
+ " AND `event_id` > @offset"
|
|
|
|
|
+ " ORDER BY `event_id` DESC"
|
|
|
|
|
+ " LIMIT @amount",
|
|
|
|
|
new MySqlParameter("target", target.TargetName),
|
|
|
|
|
new MySqlParameter("amount", amount),
|
|
|
|
|
new MySqlParameter("offset", offset)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
);
|
|
|
|
|
|
2023-02-07 15:01:56 +00:00
|
|
|
|
while(reader.Read()) {
|
2022-08-30 15:00:58 +00:00
|
|
|
|
IChatEvent evt = ReadEvent(reader, target);
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(evt != null)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
events.Add(evt);
|
|
|
|
|
}
|
|
|
|
|
} catch(MySqlException ex) {
|
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static IChatEvent GetEvent(long seqId) {
|
|
|
|
|
try {
|
|
|
|
|
using MySqlDataReader reader = RunQuery(
|
2023-02-08 03:17:07 +00:00
|
|
|
|
"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)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
);
|
|
|
|
|
|
2023-02-07 15:01:56 +00:00
|
|
|
|
while(reader.Read()) {
|
2022-08-30 15:00:58 +00:00
|
|
|
|
IChatEvent evt = ReadEvent(reader);
|
2023-02-07 15:01:56 +00:00
|
|
|
|
if(evt != null)
|
2022-08-30 15:00:58 +00:00
|
|
|
|
return evt;
|
|
|
|
|
}
|
|
|
|
|
} catch(MySqlException ex) {
|
|
|
|
|
Logger.Write(ex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|