mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-03-21 09:11:20 +00:00
- NioTSO client isn't needed because we're using RayLib - Added FreeSO's API server to handle most backend operations
163 lines
5.1 KiB
C#
Executable file
163 lines
5.1 KiB
C#
Executable file
using FSO.Server.Database.DA;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Dapper;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
using System.Text.RegularExpressions;
|
|
using FSO.Server.Database.DA.DbChanges;
|
|
using FSO.Server.Common;
|
|
using MySql.Data.MySqlClient;
|
|
|
|
namespace FSO.Server.Database.Management
|
|
{
|
|
public class DbChangeTool
|
|
{
|
|
private ISqlContext Context;
|
|
|
|
public DbChangeTool(ISqlContext context)
|
|
{
|
|
this.Context = context;
|
|
}
|
|
|
|
public List<DbChangeScript> GetChanges()
|
|
{
|
|
List<DbChangeScript> changes = new List<DbChangeScript>();
|
|
var connection = Context.Connection;
|
|
var hasChangesTable = connection.Query("SHOW TABLES LIKE 'fso_db_changes'").FirstOrDefault() != null;
|
|
|
|
var scriptsDirectory = Path.Combine(Directory.GetCurrentDirectory(), "DatabaseScripts");
|
|
var manifest = Newtonsoft.Json.JsonConvert.DeserializeObject<DbChangeManifest>(File.ReadAllText(Path.Combine(scriptsDirectory, "manifest.json")));
|
|
|
|
foreach(var script in manifest.Changes)
|
|
{
|
|
var scriptData = File.ReadAllText(Path.Combine(scriptsDirectory, script.Script));
|
|
|
|
changes.Add(new DbChangeScript {
|
|
ScriptFilename = script.Script,
|
|
Idempotent = script.Idempotent,
|
|
ScriptID = script.ID,
|
|
ScriptData = scriptData,
|
|
Status = DbChangeScriptStatus.NOT_INSTALLED,
|
|
Hash = hashScriptFile(scriptData)
|
|
});
|
|
}
|
|
|
|
if (hasChangesTable){
|
|
var changeHistory = connection.Query<DbChange>("SELECT * FROM fso_db_changes");
|
|
foreach(var changeHistoryItem in changeHistory)
|
|
{
|
|
var match = changes.FirstOrDefault(x => x.ScriptID == changeHistoryItem.id);
|
|
if(match == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if(match.Hash != changeHistoryItem.hash)
|
|
{
|
|
match.Status = DbChangeScriptStatus.MODIFIED;
|
|
}
|
|
else
|
|
{
|
|
match.Status = DbChangeScriptStatus.INSTALLED;
|
|
}
|
|
}
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
public void ApplyChange(DbChangeScript change, bool repair)
|
|
{
|
|
var connection = Context.Connection;
|
|
using (var transaction = connection.BeginTransaction(System.Data.IsolationLevel.RepeatableRead))
|
|
{
|
|
if (!repair)
|
|
{
|
|
var cmd = transaction.Connection.CreateCommand();
|
|
cmd.CommandText = change.ScriptData;
|
|
try
|
|
{
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
catch (MySqlException e)
|
|
{
|
|
throw new DbMigrateException(e.ToString());
|
|
}
|
|
}
|
|
|
|
connection.Execute("INSERT INTO fso_db_changes VALUES (@id, @filename, @date, @hash) ON DUPLICATE KEY UPDATE hash=@hash, date = @date, filename = @filename", new DbChange {
|
|
id = change.ScriptID,
|
|
date = Epoch.Now,
|
|
filename = change.ScriptFilename,
|
|
hash = change.Hash
|
|
});
|
|
|
|
transaction.Commit();
|
|
}
|
|
}
|
|
|
|
private string hashScriptFile(string sqlFileData)
|
|
{
|
|
//People often mess up whitespace in sql files in their IDE. Normalize whitespace before hashing
|
|
//to try and avoid changes
|
|
sqlFileData = Regex.Replace(sqlFileData, @"\s+", " ").Trim();
|
|
|
|
MD5 md5 = System.Security.Cryptography.MD5.Create();
|
|
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(sqlFileData);
|
|
byte[] hash = md5.ComputeHash(inputBytes);
|
|
|
|
// step 2, convert byte array to hex string
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i = 0; i < hash.Length; i++)
|
|
{
|
|
sb.Append(hash[i].ToString("X2"));
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
|
|
public class DbMigrateException : Exception
|
|
{
|
|
public DbMigrateException(string message) : base(message)
|
|
{
|
|
}
|
|
}
|
|
|
|
public class DbChangeScript
|
|
{
|
|
public DbChangeScriptStatus Status;
|
|
public string ScriptID;
|
|
public string ScriptFilename;
|
|
public string ScriptData;
|
|
public string Hash;
|
|
public bool Idempotent;
|
|
public List<string> Requires;
|
|
}
|
|
|
|
public enum DbChangeScriptStatus
|
|
{
|
|
INSTALLED,
|
|
MODIFIED,
|
|
NOT_INSTALLED,
|
|
FORCE_REINSTALL
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class DbChangeManifest
|
|
{
|
|
public List<DbChangeManifestScript> Changes;
|
|
}
|
|
|
|
public class DbChangeManifestScript
|
|
{
|
|
public string ID;
|
|
public string Script;
|
|
public bool Idempotent;
|
|
}
|
|
}
|