// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.IO; using System.Linq; using System.Collections.Generic; using MySql.Data.MySqlClient; using AutomationTool; namespace Gauntlet { /// /// Hold information about the telemetry context /// public interface ITelemetryContext { object GetProperty(string Name); } /// /// Interface to drive Database submission /// public interface IDatabaseDriver where Data : class { /// /// Submit collection of object to target Database, use TestContext to complete data modeling. /// /// /// /// bool SubmitDataItems(IEnumerable DataItems, ITelemetryContext Context); } /// /// Interface for Database Configuration /// public interface IDatabaseConfig where Data : class { void LoadConfig(string ConfigFilePath); IDatabaseDriver GetDriver(); } /// /// Interface for data type MySQL Configuration /// public interface IMySQLConfig where Data : class { /// /// Get Target Table name based on data type /// string GetTableName(); /// /// Get Target Table columns based on data type /// IEnumerable GetTableColumns(); /// Format the data for target table based on data type /// /// IEnumerable FormatDataForTable(Data InData, ITelemetryContext InContext); } public class MySQLDriver : IDatabaseDriver where Data : class { protected MySQLConfig Config; public MySQLDriver(MySQLConfig InConfig) { Config = InConfig; if (string.IsNullOrEmpty(Config.ConfigString)) { throw new AutomationException(string.Format("Database Driver '{0}' not configured.", this.GetType().FullName)); } if (string.IsNullOrEmpty(Config.DatabaseName)) { throw new AutomationException(string.Format("Database Driver '{0}' not configured properly, missing Database name.", this.GetType().FullName)); } } public override string ToString() { return Config.GetConfigValue("Server"); } public object Insert(string Table, IEnumerable Columns, IEnumerable> Rows) { string SqlQuery = string.Format( "INSERT INTO `{0}`.{1} ({2}) VALUES {3}", Config.DatabaseName, Table, string.Join(", ", Columns), string.Join(", ", Rows.Select(R => string.Format("({0})", string.Join(", ", R.Select(V => string.Format("'{0}'", V)))))) ); return MySqlHelper.ExecuteScalar(Config.ConfigString, SqlQuery); } public bool SubmitDataItems(IEnumerable DataRows, ITelemetryContext TestContext) { if (Config is IMySQLConfig DataConfig) { object Value = Insert( DataConfig.GetTableName(), DataConfig.GetTableColumns(), DataRows.Select(D => DataConfig.FormatDataForTable(D, TestContext)) ); return Value != null; } else { Log.Error("MySQL configuration '{0}' does not known how to handle {1}.", Config.GetType().FullName, typeof(Data).FullName); } return false; } } public abstract class MySQLConfig : IDatabaseConfig, IMySQLConfig where Data : class { public string ConfigString { get; protected set; } public string DatabaseName { get; protected set; } protected Dictionary KeyValuePairs = null; public virtual void LoadConfig(string ConfigFilePath) { ConfigString = string.Empty; DatabaseName = string.Empty; KeyValuePairs = null; if (File.Exists(ConfigFilePath)) { using (StreamReader ConnectionReader = new StreamReader(ConfigFilePath)) { ConfigString = ConnectionReader.ReadLine(); } if (string.IsNullOrEmpty(ConfigString)) { Log.Warning("Properly found config file, but couldn't read a valid connection string."); return; } else { Log.Info("Found MySQL connection string from config file."); } } else { Log.Error("Could not find connection string config file at '{0}'.", ConfigFilePath); return; } DatabaseName = GetConfigValue("database"); if (string.IsNullOrEmpty(DatabaseName)) { Log.Warning("Missing MySQL Database name in config file '{0}'.", ConfigFilePath); return; } } public string GetConfigValue(string Key) { if (string.IsNullOrEmpty(ConfigString)) { return null; } if (KeyValuePairs == null) { KeyValuePairs = ConfigString.Split(';').Where(KeyValue => KeyValue.Contains('=')) .Select(KeyValue => KeyValue.Split('=', 2)) .ToDictionary( KeyValue => KeyValue[0].Trim(), KeyValue => KeyValue[1].Trim(), StringComparer.InvariantCultureIgnoreCase ); } string FoundValue; if (KeyValuePairs.TryGetValue(Key, out FoundValue)) { return FoundValue; } return string.Empty; } public IDatabaseDriver GetDriver() { return new MySQLDriver(this); } /// /// Get Target Table name based on data type /// public abstract string GetTableName(); /// /// Get Target Table columns based on data type /// public abstract IEnumerable GetTableColumns(); /// /// Format the data for target table based on data type /// /// public abstract IEnumerable FormatDataForTable(Data InData, ITelemetryContext InContext); } public class DatabaseConfigManager where Data : class { protected static IEnumerable> Configs; static DatabaseConfigManager() { Configs = Gauntlet.Utils.InterfaceHelpers.FindImplementations>(); } public static IDatabaseConfig GetConfigByName(string Name) { return Configs.Where(C => string.Equals(C.GetType().Name, Name, StringComparison.OrdinalIgnoreCase)).FirstOrDefault(); } } }