Skip to content

Commit 253239e

Browse files
authored
add: implement MySQL database support (#141)
1 parent 9543418 commit 253239e

File tree

8 files changed

+143
-28
lines changed

8 files changed

+143
-28
lines changed

MapChooserSharp/Modules/McsDatabase/McsDatabaseProvider.cs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using MapChooserSharp.Modules.McsDatabase.Interfaces;
1+
using System.Runtime.InteropServices;
2+
using System.Security;
3+
using MapChooserSharp.Modules.McsDatabase.Interfaces;
24
using MapChooserSharp.Modules.McsDatabase.Repositories;
35
using MapChooserSharp.Modules.McsDatabase.Repositories.Interfaces;
46
using MapChooserSharp.Modules.PluginConfig.Interfaces;
@@ -51,8 +53,26 @@ private void ConfigureDatabase()
5153
switch (config.GeneralConfig.SqlConfig.DataBaseType)
5254
{
5355
case McsSupportedSqlType.MySql:
54-
// Plugin.Logger.LogInformation("Using MySQL database");
55-
throw new NotImplementedException("MySQL support is not implemented yet");
56+
_providerType = McsSupportedSqlType.MySql;
57+
string password = ConvertSecureStringToString(config.GeneralConfig.SqlConfig.Password);
58+
59+
try
60+
{
61+
_connectionString = $"Server={config.GeneralConfig.SqlConfig.Host};" +
62+
$"Database={config.GeneralConfig.SqlConfig.DatabaseName};" +
63+
$"User Id={config.GeneralConfig.SqlConfig.UserName};" +
64+
$"Password={password};" +
65+
$"Port={config.GeneralConfig.SqlConfig.Port};";
66+
67+
Plugin.Logger.LogInformation($"Using MySQL database at host: {config.GeneralConfig.SqlConfig.Host}, Database Name: {config.GeneralConfig.SqlConfig.DatabaseName}");
68+
}
69+
finally
70+
{
71+
// Clear password from memory ASAP
72+
SecurelyEraseString(ref password);
73+
}
74+
75+
break;
5676

5777
case McsSupportedSqlType.PostgreSql:
5878
// Plugin.Logger.LogInformation("Using PostgreSQL database");
@@ -61,10 +81,45 @@ private void ConfigureDatabase()
6181
case McsSupportedSqlType.Sqlite:
6282
default:
6383
_providerType = McsSupportedSqlType.Sqlite;
64-
string dbPath = Path.Combine(Plugin.ModuleDirectory, "MapChooserSharp.db");
84+
string dbPath = Path.Combine(Plugin.ModuleDirectory, config.GeneralConfig.SqlConfig.DatabaseName);
6585
_connectionString = $"Data Source={dbPath}";
6686
Plugin.Logger.LogInformation($"Using SQLite database at {dbPath}");
6787
break;
6888
}
6989
}
90+
91+
private string ConvertSecureStringToString(SecureString secureString)
92+
{
93+
IntPtr bstrPtr = Marshal.SecureStringToBSTR(secureString);
94+
try
95+
{
96+
return Marshal.PtrToStringBSTR(bstrPtr);
97+
}
98+
finally
99+
{
100+
Marshal.ZeroFreeBSTR(bstrPtr);
101+
}
102+
}
103+
104+
private void SecurelyEraseString(ref string value)
105+
{
106+
if (string.IsNullOrEmpty(value))
107+
return;
108+
109+
GCHandle handle = GCHandle.Alloc(value, GCHandleType.Pinned);
110+
111+
try
112+
{
113+
IntPtr ptr = handle.AddrOfPinnedObject();
114+
int size = value.Length * sizeof(char);
115+
116+
Marshal.Copy(new byte[size], 0, ptr, size);
117+
}
118+
finally
119+
{
120+
handle.Free();
121+
122+
value = "";
123+
}
124+
}
70125
}

MapChooserSharp/Modules/McsDatabase/Repositories/SqlProviders/MySql/MySqlGroupSqlQueries.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,25 @@ internal sealed class MySqlGroupSqlQueries(string tableName) : IMcsGroupSqlQueri
66
{
77
public string TableName { get; } = tableName;
88

9-
public string GetEnsureTableExistsSql() => throw new NotImplementedException("This functionality is not implemented.");
9+
public string GetEnsureTableExistsSql() => @$"
10+
CREATE TABLE IF NOT EXISTS {TableName} (
11+
Id INT AUTO_INCREMENT PRIMARY KEY,
12+
GroupName VARCHAR(255) NOT NULL UNIQUE,
13+
CooldownRemains INT NOT NULL
14+
)";
1015

11-
public string GetDecrementCooldownsSql() => throw new NotImplementedException("This functionality is not implemented.");
16+
public string GetDecrementCooldownsSql() =>
17+
$"UPDATE {TableName} SET CooldownRemains = CooldownRemains - 1 WHERE CooldownRemains > 0";
1218

13-
public string GetUpsertGroupCooldownSql() => throw new NotImplementedException("This functionality is not implemented.");
19+
public string GetUpsertGroupCooldownSql() => @$"
20+
INSERT INTO {TableName} (GroupName, CooldownRemains)
21+
VALUES (@GroupName, @CooldownValue)
22+
ON DUPLICATE KEY UPDATE
23+
CooldownRemains = @CooldownValue";
1424

15-
public string GetAllGroupInfosSql() => throw new NotImplementedException("This functionality is not implemented.");
25+
public string GetAllGroupInfosSql() =>
26+
$"SELECT * FROM {TableName}";
1627

17-
public string GetInsertGroupInfoSql() => throw new NotImplementedException("This functionality is not implemented.");
28+
public string GetInsertGroupInfoSql() =>
29+
$"INSERT INTO {TableName} (GroupName, CooldownRemains) VALUES (@GroupName, @CooldownRemains)";
1830
}

