init commit

This commit is contained in:
Michal Buzik 2024-10-17 21:43:36 +02:00
commit 1b7fdc4a53
14 changed files with 651 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
bin/
obj/
/packages/
riderModule.iml
/_ReSharper.Caches/

16
tbfDBBackup.sln Normal file
View File

@ -0,0 +1,16 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tbfDBBackup", "tbfDBBackup\tbfDBBackup.csproj", "{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F4F004F-8E31-42B3-BE6D-EA9453EADC7F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,15 @@
using tbfDBBackup.configuration;
namespace tbfDBBackup;
public struct BackupCombination
{
public PathWrapper Path { get; init; }
public string DatabaseName { get; set; }
public string BackupFilePath { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string CommandPath { get; set; }
public string ServerName { get; set; }
}

View File

@ -0,0 +1,117 @@
using System.Text.Json;
using tbfDBBackup.configuration;
namespace tbfDBBackup;
public class Configuration
{
public const string ConfigDir = "config";
public const string FileName = "configuration.json";
public string? PathToDumpMysql { get; set; }
public Boolean? WaitOnEndCmdOpen { get; set; }
public Boolean? PrintConfigurationEnabled { get; set; }
public List<DbConnection>? DbConnectionStrings { get; set; }
public List<Update>? UpdateString { get; set; }
public List<Backup>? BackupDB { get; set; }
public static Configuration DeserializeFromJson(string jsonString)
{
return JsonSerializer.Deserialize<Configuration>(jsonString);
}
// Serialize method for saving
public string SerializeToJson()
{
return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
}
public void PrintConfiguration()
{
if (DbConnectionStrings != null)
{
Console.WriteLine("-- DbConnectionStrings:");
foreach (var dbConnection in DbConnectionStrings)
{
Console.WriteLine(dbConnection.ToString());
}
}
if (UpdateString != null)
{
Console.WriteLine("-- UpdateString:");
foreach (var update in UpdateString)
{
Console.WriteLine(update.ToString());
}
}
if (BackupDB != null)
{
Console.WriteLine("-- BackupResults:");
foreach (var backup in BackupDB)
{
Console.WriteLine(backup.ToString());
}
}
}
public List<BackupCombination> GetBackupCombinations()
{
List<BackupCombination> combinations = new List<BackupCombination>();
if (DbConnectionStrings != null)
{
foreach (DbConnection dbConnection in DbConnectionStrings)
{
if (!(dbConnection.Enabled ?? true))
{
continue;
}
combinations.AddRange(GetBackupCombinations(BackupDB, dbConnection));
}
}
return combinations;
}
private List<BackupCombination> GetBackupCombinations(List<Backup>? backups, DbConnection dbConnection)
{
List<BackupCombination> combinations = new List<BackupCombination>();
if (backups != null)
{
foreach (Backup backup in backups)
{
if (!(backup.Enabled??true) || backup.DbConnectionStringsName != dbConnection.Name )
{
continue;
}
foreach (PathWrapper path in backup.StoreDirPaths)
{
if ((path.Enabled ?? true))
{
combinations.Add(new BackupCombination
{
Path = path,
DatabaseName = dbConnection.DatabaseName,
ServerName = dbConnection.getServer(),
Password = dbConnection.getPassword(),
UserName = dbConnection.getUserName(),
CommandPath = PathToDumpMysql ?? "",
BackupFilePath = path.Path
});
}
}
}
}
return combinations;
}
}

276
tbfDBBackup/Program.cs Normal file
View File

@ -0,0 +1,276 @@
// See https://aka.ms/new-console-template for more information
using System.Diagnostics;
using MySqlConnector;
using tbfDBBackup;
using tbfDBBackup.configuration;
Console.WriteLine("---- TBF DB Backup process started -----");
//Read configuration
Configuration? configuration = GetConfiguration();
if (configuration == null)
{
Console.WriteLine("**** Configuration no found!! ***");
return -1;
}
//update part
if (configuration.UpdateString != null){
try
{
UpdateDb(configuration);
}
catch (Exception e)
{
Console.WriteLine("------ MySql Data uprade FAILED!! *** -----");
Console.WriteLine(e);
}
}
//database backup part
List<BackupCombination> backupCombinations = configuration.GetBackupCombinations();
foreach (BackupCombination combination in backupCombinations)
{
try
{
BackupDatabase(combination);
}
catch (Exception e)
{
Console.WriteLine($"------ MySql backup of database: {combination.DatabaseName} FAILED!! *** -----");
Console.WriteLine(e);
}
}
//Update one time config
//store configuration
SaveConfiguration(configuration);
//final info
Console.WriteLine("Program finished correctly!!");
//wait to end
if (configuration != null && (configuration.WaitOnEndCmdOpen ?? false))
{
Console.ReadLine();
}
//program END
return 0;
//////////////////////////////////////////////////////////////////////////////
Configuration? GetConfiguration()
{
try
{
Console.WriteLine($"---- program started path: {Environment.CurrentDirectory}");
string fileNamePath = ConfigurationFileNamePath();
Console.WriteLine($"- full config file path: {fileNamePath}");
string jsonConfiguration = "";
using (StreamReader reader = new StreamReader(fileNamePath))
{
jsonConfiguration = reader.ReadToEnd();
}
Configuration? configurationDeserialized = Configuration.DeserializeFromJson(jsonConfiguration);
if (configurationDeserialized != null && (configurationDeserialized.PrintConfigurationEnabled ?? false))
{
configurationDeserialized.PrintConfiguration();
}
return configurationDeserialized;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
void SaveConfiguration(Configuration configuration)
{
try
{
// Serialize the configuration back to JSON
string jsonString = configuration.SerializeToJson();
string fileNamePath = ConfigurationFileNamePath();
Console.WriteLine($"- full config file path: {fileNamePath}");
// Write the JSON string to the file
using (StreamWriter writer = new StreamWriter(fileNamePath))
{
writer.Write(jsonString);
}
Console.WriteLine("Configuration saved successfully.");
}
catch (Exception e)
{
Console.WriteLine($"Error saving configuration: {e}");
throw;
}
}
void BackupDatabase(BackupCombination backupCombination)
{
Console.WriteLine($"------ MySql backup of database: {backupCombination.DatabaseName} started -----");
DateTime currentTime = DateTime.Now; // Get current date and time
// Format the date and time as yyyyMMdd_HHmmss (e.g., 20241015_142530)
string time = currentTime.ToString("yyyyMMdd_HHmmss");
// Create the file name by appending the formatted time to the database name
string fileName = backupCombination.DatabaseName.Trim()
.Replace('\\', '_')
.Replace(' ', '_')
.ToLower() + "_backup_" + time + ".sql";
string filePathName = Path.Combine(backupCombination.BackupFilePath, fileName);
// Set up the mysqldump command
string dumpCommand =
$"mysqldump --user={backupCombination.UserName} --password={backupCombination.Password} --host={backupCombination.ServerName} {backupCombination.DatabaseName} --result-file=\"{filePathName}\" --routines --events";
// Check if the directory exists, and create it if not
if (!Directory.Exists(backupCombination.BackupFilePath))
{
Directory.CreateDirectory(backupCombination.BackupFilePath);
}
// Execute the mysqldump command
ProcessStartInfo processInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
Process process = new Process
{
StartInfo = processInfo
};
process.Start();
using (var writer = process.StandardInput)
{
if (writer.BaseStream.CanWrite)
{
if (backupCombination.CommandPath.Length == 0)
{
writer.WriteLine(dumpCommand);
}
else
{
// Split the dumpCommand into the executable and the arguments
string[]
parts = dumpCommand.Split(' ', 2); // Split into two parts: the command and the rest (arguments)
// Combine the commandPath with the executable (first part of dumpCommand)
string fullCommand = Path.Combine(backupCombination.CommandPath, parts[0]) + " " + parts[1];
// Execute the command with the full path
writer.WriteLine(fullCommand);
}
}
}
process.WaitForExit();
string result = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
if (!string.IsNullOrEmpty(error))
{
Console.WriteLine($"Error: {error}");
}
else
{
Console.WriteLine($"Backup created successfully at {filePathName}");
}
process.Close();
//Deactivate if only one time possible run
if ((backupCombination.Path.IsOneTimeOpaque ?? false) && (backupCombination.Path.Enabled??false))
{
backupCombination.Path.Enabled = false;
}
}
void UpdateDb(Configuration dbConfiguration)
{
if (dbConfiguration.DbConnectionStrings != null)
foreach (DbConnection dbConnection in dbConfiguration.DbConnectionStrings)
{
if (!(dbConnection.Enabled ?? true))
{
continue;
}
if (dbConfiguration.UpdateString != null)
foreach (Update update in dbConfiguration.UpdateString)
{
if (!(update.Enabled ?? true) || dbConnection.DatabaseName != update.DatabaseName)
{
continue;
}
try
{
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} starting -----");
string connectionString =
dbConnection.Connection.Replace("{DatabaseName}", dbConnection.DatabaseName);
MySqlConnection connection = new MySqlConnection(connectionString);
connection.Open();
MySqlCommand command =
new MySqlCommand(update.Query.Replace("{DatabaseName}", update.DatabaseName), connection);
int affectedItems = command.ExecuteNonQuery();
Console.WriteLine($"Affected items: {affectedItems}");
connection.Close();
if (update.IsOneTimeOpaque ?? false)
{
update.Enabled = false;
}
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} finished! -----");
}
catch (Exception e)
{
Console.WriteLine($"------ MySql Data upgrade name: {update.Name} ERROR!");
Console.WriteLine(e);
}
}
}
}
string ConfigurationFileNamePath()
{
string s;
#if DEBUG
Console.WriteLine("-- DEV version of THE PROJECT -- ");
string projectPath = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName;
s = Path.Combine(projectPath, Configuration.ConfigDir, Configuration.FileName);
#else
// For release mode, use an absolute path or the application base directory
Console.WriteLine("-- PROD version of THE PROJECT -- ");
fileNamePath = Path.Combine(Environment.CurrentDirectory, Configuration.ConfigDir, Configuration.FileName);
#endif
return s;
}

View File

@ -0,0 +1,55 @@
{
"PathToDumpMysql": "C:\\xampp\\mysql\\bin",
"WaitOnEndCmdOpen": false,
"PrintConfigurationEnabled": false,
"DbConnectionStrings": [
{
"Enabled": false,
"Name": "Settings DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298"
},
{
"Enabled": true,
"Name": "Results DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298-r"
}
],
"UpdateString": [
{
"Enabled": false,
"Name": "Alter table Water Meter",
"Query": "ALTER TABLE `{DatabaseName}`.`WaterMeter` ADD COLUMN `RadioAddress` BOOLEAN;",
"DatabaseName": "wrcswindon298-r"
}
],
"BackupDB": [
{
"Enabled": true,
"DbConnectionStringsName": "Results DB",
"StoreDirPaths": [
{
"Path": "C:\\TBF\\"
},
{
"Path": "C:\\TBF\\storeString",
"Enable": false
}
]
},
{
"Enabled": false,
"DbConnectionStringsName": "Settings DB",
"StoreDirPaths": [
{
"Path": "C:\\TBF\\"
},
{
"Path": "C:\\TBF\\storeString",
"Enable": true
}
]
}
]
}

View File

@ -0,0 +1,55 @@
{
"PathToDumpMysql": "C:\\xampp\\mysql\\bin",
"WaitOnEndCmdOpen": false,
"PrintConfigurationEnabled": false,
"DbConnectionStrings": [
{
"Enabled": false,
"Name": "Settings DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298"
},
{
"Enabled": true,
"Name": "Results DB",
"Connection": "SERVER=localhost; DATABASE={DatabaseName}; UID=root; PASSWORD=; CHARSET=utf8;",
"DatabaseName": "wrcswindon298-r"
}
],
"UpdateString": [
{
"Enabled": false,
"Name": "Alter table Water Meter",
"Query": "ALTER TABLE `{DatabaseName}`.`WaterMeter` ADD COLUMN `RadioAddress` BOOLEAN;",
"DatabaseName": "wrcswindon298-r"
}
],
"BackupDB": [
{
"Enabled": true,
"DbConnectionStringsName": "Results DB",
"StoreDirPaths": [
{
"Path": "C:\\TBF\\"
},
{
"Path": "C:\\TBF\\storeString",
"Enable": false
}
]
},
{
"Enabled": false,
"DbConnectionStringsName": "Settings DB",
"StoreDirPaths": [
{
"Path": "C:\\TBF\\"
},
{
"Path": "C:\\TBF\\storeString",
"Enable": true
}
]
}
]
}

View File

@ -0,0 +1,15 @@
using System.Text.Json;
namespace tbfDBBackup.configuration;
public class Backup : StandardBehaviour
{
public string DbConnectionStringsName { get; set; }
public List<PathWrapper> StoreDirPaths { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
}
}

View File

@ -0,0 +1,40 @@
using System.Text.Json;
using System.Text.RegularExpressions;
namespace tbfDBBackup.configuration;
public class DbConnection : StandardBehaviour
{
public string Name { get; set; }
public string Connection { get; set; }
public string DatabaseName { get; set; }
public string getServer()
{
return ExtractValueUsingRegex(Connection, @"SERVER=([^;]+)");
}
public string getPassword()
{
return ExtractValueUsingRegex(Connection, @"PASSWORD=([^;]+)");
}
public string getUserName()
{
return ExtractValueUsingRegex(Connection, @"UID=([^;]+)");
}
// Helper function to extract value using regex
public static string ExtractValueUsingRegex(string input, string pattern)
{
Match match = Regex.Match(input, pattern);
return match.Success ? match.Groups[1].Value : null;
}
public override string ToString()
{
return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
}
}

View File

@ -0,0 +1,7 @@
namespace tbfDBBackup.configuration;
public interface IStandartBehaviour
{
bool IsEnabled();
bool IsOneTimeOpaque();
}

View File

@ -0,0 +1,13 @@
using System.Text.Json;
namespace tbfDBBackup.configuration;
public class PathWrapper : StandardBehaviour
{
public string Path { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
}
}

View File

@ -0,0 +1,7 @@
namespace tbfDBBackup.configuration;
public class StandardBehaviour
{
public Boolean? Enabled { get; set; }
public Boolean? IsOneTimeOpaque { get; set; }
}

View File

@ -0,0 +1,16 @@
using System.Text.Json;
namespace tbfDBBackup.configuration;
public class Update : StandardBehaviour
{
public string Name { get; set; }
public string Query { get; set; }
public string DatabaseName { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
}
}

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySqlConnector" Version="2.4.0-beta.1" />
</ItemGroup>
</Project>