using System.Net; using CollabVMSharp; using MySqlConnector; namespace EmperorPalpatine; public class Database { private readonly string connstr; public Database(ConfigDatabase config) { connstr = new MySqlConnectionStringBuilder { Server = config.Host, UserID = config.Username, Password = config.Password, Database = config.Database, }.ToString(); } public async Task InitAsync() { await using var db = new MySqlConnection(connstr); await db.OpenAsync(); using var cmd = db.CreateCommand(); cmd.CommandText = """ CREATE TABLE IF NOT EXISTS chatlogs ( vm TEXT NOT NULL, username TEXT NOT NULL, message TEXT NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) """; await cmd.ExecuteNonQueryAsync(); cmd.CommandText = """ CREATE TABLE IF NOT EXISTS iplog ( vm TEXT NOT NULL, username TEXT NOT NULL, ip varbinary(16) NOT NULL, date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) """; await cmd.ExecuteNonQueryAsync(); } public async Task LogChatMessageAsync(string vm, string username, string message) { await using var db = new MySqlConnection(connstr); await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "INSERT INTO chatlogs (vm, username, message) VALUES (@vm, @username, @message)"; cmd.Parameters.AddWithValue("@vm", vm); cmd.Parameters.AddWithValue("@username", username); cmd.Parameters.AddWithValue("@message", message); await cmd.ExecuteNonQueryAsync(); } public async Task LogIPAsync(string vm, string username, IPAddress ip) { await using var db = new MySqlConnection(connstr); await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT COUNT(ip) FROM iplog WHERE ip = @ip AND date >= DATE_SUB(NOW(), INTERVAL 1 HOUR) AND vm = @vm AND username = @username"; cmd.Parameters.AddWithValue("@ip", ip.GetAddressBytes()); cmd.Parameters.AddWithValue("@vm", vm); cmd.Parameters.AddWithValue("@username", username); var count = (long)await cmd.ExecuteScalarAsync(); if (count > 0) return; cmd.CommandText = "INSERT INTO iplog (vm, username, ip) VALUES (@vm, @username, @ip)"; await cmd.ExecuteNonQueryAsync(); } public async Task GetChatlogsAsync(ChatlogQuery q) { await using var db = new MySqlConnection(connstr); await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT * FROM chatlogs"; List where = new(); if (q.VM != null) { where.Add("vm = @vm"); cmd.Parameters.AddWithValue("@vm", q.VM); } if (q.Username != null) { where.Add("username = @username"); cmd.Parameters.AddWithValue("@username", q.Username); } if (q.FromTimestamp != null) { where.Add("date >= @from"); cmd.Parameters.AddWithValue("@from", q.FromTimestamp); } if (q.ToTimestamp != null) { where.Add("date <= @to"); cmd.Parameters.AddWithValue("@to", q.ToTimestamp); } if (q.Regex != null) { where.Add("message REGEXP @regex"); cmd.Parameters.AddWithValue("@regex", q.Regex); } if (q.CustomWhere != null) where.AddRange(q.CustomWhere); if (where.Count > 0) { cmd.CommandText += " WHERE " + string.Join(" AND ", where); } if (q.Count != null) { cmd.CommandText += $" ORDER BY {(q.Random ? "RAND()" : "date DESC")} LIMIT @count"; cmd.Parameters.AddWithValue("@count", q.Count); } await using var reader = await cmd.ExecuteReaderAsync(); List logs = new(); while (await reader.ReadAsync()) { logs.Add(new LoggedChatMessage { VM = reader.GetString(0), Username = reader.GetString(1), Message = reader.GetString(2), Timestamp = reader.GetDateTime(3).ToString("yyyy-MM-dd HH:mm:ss") }); } if (q.Count != null) logs.Reverse(); return logs.ToArray(); } public async Task GetIPFromUsernameAsync(string username) { await using var db = new MySqlConnection(connstr); await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT * FROM iplog WHERE username = @username"; cmd.Parameters.AddWithValue("@username", username); await using var reader = await cmd.ExecuteReaderAsync(); List logs = new(); while (await reader.ReadAsync()) { logs.Add(new LoggedIP { VM = reader.GetString(0), Username = reader.GetString(1), IP = new IPAddress(reader.GetFieldValue(2)).ToString(), Timestamp = reader.GetDateTime(3).ToString("yyyy-MM-dd HH:mm:ss") }); } return logs.ToArray(); } public async Task GetUsernameFromIPAsync(IPAddress ip) { await using var db = new MySqlConnection(connstr); await db.OpenAsync(); await using var cmd = db.CreateCommand(); cmd.CommandText = "SELECT * FROM iplog WHERE ip = @ip"; cmd.Parameters.AddWithValue("@ip", ip.GetAddressBytes()); await using var reader = await cmd.ExecuteReaderAsync(); List logs = new(); while (await reader.ReadAsync()) { logs.Add(new LoggedIP { VM = reader.GetString(0), Username = reader.GetString(1), IP = new IPAddress(reader.GetFieldValue(2)).ToString(), Timestamp = reader.GetDateTime(3).ToString("yyyy-MM-dd HH:mm:ss") }); } return logs.ToArray(); } }