MapChooserSharp/Modules/McsDatabase/Repositories/SqlProviders/MySql/MySqlMapInformationSqlQueries.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,28 @@ internal sealed class MySqlMapInformationSqlQueries(string tableName) : IMcsMapI
66
{
77
public string TableName { get; } = tableName;
88

9-
public string GetEnsureTableExistsSql() => throw new NotImplementedException("This functionality is not implemented.");
9+
public string GetEnsureTableExistsSql() => @$"
10+
CREATE TABLE IF NOT EXISTS {TableName} (
11+
Id INT AUTO_INCREMENT PRIMARY KEY,
12+
MapName VARCHAR(255) NOT NULL UNIQUE,
13+
CooldownRemains INT NOT NULL
14+
)";
1015

11-
public string GetDecrementCooldownsSql() => throw new NotImplementedException("This functionality is not implemented.");
16+
public string GetDecrementCooldownsSql() =>
17+
$"UPDATE {TableName} SET CooldownRemains = CooldownRemains - 1 WHERE CooldownRemains > 0";
1218

13-
public string GetUpsertMapInfoSql() => throw new NotImplementedException("This functionality is not implemented.");
19+
public string GetUpsertMapInfoSql() => @$"
20+
INSERT INTO {TableName} (MapName, CooldownRemains)
21+
VALUES (@MapName, @CooldownRemains)
22+
ON DUPLICATE KEY UPDATE
23+
CooldownRemains = @CooldownRemains";
1424

15-
public string GetAllMapInfosSql() => throw new NotImplementedException("This functionality is not implemented.");
25+
public string GetAllMapInfosSql() =>
26+
$"SELECT * FROM {TableName}";
1627

17-
public string GetMapInfoByNameSql() => throw new NotImplementedException("This functionality is not implemented.");
28+
public string GetMapInfoByNameSql() =>
29+
$"SELECT * FROM {TableName} WHERE MapName = @MapName";
1830

19-
public string GetInsertMapInfoSql() => throw new NotImplementedException("This functionality is not implemented.");
31+
public string GetInsertMapInfoSql() =>
32+
$"INSERT INTO {TableName} (MapName, CooldownRemains) VALUES (@MapName, @CooldownRemains)";
2033
}

MapChooserSharp/Modules/PluginConfig/Interfaces/IMcsSqlConfig.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,13 @@ public interface IMcsSqlConfig
77
{
88
internal McsSupportedSqlType DataBaseType { get; }
99

10-
internal string Address { get; }
10+
internal string Host { get; }
1111

12-
internal string User { get; }
12+
internal string Port { get; }
13+
14+
internal string DatabaseName { get; }
15+
16+
internal string UserName { get; }
1317

1418
internal SecureString Password { get; }
1519

MapChooserSharp/Modules/PluginConfig/McsPluginConfigParser.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,21 @@ private McsSqlConfig ParseSqlConfig(TomlTable tomlModel)
344344
throw new InvalidOperationException("General.Sql.Type is not found or invalid");
345345
}
346346

347-
if (!sqlTable.TryGetValue("Address", out var sqlAddressObj) || sqlAddressObj is not string sqlAddress)
347+
if (!sqlTable.TryGetValue("Address", out var sqlAddressObj) || sqlAddressObj is not string sqlHost)
348348
{
349349
throw new InvalidOperationException("General.Sql.Address is not found or invalid");
350350
}
351351

352+
if (!sqlTable.TryGetValue("Port", out var sqlPortObj) || sqlPortObj is not string sqlPort)
353+
{
354+
throw new InvalidOperationException("General.Sql.Port is not found or invalid");
355+
}
356+
357+
if (!sqlTable.TryGetValue("DatabaseName", out var sqlDbNameObj) || sqlDbNameObj is not string sqlDbName)
358+
{
359+
throw new InvalidOperationException("General.Sql.DatabaseName is not found or invalid");
360+
}
361+
352362
if (!sqlTable.TryGetValue("User", out var sqlUserObj) || sqlUserObj is not string sqlUser)
353363
{
354364
throw new InvalidOperationException("General.Sql.User is not found or invalid");
@@ -377,7 +387,7 @@ private McsSqlConfig ParseSqlConfig(TomlTable tomlModel)
377387
throw new InvalidOperationException("General.Sql.Type is invalid");
378388
}
379389

