Split MariaDB message storage out into its own library.
This commit is contained in:
parent
8eff4127b5
commit
f1d4051fb5
23 changed files with 255 additions and 228 deletions
129
SharpChat.MariaDB/MariaDBMessageStorage.cs
Normal file
129
SharpChat.MariaDB/MariaDBMessageStorage.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
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)
|
||||
);
|
||||
}
|
||||
}
|
87
SharpChat.MariaDB/MariaDBMessageStorage_Database.cs
Normal file
87
SharpChat.MariaDB/MariaDBMessageStorage_Database.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using MySqlConnector;
|
||||
using SharpChat.Configuration;
|
||||
|
||||
namespace SharpChat.MariaDB;
|
||||
|
||||
public partial class MariaDBMessageStorage {
|
||||
public static string BuildConnString(Config config) {
|
||||
return BuildConnString(
|
||||
config.ReadValue("host", "localhost"),
|
||||
config.ReadValue("user", string.Empty),
|
||||
config.ReadValue("pass", string.Empty),
|
||||
config.ReadValue("db", "sharpchat")
|
||||
);
|
||||
}
|
||||
|
||||
public static string BuildConnString(string? host, string? username, string? password, string? database) {
|
||||
return new MySqlConnectionStringBuilder {
|
||||
Server = host,
|
||||
UserID = username,
|
||||
Password = password,
|
||||
Database = database,
|
||||
OldGuids = false,
|
||||
TreatTinyAsBoolean = false,
|
||||
CharacterSet = "utf8mb4",
|
||||
SslMode = MySqlSslMode.None,
|
||||
ForceSynchronous = true,
|
||||
ConnectionTimeout = 5,
|
||||
DefaultCommandTimeout = 900, // fuck it, 15 minutes
|
||||
}.ToString();
|
||||
}
|
||||
|
||||
private async Task<MySqlConnection> GetConnection() {
|
||||
MySqlConnection conn = new(ConnectionString);
|
||||
await conn.OpenAsync();
|
||||
return conn;
|
||||
}
|
||||
|
||||
private async Task<int> RunCommand(string command, params MySqlParameter[] parameters) {
|
||||
try {
|
||||
using MySqlConnection conn = await GetConnection();
|
||||
using MySqlCommand cmd = conn.CreateCommand();
|
||||
if(parameters?.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
return await cmd.ExecuteNonQueryAsync();
|
||||
} catch(MySqlException ex) {
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private async Task<MySqlDataReader?> RunQuery(string command, params MySqlParameter[] parameters) {
|
||||
try {
|
||||
MySqlConnection conn = await GetConnection();
|
||||
MySqlCommand cmd = conn.CreateCommand();
|
||||
if(parameters?.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
return await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.CloseConnection);
|
||||
} catch(MySqlException ex) {
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<T> RunQueryValue<T>(string command, params MySqlParameter[] parameters)
|
||||
where T : struct {
|
||||
try {
|
||||
using MySqlConnection conn = await GetConnection();
|
||||
using MySqlCommand cmd = conn.CreateCommand();
|
||||
if(parameters?.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
await cmd.PrepareAsync();
|
||||
|
||||
object? raw = await cmd.ExecuteScalarAsync();
|
||||
if(raw is T value)
|
||||
return value;
|
||||
} catch(MySqlException ex) {
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
84
SharpChat.MariaDB/MariaDBMessageStorage_Migrations.cs
Normal file
84
SharpChat.MariaDB/MariaDBMessageStorage_Migrations.cs
Normal file
|
@ -0,0 +1,84 @@
|
|||
using MySqlConnector;
|
||||
|
||||
namespace SharpChat.MariaDB;
|
||||
|
||||
public partial class MariaDBMessageStorage {
|
||||
private async Task DoMigration(string name, Func<Task> action) {
|
||||
bool done = await RunQueryValue<long>(
|
||||
"SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name",
|
||||
new MySqlParameter("name", name)
|
||||
) > 0;
|
||||
if(!done) {
|
||||
Logger.Write($"Running migration '{name}'...");
|
||||
await action();
|
||||
await RunCommand(
|
||||
"INSERT INTO `sqc_migrations` (`migration_name`) VALUES (@name)",
|
||||
new MySqlParameter("name", name)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunMigrations() {
|
||||
await RunCommand(
|
||||
"CREATE TABLE IF NOT EXISTS `sqc_migrations` ("
|
||||
+ "`migration_name` VARCHAR(255) NOT NULL,"
|
||||
+ "`migration_completed` TIMESTAMP NOT NULL DEFAULT current_timestamp(),"
|
||||
+ "UNIQUE INDEX `migration_name` (`migration_name`),"
|
||||
+ "INDEX `migration_completed` (`migration_completed`)"
|
||||
+ ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;"
|
||||
);
|
||||
|
||||
await DoMigration("create_events_table", CreateEventsTable);
|
||||
await DoMigration("allow_null_target", AllowNullTarget);
|
||||
await DoMigration("event_data_as_medium_blob", EventDataAsMediumBlob);
|
||||
await DoMigration("event_user_and_nick_name_to_1000", EventUserAndNickNameTo1000);
|
||||
}
|
||||
|
||||
private async Task EventUserAndNickNameTo1000() {
|
||||
await RunCommand(
|
||||
"ALTER TABLE `sqc_events`"
|
||||
+ " CHANGE COLUMN `event_sender_name` `event_sender_name` VARCHAR(1000) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_520_ci' AFTER `event_sender`,"
|
||||
+ " CHANGE COLUMN `event_sender_nick` `event_sender_nick` VARCHAR(1000) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_520_ci' AFTER `event_sender_rank`;"
|
||||
);
|
||||
}
|
||||
|
||||
private async Task EventDataAsMediumBlob() {
|
||||
await RunCommand(
|
||||
"ALTER TABLE `sqc_events`"
|
||||
+ " CHANGE COLUMN `event_data` `event_data` MEDIUMBLOB NULL DEFAULT NULL AFTER `event_flags`;"
|
||||
);
|
||||
}
|
||||
|
||||
private async Task AllowNullTarget() {
|
||||
await RunCommand(
|
||||
"ALTER TABLE `sqc_events`"
|
||||
+ " CHANGE COLUMN `event_target` `event_target` VARBINARY(255) NULL AFTER `event_type`;"
|
||||
);
|
||||
}
|
||||
|
||||
private async Task CreateEventsTable() {
|
||||
await RunCommand(
|
||||
"CREATE TABLE `sqc_events` ("
|
||||
+ "`event_id` BIGINT(20) NOT NULL,"
|
||||
+ "`event_sender` BIGINT(20) UNSIGNED NULL DEFAULT NULL,"
|
||||
+ "`event_sender_name` VARCHAR(255) NULL DEFAULT NULL,"
|
||||
+ "`event_sender_colour` INT(11) NULL DEFAULT NULL,"
|
||||
+ "`event_sender_rank` INT(11) NULL DEFAULT NULL,"
|
||||
+ "`event_sender_nick` VARCHAR(255) NULL DEFAULT NULL,"
|
||||
+ "`event_sender_perms` INT(11) NULL DEFAULT NULL,"
|
||||
+ "`event_created` TIMESTAMP NOT NULL DEFAULT current_timestamp(),"
|
||||
+ "`event_deleted` TIMESTAMP NULL DEFAULT NULL,"
|
||||
+ "`event_type` VARBINARY(255) NOT NULL,"
|
||||
+ "`event_target` VARBINARY(255) NOT NULL,"
|
||||
+ "`event_flags` TINYINT(3) UNSIGNED NOT NULL,"
|
||||
+ "`event_data` BLOB NULL DEFAULT NULL,"
|
||||
+ "PRIMARY KEY (`event_id`),"
|
||||
+ "INDEX `event_target` (`event_target`),"
|
||||
+ "INDEX `event_type` (`event_type`),"
|
||||
+ "INDEX `event_sender` (`event_sender`),"
|
||||
+ "INDEX `event_datetime` (`event_created`),"
|
||||
+ "INDEX `event_deleted` (`event_deleted`)"
|
||||
+ ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;"
|
||||
);
|
||||
}
|
||||
}
|
101
SharpChat.MariaDB/MariaDBMessageStorage_Permissions.cs
Normal file
101
SharpChat.MariaDB/MariaDBMessageStorage_Permissions.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
namespace SharpChat.MariaDB;
|
||||
|
||||
public partial class MariaDBMessageStorage {
|
||||
public static UserPermissions FromMessagePermissions(MariaDBUserPermissions mup) {
|
||||
UserPermissions perms = 0;
|
||||
|
||||
if(mup.HasFlag(MariaDBUserPermissions.KickUser))
|
||||
perms |= UserPermissions.KickUser;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.BanUser))
|
||||
perms |= UserPermissions.BanUser;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.Broadcast))
|
||||
perms |= UserPermissions.SendBroadcast;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SetOwnNickname))
|
||||
perms |= UserPermissions.SetOwnNickname;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SetOthersNickname))
|
||||
perms |= UserPermissions.SetOthersNickname;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.CreateChannel))
|
||||
perms |= UserPermissions.CreateChannel;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.DeleteChannel))
|
||||
perms |= UserPermissions.DeleteChannel;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SetChannelPermanent))
|
||||
perms |= UserPermissions.SetChannelPermanent;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SetChannelPassword))
|
||||
perms |= UserPermissions.SetChannelPassword;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SetChannelHierarchy))
|
||||
perms |= UserPermissions.SetChannelMinimumRank;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.JoinAnyChannel))
|
||||
perms |= UserPermissions.JoinAnyChannel;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SendMessage))
|
||||
perms |= UserPermissions.SendMessage;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.DeleteOwnMessage))
|
||||
perms |= UserPermissions.DeleteOwnMessage;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.DeleteAnyMessage))
|
||||
perms |= UserPermissions.DeleteAnyMessage;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.EditOwnMessage))
|
||||
perms |= UserPermissions.EditOwnMessage;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.EditAnyMessage))
|
||||
perms |= UserPermissions.EditAnyMessage;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.SeeIPAddress))
|
||||
perms |= UserPermissions.ViewIPAddress;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.ViewLogs))
|
||||
perms |= UserPermissions.ViewLogs;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.ViewBanList))
|
||||
perms |= UserPermissions.ViewBanList;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.PardonUser))
|
||||
perms |= UserPermissions.PardonUser;
|
||||
if(mup.HasFlag(MariaDBUserPermissions.PardonIPAddress))
|
||||
perms |= UserPermissions.PardonIPAddress;
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
public static MariaDBUserPermissions ToStoredPermissions(UserPermissions up) {
|
||||
MariaDBUserPermissions perms = 0;
|
||||
|
||||
if(up.HasFlag(UserPermissions.KickUser))
|
||||
perms |= MariaDBUserPermissions.KickUser;
|
||||
if(up.HasFlag(UserPermissions.BanUser))
|
||||
perms |= MariaDBUserPermissions.BanUser;
|
||||
if(up.HasFlag(UserPermissions.SendBroadcast))
|
||||
perms |= MariaDBUserPermissions.Broadcast;
|
||||
if(up.HasFlag(UserPermissions.SetOwnNickname))
|
||||
perms |= MariaDBUserPermissions.SetOwnNickname;
|
||||
if(up.HasFlag(UserPermissions.SetOthersNickname))
|
||||
perms |= MariaDBUserPermissions.SetOthersNickname;
|
||||
if(up.HasFlag(UserPermissions.CreateChannel))
|
||||
perms |= MariaDBUserPermissions.CreateChannel;
|
||||
if(up.HasFlag(UserPermissions.DeleteChannel))
|
||||
perms |= MariaDBUserPermissions.DeleteChannel;
|
||||
if(up.HasFlag(UserPermissions.SetChannelPermanent))
|
||||
perms |= MariaDBUserPermissions.SetChannelPermanent;
|
||||
if(up.HasFlag(UserPermissions.SetChannelPassword))
|
||||
perms |= MariaDBUserPermissions.SetChannelPassword;
|
||||
if(up.HasFlag(UserPermissions.SetChannelMinimumRank))
|
||||
perms |= MariaDBUserPermissions.SetChannelHierarchy;
|
||||
if(up.HasFlag(UserPermissions.JoinAnyChannel))
|
||||
perms |= MariaDBUserPermissions.JoinAnyChannel;
|
||||
if(up.HasFlag(UserPermissions.SendMessage))
|
||||
perms |= MariaDBUserPermissions.SendMessage;
|
||||
if(up.HasFlag(UserPermissions.DeleteOwnMessage))
|
||||
perms |= MariaDBUserPermissions.DeleteOwnMessage;
|
||||
if(up.HasFlag(UserPermissions.DeleteAnyMessage))
|
||||
perms |= MariaDBUserPermissions.DeleteAnyMessage;
|
||||
if(up.HasFlag(UserPermissions.EditOwnMessage))
|
||||
perms |= MariaDBUserPermissions.EditOwnMessage;
|
||||
if(up.HasFlag(UserPermissions.EditAnyMessage))
|
||||
perms |= MariaDBUserPermissions.EditAnyMessage;
|
||||
if(up.HasFlag(UserPermissions.ViewIPAddress))
|
||||
perms |= MariaDBUserPermissions.SeeIPAddress;
|
||||
if(up.HasFlag(UserPermissions.ViewLogs))
|
||||
perms |= MariaDBUserPermissions.ViewLogs;
|
||||
if(up.HasFlag(UserPermissions.ViewBanList))
|
||||
perms |= MariaDBUserPermissions.ViewBanList;
|
||||
if(up.HasFlag(UserPermissions.PardonUser))
|
||||
perms |= MariaDBUserPermissions.PardonUser;
|
||||
if(up.HasFlag(UserPermissions.PardonIPAddress))
|
||||
perms |= MariaDBUserPermissions.PardonIPAddress;
|
||||
|
||||
return perms;
|
||||
}
|
||||
}
|
27
SharpChat.MariaDB/MariaDBUserPermissions.cs
Normal file
27
SharpChat.MariaDB/MariaDBUserPermissions.cs
Normal file
|
@ -0,0 +1,27 @@
|
|||
namespace SharpChat.MariaDB;
|
||||
|
||||
[Flags]
|
||||
public enum MariaDBUserPermissions : int {
|
||||
KickUser = 0x1,
|
||||
BanUser = 0x2,
|
||||
//SilenceUser = 0x4,
|
||||
Broadcast = 0x8,
|
||||
SetOwnNickname = 0x10,
|
||||
SetOthersNickname = 0x20,
|
||||
CreateChannel = 0x40,
|
||||
SetChannelPermanent = 0x80,
|
||||
SetChannelPassword = 0x100,
|
||||
SetChannelHierarchy = 0x200,
|
||||
SendMessage = 0x400,
|
||||
DeleteOwnMessage = 0x800,
|
||||
DeleteAnyMessage = 0x1000,
|
||||
EditOwnMessage = 0x2000,
|
||||
EditAnyMessage = 0x4000,
|
||||
SeeIPAddress = 0x8000,
|
||||
DeleteChannel = 0x10000,
|
||||
JoinAnyChannel = 0x20000,
|
||||
ViewLogs = 0x40000,
|
||||
ViewBanList = 0x80000,
|
||||
PardonUser = 0x100000,
|
||||
PardonIPAddress = 0x200000,
|
||||
}
|
17
SharpChat.MariaDB/SharpChat.MariaDB.csproj
Normal file
17
SharpChat.MariaDB/SharpChat.MariaDB.csproj
Normal file
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MySqlConnector" Version="2.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SharpChatCommon\SharpChatCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Loading…
Add table
Add a link
Reference in a new issue