MySqlConnector.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. using System.Globalization;
  2. using System.Text;
  3. using System.Text.Json;
  4. using Microsoft.Extensions.Configuration;
  5. using MinecraftStatus;
  6. using MySqlConnector;
  7. using Serilog;
  8. using VeloeMonitorDataCollector.Dependencies;
  9. using VeloeMonitorDataCollector.Models;
  10. namespace VeloeMonitorDataCollector.DatabaseConnectors
  11. {
  12. class MySqlConnector : IDataSendable
  13. {
  14. MySqlConnection _connection;
  15. private string _database;
  16. Serilog.ILogger _logger;
  17. Dictionary<string, bool?> _gamespyTableCheck = new();
  18. /// <summary>
  19. /// Creates connection to MySQL database using config.ini
  20. /// Checks if server is available and schema is created
  21. /// </summary>
  22. /// <param name="section">Configuration section with tag [MySQL]</param>
  23. /// <exception cref="ArgumentNullException"></exception>
  24. public MySqlConnector(in IConfigurationSection section, in Serilog.ILogger logger)
  25. {
  26. _logger = logger;
  27. section["port"] ??= "3306";
  28. _database = section["database"][..(section["database"].IndexOfAny(new[] { ' ', ';' }) >= 0 ?
  29. section["database"].IndexOfAny(new[] { ' ', ';' }) :
  30. section["database"].Length)];
  31. if (_database is null)
  32. throw new ArgumentNullException(_database);
  33. MySqlConnectionStringBuilder connectionString = new MySqlConnectionStringBuilder();
  34. //connectionString.Database = section["database"];
  35. connectionString.Server = section["server"];
  36. connectionString.Port = UInt32.Parse(section["port"]);
  37. connectionString.UserID = section["uid"];
  38. connectionString.Password = section["pwd"];
  39. connectionString.ConnectionReset = true;
  40. _logger.Information("Connecting to {0} (MySQL)", section["server"]);
  41. _connection = new MySqlConnection(connectionString.ToString());
  42. _connection.Open();
  43. try
  44. {
  45. _connection.ChangeDatabase(_database);
  46. }
  47. catch (MySqlException ex)
  48. {
  49. switch (ex.Number)
  50. {
  51. case 1049:
  52. _logger.Warning(ex.Message);
  53. _logger.Information("Create database? Y/N");
  54. var key = Console.ReadKey();
  55. if (key.KeyChar.Equals('Y'))
  56. {
  57. CreateDatabase(_database);
  58. }
  59. break;
  60. default:
  61. throw;
  62. }
  63. }
  64. }
  65. public void Close()
  66. {
  67. _connection.Close();
  68. _connection.Dispose();
  69. }
  70. /// <summary>
  71. /// Check if table in database is correct for sending data from game servers
  72. /// Creates table if schema creates for the first time or empty
  73. /// </summary>
  74. /// <param name="name">name of table in database</param>
  75. /// <param name="type">type of server</param>
  76. /// <exception cref="ArgumentException">when entered type is not supported or invalid string accepted</exception>
  77. public bool CheckGameServer(in string name, in string type)
  78. {
  79. MySqlCommand command;
  80. string[] cols;
  81. string[] types;
  82. //TODO store cols and types strings somewhere else
  83. switch (type)
  84. {
  85. case "Minecraft":
  86. cols = new string[]
  87. {
  88. "messageofaday",
  89. "gametype",
  90. "gameid",
  91. "version",
  92. "plugins",
  93. "map",
  94. "numplayers",
  95. "maxplayers",
  96. "players"
  97. };
  98. types = new string[]
  99. {
  100. "varchar(255)",
  101. "varchar(16)",
  102. "varchar(16)",
  103. "varchar(16)",
  104. "varchar(255)",
  105. "varchar(48)",
  106. "int",
  107. "int",
  108. "varchar(255)"
  109. };
  110. break;
  111. case "Steam":
  112. cols = new string[]
  113. {
  114. "bots",
  115. "environment",
  116. "folder",
  117. "game",
  118. "gameid",
  119. "keywords",
  120. "map",
  121. "maxplayers",
  122. "name",
  123. "players",
  124. "servertype",
  125. "vac",
  126. "version",
  127. "visibility",
  128. "playerslist"
  129. };
  130. types = new string[]
  131. {
  132. "tinyint unsigned",
  133. "varchar(16)",
  134. "varchar(48)",
  135. "varchar(48)",
  136. "bigint",
  137. "varchar(255)",
  138. "varchar(48)",
  139. "tinyint unsigned",
  140. "varchar(128)",
  141. "tinyint unsigned",
  142. "varchar(16)",
  143. "varchar(16)",
  144. "varchar(16)",
  145. "varchar(16)",
  146. "varchar(255)"
  147. };
  148. break;
  149. case "Gamespy3":
  150. _logger.Warning("Table {0} can't be checked before game server quering service init because server uses {1} protocol. Table will be checked after first success connection to the server.", name, "Gamespy3");
  151. return true;
  152. case "Gamespy2":
  153. _logger.Warning("Table {0} can't be checked before game server quering service init because server uses {1} protocol. Table will be checked after first success connection to the server.", name, "Gamespy2");
  154. return true;
  155. default:
  156. throw new ArgumentException(type);
  157. }
  158. try
  159. {
  160. bool valid = true;
  161. command = new MySqlCommand($"SHOW COLUMNS FROM {name};", _connection);
  162. using var result = command.ExecuteReader();
  163. _logger.Information(
  164. "Checking table {0} in {1} for {2} (MySQL)", name, _connection.Database, _connection.DataSource);
  165. if (result.Read() is false)
  166. {
  167. CreateTableGameServer(name, type);
  168. return true;
  169. }
  170. if (result.GetString(0) is not "date" &&
  171. result.GetString(1) is not "bigint")
  172. {
  173. _logger.Error("Error at column {0}. Correct is {1} {2}",0,"date","bigint");
  174. valid = false;
  175. }
  176. //check here other columns
  177. for (int i = 0; i < cols.Length; i++)
  178. {
  179. if (!result.Read())
  180. {
  181. _logger.Error("End of table on column {0}/{1}",i+1,cols.Length);
  182. return false;
  183. }
  184. if (result.GetString(0) != cols[i] &&
  185. result.GetString(1) != types[i])
  186. {
  187. _logger.Error("Error at colunm {0}. Correct is {1} {2}",i+1,cols[i],types[i]);
  188. valid = false;
  189. }
  190. }
  191. if (valid) _logger.Information("Ok");
  192. return valid;
  193. }
  194. catch (MySqlException e)
  195. {
  196. if (e.Number == 1146)
  197. {
  198. CreateTableGameServer(name, type);
  199. return true;
  200. }
  201. throw;
  202. }
  203. }
  204. public bool CheckHardware(in Dictionary<string, float> input)
  205. {
  206. var command = new MySqlCommand("SHOW COLUMNS FROM hardware;", _connection);
  207. try
  208. {
  209. bool valid = true;
  210. using var result = command.ExecuteReader();
  211. _logger.Information("Checking table {0} in {1} for {2} (MySQL)", "hardware",_connection.Database, _connection.DataSource);
  212. if (result.Read() is false)
  213. {
  214. CreateTableHardware(input);
  215. return true;
  216. }
  217. if (result.GetString(0) is not "date" && result.GetString(1) is not "bigint")
  218. {
  219. _logger.Error("Error at column {0}. Correct is {1} {2}",0,"date","bigint");
  220. valid = false;
  221. }
  222. int i = 1;
  223. foreach (var parameter in input)
  224. {
  225. if (result.Read() is false)
  226. {
  227. _logger.Error("End of table on column {0}",i);
  228. return false;
  229. }
  230. if (result.GetString(0) != parameter.Key || result.GetString(1) != "float")
  231. {
  232. _logger.Error("Error at colunm {0}. Correct is {1} {2}",i,parameter.Key,"float");
  233. valid = false;
  234. }
  235. i++;
  236. }
  237. if (valid) _logger.Information("Ok");
  238. return valid;
  239. }
  240. catch (MySqlException e)
  241. {
  242. if (e.Number == 1146)
  243. {
  244. CreateTableHardware(input);
  245. return true;
  246. }
  247. throw;
  248. }
  249. }
  250. public void CreateTableGameServer(in string name,in string type)
  251. {
  252. MySqlCommand command;
  253. StringBuilder query;
  254. switch (type)
  255. {
  256. case "Minecraft":
  257. //TODO change it when C#11 releases
  258. //TODO query builder
  259. query = new StringBuilder();
  260. query.AppendFormat("CREATE TABLE {0} (", name);
  261. query.Append("date BIGINT NOT NULL,");
  262. query.Append("messageofaday VARCHAR(255),");
  263. query.Append("gametype VARCHAR(16),");
  264. query.Append("gameid VARCHAR(16),");
  265. query.Append("version VARCHAR(16),");
  266. query.Append("plugins VARCHAR(255),");
  267. query.Append("map VARCHAR(48),");
  268. query.Append("numplayers INT,");
  269. query.Append("maxplayers INT,");
  270. query.Append("players VARCHAR(255)");
  271. query.Append(",PRIMARY KEY (date))");
  272. command = new MySqlCommand(query.ToString(), _connection);
  273. break;
  274. case "Steam":
  275. query = new StringBuilder();
  276. query.AppendFormat("CREATE TABLE {0} (", name);
  277. query.Append("date BIGINT NOT NULL,");
  278. query.Append("bots tinyint unsigned,");
  279. query.Append("environment VARCHAR(16),");
  280. query.Append("folder VARCHAR(48),");
  281. query.Append("game VARCHAR(48),");
  282. query.Append("gameid bigint,");
  283. query.Append("keywords VARCHAR(255),");
  284. query.Append("map varchar(48),");
  285. query.Append("maxplayers tinyint unsigned,");
  286. query.Append("name VARCHAR(128),");
  287. query.Append("players tinyint unsigned,");
  288. query.Append("servertype VARCHAR(16),");
  289. query.Append("vac VARCHAR(16),");
  290. query.Append("version VARCHAR(16),");
  291. query.Append("visibility VARCHAR(16),");
  292. query.Append("playerslist VARCHAR(255)");
  293. query.Append(",PRIMARY KEY (date))");
  294. command = new MySqlCommand(query.ToString(), _connection);
  295. break;
  296. case "Gamespy3":
  297. throw new NotImplementedException("Gamespy3");
  298. return;
  299. case "Gamespy2":
  300. throw new NotImplementedException("Gamespy3");
  301. return;
  302. default:
  303. throw new ArgumentException(type);
  304. }
  305. command.ExecuteNonQuery();
  306. _logger.Information("Table {0} created in {1} for {2} (MySQL)", name, _connection.Database, _connection.DataSource);
  307. }
  308. public void CreateTableHardware(in Dictionary<string, float> input)
  309. {
  310. StringBuilder columns = new StringBuilder();
  311. foreach (var parameter in input)
  312. {
  313. columns.Append($",{parameter.Key} FLOAT ");
  314. }
  315. MySqlCommand command = new MySqlCommand(
  316. $"CREATE TABLE hardware (date BIGINT NOT NULL {columns} ,PRIMARY KEY (date))", _connection);
  317. command.ExecuteNonQuery();
  318. _logger.Information("Table hardware created in {0} for {1} (MySQL)", _connection.Database,_connection.DataSource);
  319. }
  320. public void SendHardware(in Dictionary<string,float> data)
  321. {
  322. MySqlCommand command;
  323. CultureInfo oldCultureInfo = CultureInfo.CurrentCulture;
  324. CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
  325. var cols = string.Join(',',data.Keys);
  326. var values = string.Join(", @",data.Keys);
  327. CultureInfo.CurrentCulture = oldCultureInfo;
  328. var query = $"INSERT INTO hardware (date ,{cols}) VALUES (@date ,@{values})";
  329. //Console.WriteLine(query);
  330. command = new MySqlCommand(query, _connection);
  331. command.Parameters.Add("date", MySqlDbType.Int64).Value = DateTimeOffset.Now.ToUnixTimeSeconds();
  332. foreach (var parameter in data)
  333. {
  334. command.Parameters.Add(parameter.Key, MySqlDbType.Float).Value = parameter.Value;
  335. }
  336. command.ExecuteNonQueryAsync();
  337. }
  338. public void SendMinecraft(in McStatus data, in string name)
  339. {
  340. MySqlCommand command;
  341. command = new MySqlCommand($"INSERT INTO {name} (date ,messageofaday, gametype, gameid, version, plugins, map, numplayers, maxplayers, players) VALUES (@date, @messageofaday, @gametype, @gameid, @version, @plugins, @map, @numplayers, @maxplayers, @players)", _connection);
  342. command.Parameters.Clear();
  343. command.Parameters.Add("date", MySqlDbType.UInt64).Value = DateTimeOffset.Now.ToUnixTimeSeconds();
  344. command.Parameters.Add("messageofaday", MySqlDbType.VarString).Value = data.MessageOfTheDay;
  345. command.Parameters.Add("gametype", MySqlDbType.VarString).Value = data.Gametype;
  346. command.Parameters.Add("gameid", MySqlDbType.VarString).Value = data.GameId;
  347. command.Parameters.Add("version", MySqlDbType.VarString).Value = data.Version;
  348. command.Parameters.Add("plugins", MySqlDbType.VarString).Value = data.Plugins;
  349. command.Parameters.Add("map", MySqlDbType.VarString).Value = data.Map;
  350. command.Parameters.Add("numplayers", MySqlDbType.Int32).Value = data.NumPlayers;
  351. command.Parameters.Add("maxplayers", MySqlDbType.Int32).Value = data.MaxPlayers;
  352. command.Parameters.Add("players", MySqlDbType.VarString).Value = JsonSerializer.Serialize(data.Players);
  353. command.ExecuteNonQueryAsync();
  354. }
  355. public void SendSteam(in SteamData data, in string name)
  356. {
  357. MySqlCommand command;
  358. command = new MySqlCommand($"INSERT INTO {name} (date, bots, environment, folder, game, gameid, keywords, map, maxplayers, name, players, servertype, vac, version, visibility, playerslist) VALUES (@date, @bots, @environment, @folder, @game, @gameid, @keywords, @map, @maxplayers, @name, @players, @servertype, @vac, @version, @visibility, @playerslist)", _connection);
  359. command.Parameters.Clear();
  360. command.Parameters.Add("date", MySqlDbType.UInt64).Value = DateTimeOffset.Now.ToUnixTimeSeconds();
  361. command.Parameters.Add("bots", MySqlDbType.UByte).Value = data.ServerInfo.Bots;
  362. command.Parameters.Add("environment", MySqlDbType.VarString).Value = data.ServerInfo.Environment;
  363. command.Parameters.Add("folder", MySqlDbType.VarString).Value = data.ServerInfo.Folder;
  364. command.Parameters.Add("game", MySqlDbType.VarString).Value = data.ServerInfo.Game;
  365. command.Parameters.Add("gameid", MySqlDbType.Int64).Value = data.ServerInfo.GameID;
  366. command.Parameters.Add("keywords", MySqlDbType.VarString).Value = data.ServerInfo.Keywords;
  367. command.Parameters.Add("map", MySqlDbType.VarString).Value = data.ServerInfo.Map;
  368. command.Parameters.Add("maxplayers", MySqlDbType.VarString).Value = data.ServerInfo.MaxPlayers;
  369. command.Parameters.Add("name", MySqlDbType.VarString).Value = data.ServerInfo.Name;
  370. command.Parameters.Add("players", MySqlDbType.VarString).Value = data.ServerInfo.Players;
  371. command.Parameters.Add("servertype", MySqlDbType.VarString).Value = data.ServerInfo.ServerType;
  372. command.Parameters.Add("vac", MySqlDbType.VarString).Value = data.ServerInfo.VAC;
  373. command.Parameters.Add("version", MySqlDbType.VarString).Value = data.ServerInfo.Version;
  374. command.Parameters.Add("visibility", MySqlDbType.VarString).Value = data.ServerInfo.Visibility;
  375. command.Parameters.Add("playerslist", MySqlDbType.VarString).Value = JsonSerializer.Serialize(data.Players);
  376. command.ExecuteNonQueryAsync();
  377. }
  378. public void SendGamespy3(in Gs3Status.Status data,in string name)
  379. {
  380. if (_gamespyTableCheck.GetValueOrDefault(name, null) is null)
  381. {
  382. _gamespyTableCheck[name] = CheckGamespy3(data, name);
  383. }
  384. if (_gamespyTableCheck[name] is false)
  385. return;
  386. MySqlCommand command;
  387. StringBuilder queryBuilder = new StringBuilder();
  388. queryBuilder.Append($"INSERT INTO {name} (date");
  389. foreach (var parameter in data.Info)
  390. {
  391. if (parameter.Value != String.Empty && parameter.Value is not null)
  392. {
  393. queryBuilder.Append(", ");
  394. queryBuilder.Append(parameter.Key);
  395. }
  396. }
  397. queryBuilder.Append(", playerslist) VALUES ( @date ");
  398. foreach (var parameter in data.Info)
  399. {
  400. if (parameter.Value != String.Empty && parameter.Value is not null)
  401. {
  402. queryBuilder.Append(", @");
  403. queryBuilder.Append(parameter.Key);
  404. //_logger.Debug("'{0}' = '{1}'", parameter.Key, parameter.Value);
  405. }
  406. }
  407. queryBuilder.Append(", @playerslist )");
  408. command = new MySqlCommand(queryBuilder.ToString(), _connection);
  409. command.Parameters.Clear();
  410. command.Parameters.Add("date", MySqlDbType.UInt64).Value = DateTimeOffset.Now.ToUnixTimeSeconds();
  411. foreach(var parameter in data.Info)
  412. {
  413. if (parameter.Value != String.Empty && parameter.Value is not null)
  414. command.Parameters.Add(parameter.Key, MySqlDbType.VarString).Value = parameter.Value;
  415. }
  416. command.Parameters.Add("playerslist", MySqlDbType.VarString).Value = JsonSerializer.Serialize(data.Players);
  417. command.ExecuteNonQueryAsync();
  418. }
  419. private bool CheckGamespy3(Gs3Status.Status input, string name)
  420. {
  421. var command = new MySqlCommand($"SHOW COLUMNS FROM {name};", _connection);
  422. try
  423. {
  424. bool valid = true;
  425. using var result = command.ExecuteReaderAsync().Result;
  426. _logger.Information("Checking table {0} ({1}) in {2} for {3} (MySQL)", name, "Gamespy3" , _connection.Database, _connection.DataSource);
  427. if (result.Read() is false)
  428. {
  429. CreateTableGamespy3(input, name);
  430. return true;
  431. }
  432. int colsCount = 1;
  433. foreach(var parameter in input.Info)
  434. if (parameter.Value is not null && parameter.Value != String.Empty)
  435. colsCount++;
  436. if (result.GetString(0) is not "date" && result.GetString(1) is not "bigint")
  437. {
  438. _logger.Error("Error at column {0}. Correct is {1} {2}", 0, "date", "bigint");
  439. valid = false;
  440. }
  441. int i = 1;
  442. foreach (var parameter in input.Info)
  443. {
  444. if (result.Read() is false)
  445. {
  446. _logger.Error("End of table on column {0}/{1}", i, colsCount);
  447. return false;
  448. }
  449. if (result.GetString(0) != parameter.Key || result.GetString(1) != "varchar(127)")
  450. {
  451. _logger.Error("Error at colunm {0}. Correct is {1} {2}", i, parameter.Key, "varchar(127)");
  452. valid = false;
  453. }
  454. i++;
  455. }
  456. if (result.Read() is false)
  457. {
  458. _logger.Error("End of table on column {0}/{0}", colsCount);
  459. return false;
  460. }
  461. if (result.GetString(0) != "playerslist" || result.GetString(1) != "varchar(255)")
  462. {
  463. _logger.Error("Error at colunm {0}. Correct is {1} {2}", i, "playerslist", "varchar(255)");
  464. valid = false;
  465. }
  466. if (valid) _logger.Information("Ok");
  467. //else _logger.Warning("Table {0} isn't receiving any updates to {1} (MySQL)", name, _connection.DataSource);
  468. return valid;
  469. }
  470. catch (MySqlException e)
  471. {
  472. if (e.Number == 1146)
  473. {
  474. CreateTableGamespy3(input, name);
  475. return true;
  476. }
  477. throw;
  478. }
  479. }
  480. private void CreateTableGamespy3(Gs3Status.Status input, string name)
  481. {
  482. StringBuilder columns = new StringBuilder();
  483. foreach (var parameter in input.Info)
  484. {
  485. if (parameter.Value != String.Empty && parameter.Value is not null)
  486. columns.Append($",{parameter.Key} VARCHAR(127) ");
  487. }
  488. MySqlCommand command = new MySqlCommand(
  489. $"CREATE TABLE {name} (date BIGINT NOT NULL {columns}, playerslist VARCHAR(255) ,PRIMARY KEY (date))", _connection);
  490. command.ExecuteNonQuery();
  491. _logger.Information("Table {0} created in {1} for {2} (MySQL)", name ,_connection.Database, _connection.DataSource);
  492. }
  493. public void SendGamespy2(in Gs2Status.Status data, in string name)
  494. {
  495. if (_gamespyTableCheck.GetValueOrDefault(name, null) is null)
  496. {
  497. _gamespyTableCheck[name] = CheckGamespy2(data, name);
  498. }
  499. if (_gamespyTableCheck[name] is false)
  500. return;
  501. MySqlCommand command;
  502. StringBuilder queryBuilder = new StringBuilder();
  503. queryBuilder.Append($"INSERT INTO {name} (date");
  504. foreach (var parameter in data.Info)
  505. {
  506. if (parameter.Value != String.Empty && parameter.Value is not null)
  507. {
  508. queryBuilder.Append(", ");
  509. queryBuilder.Append(parameter.Key);
  510. }
  511. }
  512. queryBuilder.Append(", playerslist) VALUES ( @date ");
  513. foreach (var parameter in data.Info)
  514. {
  515. if (parameter.Value != String.Empty && parameter.Value is not null)
  516. {
  517. queryBuilder.Append(", @");
  518. queryBuilder.Append(parameter.Key);
  519. //_logger.Debug("'{0}' = '{1}'", parameter.Key, parameter.Value);
  520. }
  521. }
  522. queryBuilder.Append(", @playerslist )");
  523. command = new MySqlCommand(queryBuilder.ToString(), _connection);
  524. command.Parameters.Clear();
  525. command.Parameters.Add("date", MySqlDbType.UInt64).Value = DateTimeOffset.Now.ToUnixTimeSeconds();
  526. foreach (var parameter in data.Info)
  527. {
  528. if (parameter.Value != String.Empty && parameter.Value is not null)
  529. command.Parameters.Add(parameter.Key, MySqlDbType.VarString).Value = parameter.Value;
  530. }
  531. command.Parameters.Add("playerslist", MySqlDbType.VarString).Value = JsonSerializer.Serialize(data.Players);
  532. command.ExecuteNonQueryAsync();
  533. }
  534. private bool CheckGamespy2(Gs2Status.Status input, string name)
  535. {
  536. var command = new MySqlCommand($"SHOW COLUMNS FROM {name};", _connection);
  537. try
  538. {
  539. bool valid = true;
  540. using var result = command.ExecuteReaderAsync().Result;
  541. _logger.Information("Checking table {0} ({1}) in {2} for {3} (MySQL)", name, "Gamespy2", _connection.Database, _connection.DataSource);
  542. if (result.Read() is false)
  543. {
  544. CreateTableGamespy2(input, name);
  545. return true;
  546. }
  547. int colsCount = 1;
  548. foreach (var parameter in input.Info)
  549. if (parameter.Value is not null && parameter.Value != String.Empty)
  550. colsCount++;
  551. if (result.GetString(0) is not "date" && result.GetString(1) is not "bigint")
  552. {
  553. _logger.Error("Error at column {0}. Correct is {1} {2}", 0, "date", "bigint");
  554. valid = false;
  555. }
  556. int i = 1;
  557. foreach (var parameter in input.Info)
  558. {
  559. if (result.Read() is false)
  560. {
  561. _logger.Error("End of table on column {0}/{1}", i, colsCount);
  562. return false;
  563. }
  564. if (result.GetString(0) != parameter.Key || result.GetString(1) != "varchar(127)")
  565. {
  566. _logger.Error("Error at colunm {0}. Correct is {1} {2}", i, parameter.Key, "varchar(127)");
  567. valid = false;
  568. }
  569. i++;
  570. }
  571. if (result.Read() is false)
  572. {
  573. _logger.Error("End of table on column {0}/{0}", colsCount);
  574. return false;
  575. }
  576. if (result.GetString(0) != "playerslist" || result.GetString(1) != "varchar(255)")
  577. {
  578. _logger.Error("Error at colunm {0}. Correct is {1} {2}", i, "playerslist", "varchar(255)");
  579. valid = false;
  580. }
  581. if (valid) _logger.Information("Ok");
  582. //else _logger.Warning("Table {0} isn't receiving any updates to {1} (MySQL)", name, _connection.DataSource);
  583. return valid;
  584. }
  585. catch (AggregateException e)
  586. {
  587. if (e.InnerException is MySqlException)
  588. {
  589. if (((MySqlException)e.InnerException).Number == 1146)
  590. {
  591. CreateTableGamespy2(input, name);
  592. return true;
  593. }
  594. }
  595. throw;
  596. }
  597. }
  598. private void CreateTableGamespy2(Gs2Status.Status input, string name)
  599. {
  600. StringBuilder columns = new StringBuilder();
  601. foreach (var parameter in input.Info)
  602. {
  603. if (parameter.Value != String.Empty && parameter.Value is not null)
  604. columns.Append($",{parameter.Key} VARCHAR(127) ");
  605. }
  606. MySqlCommand command = new MySqlCommand(
  607. $"CREATE TABLE {name} (date BIGINT NOT NULL {columns}, playerslist VARCHAR(255) ,PRIMARY KEY (date))", _connection);
  608. command.ExecuteNonQuery();
  609. _logger.Information("Table {0} created in {1} for {2} (MySQL)", name, _connection.Database, _connection.DataSource);
  610. }
  611. private void CreateDatabase(string name)
  612. {
  613. MySqlCommand command = new MySqlCommand($"CREATE DATABASE {name}", _connection);
  614. command.ExecuteNonQuery();
  615. }
  616. }
  617. }