380-
var sqlConfig = new McsSqlConfig(sqlAddress, sqlUser, ref sqlPassword, groupTableName, mapTableName, type);
390+
var sqlConfig = new McsSqlConfig(sqlHost, sqlPort, sqlDbName, sqlUser, ref sqlPassword, groupTableName, mapTableName, type);
381391

382392
return sqlConfig;
383393
}
@@ -461,10 +471,13 @@ private void WriteDefaultConfig()
461471
#
462472
# Currently Supports:
463473
# - Sqlite
474+
# - MySQL
464475
#
465476
# See GitHub readme for more and updated information.
466477
Type = ""sqlite""
478+
DatabaseName = ""MapChooserSharp.db""
467479
Address = """"
480+
Port = """"
468481
User = """"
469482
Password = """"
470483

MapChooserSharp/Modules/PluginConfig/Models/McsSqlConfig.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ namespace MapChooserSharp.Modules.PluginConfig.Models;
77

88
public sealed class McsSqlConfig: IMcsSqlConfig
99
{
10-
public McsSqlConfig(string address, string user, ref string password, string groupSettingsSqlTableName, string mapSettingsSqlTableName, McsSupportedSqlType dataBaseType)
10+
public McsSqlConfig(string host, string port, string databaseName, string user, ref string password, string groupSettingsSqlTableName, string mapSettingsSqlTableName, McsSupportedSqlType dataBaseType)
1111
{
12-
Address = address;
13-
User = user;
12+
Host = host;
13+
UserName = user;
1414
GroupSettingsSqlTableName = groupSettingsSqlTableName;
1515
MapSettingsSqlTableName = mapSettingsSqlTableName;
1616
DataBaseType = dataBaseType;
17+
Port = port;
18+
DatabaseName = databaseName;
1719

1820

1921
Password = ConvertToSecureString(password);
@@ -23,8 +25,10 @@ public McsSqlConfig(string address, string user, ref string password, string gro
2325
}
2426

2527
public McsSupportedSqlType DataBaseType { get; }
26-
public string Address { get; }
27-
public string User { get; }
28+
public string Host { get; }
29+
public string Port { get; }
30+
public string DatabaseName { get; }
31+
public string UserName { get; }
2832
public SecureString Password { get; }
2933
public string GroupSettingsSqlTableName { get; }
3034
public string MapSettingsSqlTableName { get; }

docs/en/configuration/PLUGIN_CONFIG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ Whether to display the number of seconds when RTV commands and other commands ar
3636
#
3737
# Currently Supports:
3838
# - Sqlite
39+
# - MySQL
3940
#
4041
# See GitHub readme for more and updated information.
4142
Type = "sqlite"
43+
DatabaseName = "MapChooserSharp.db"
4244
Address = ""
45+
Port = ""
4346
User = ""
4447
Password = ""
4548

@@ -49,9 +52,13 @@ MapInformationTableName = "McsMapInformation"
4952

5053
### Type
5154

52-
Specify the database type here. Currently only SQLite is supported.
55+
Specify the database type here.
5356

54-
### Address, User, Password
57+
### DatabaseName
58+
59+
Name of database, if database type is SQLite then this name will be a file name.
60+
61+
### Address, Port, User, Password
5562

5663
These will be necessary for connecting to the database when MySQL and PostgreSQL are supported in the future.
5764

docs/ja/configuration/PLUGIN_CONFIG.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,13 @@ RTVコマンドなどがクールダウンのときに秒数を表示するか
3737
#
3838
# Currently Supports:
3939
# - Sqlite
40+
# - MySQL
4041
#
4142
# See GitHub readme for more and updated information.
4243
Type = "sqlite"
44+
DatabaseName = "MapChooserSharp.db"
4345
Address = ""
46+
Port = ""
4447
User = ""
4548
Password = ""
4649

@@ -50,9 +53,13 @@ MapInformationTableName = "McsMapInformation"
5053

5154
### Type
5255

53-
データベースタイプをここで指定します。 現在はSqliteのみサポートしています。
56+
データベースタイプをここで指定します。
5457

55-
### Address, User, Password
58+
### DatabaseName
59+
60+
データベース名を指定します。 SQLiteを使用している際は、ここの名前がファイル名になります。
61+
62+
### Address, Port, User, Password
5663

5764
これは将来的にMySQLやPostgreSQLをサポートした際に、データベースに接続するために必要になります。
5865

0 commit comments

Comments
 (0)