diff --git a/Arduino/Display/Display.ino b/Arduino/Display/Display.ino index 204f465..c89c112 100644 --- a/Arduino/Display/Display.ino +++ b/Arduino/Display/Display.ino @@ -50,7 +50,7 @@ void doJob(String task, String value) { co = 0x00539F; //Rwth Color } job = value.toInt(); - Rb.fillRectangle(1, 2, 6, 7, 0x000000); + Rb.fillRectangle(1, 2, 7, 6, 0x000000); Rb.drawChar(b, 1, 1, co); } else if(task == "online") { Rb.setPixelXY(0,7,value.toInt()==0?0xFF0000:0x00FF00); diff --git a/Arduino/Zeit/Zeit.ino b/Arduino/Zeit/Zeit.ino index 1511082..7932f9e 100644 --- a/Arduino/Zeit/Zeit.ino +++ b/Arduino/Zeit/Zeit.ino @@ -42,7 +42,7 @@ void loadFromDisplay() { print_disp("getStoreData=1"); parse(disp.readStringUntil('\n')); } - if(keepAlive()) { + if(storeCount > 0 && keepAlive()) { doJob("getStore","1"); } } diff --git a/TimeKeeper/Database/DatabaseDriver.cs b/TimeKeeper/Database/DatabaseDriver.cs index 7da31e6..13726ee 100644 --- a/TimeKeeper/Database/DatabaseDriver.cs +++ b/TimeKeeper/Database/DatabaseDriver.cs @@ -10,518 +10,460 @@ using System.Data.SQLite; using MySql; using MySql.Data.Common; using MySql.Data.MySqlClient; +using TimeKeeper.Exceptions; -namespace BF2Statistics.Database -{ - public class DatabaseDriver : IDisposable - { - /// - /// Current DB Engine - /// - public DatabaseEngine DatabaseEngine { get; protected set; } +namespace TimeKeeper.Database { + public class DatabaseDriver : IDisposable { + /// + /// Current DB Engine + /// + public DatabaseEngine DatabaseEngine { get; protected set; } - /// - /// The database connection - /// - public DbConnection Connection { get; protected set; } + /// + /// The database connection + /// + public DbConnection Connection { get; protected set; } - /// - /// Returns whether the Database connection is open - /// - public bool IsConnected - { - get { return (Connection.State == ConnectionState.Open); } - } - - /// - /// Returns the current conenction state of the database - /// - public ConnectionState State - { - get { return Connection.State; } - } - - /// - /// Gets the number of queries ran by this instance - /// - public int NumQueries = 0; - - /// - /// Random, yes... But its used here when building queries dynamically - /// - protected static char Comma = ','; - - /// - /// Indicates whether the disposed method was called - /// - protected bool IsDisposed = false; - - /// - /// Constructor - /// - /// The string name, for the GetDatabaseEngine() method - /// The Database server IP Address - /// The Database server Port Number - /// The name of the database - /// A username, with database privliages - /// The password to the User - public DatabaseDriver(string Engine, string Host, int Port, string DatabaseName, string User, string Pass) - { - // Set class variables, and create a new connection builder - this.DatabaseEngine = GetDatabaseEngine(Engine); - DbConnectionStringBuilder Builder; - - // Establish the connection - if (this.DatabaseEngine == DatabaseEngine.Sqlite) - { - // Create the connection - Builder = new SQLiteConnectionStringBuilder(); - Builder.Add("Data Source", Path.Combine(Program.RootPath, DatabaseName + ".sqlite3")); - Connection = new SQLiteConnection(Builder.ConnectionString); - } - else if (this.DatabaseEngine == DatabaseEngine.Mysql) - { - // Create the connection - Builder = new MySqlConnectionStringBuilder(); - Builder.Add("Server", Host); - Builder.Add("Port", Port); - Builder.Add("User ID", User); - Builder.Add("Password", Pass); - Builder.Add("Database", DatabaseName); - Builder.Add("Convert Zero Datetime", "true"); - Connection = new MySqlConnection(Builder.ConnectionString); - } - else - { - throw new Exception("Invalid Database type."); - } - } - - /// - /// Destructor - /// - ~DatabaseDriver() - { - Dispose(); - } - - /// - /// Disposes the DB connection - /// - public void Dispose() - { - if(Connection != null && !IsDisposed) - { - try - { - Connection.Close(); - Connection.Dispose(); - } - catch (ObjectDisposedException) { } - - IsDisposed = true; - } - } - - /// - /// Opens the database connection - /// - public void Connect() - { - if (Connection.State != ConnectionState.Open) - { - try - { - Connection.Open(); - } - catch (Exception e) - { - throw new DbConnectException("Unable to etablish database connection", e); - } - } - } - - /// - /// Closes the connection to the database - /// - public void Close() - { - try { - if (Connection.State != ConnectionState.Closed) - Connection.Close(); - } - catch (ObjectDisposedException) { } - } - - /// - /// Creates a new command to be executed on the database - /// - /// - public DbCommand CreateCommand(string QueryString) - { - if (DatabaseEngine == Database.DatabaseEngine.Sqlite) - return new SQLiteCommand(QueryString, Connection as SQLiteConnection); - else - return new MySqlCommand(QueryString, Connection as MySqlConnection); - } - - /// - /// Creates a DbParameter using the current Database engine's Parameter object - /// - /// - public DbParameter CreateParam() - { - if (DatabaseEngine == Database.DatabaseEngine.Sqlite) - return (new SQLiteParameter() as DbParameter); - else - return (new MySqlParameter() as DbParameter); - } - - /// - /// Queries the database, and returns a result set - /// - /// The SQL Statement to run on the database - /// - public List> Query(string Sql) - { - return this.Query(Sql, new List()); - } - - /// - /// Queries the database, and returns a result set - /// - /// The SQL Statement to run on the database - /// Additional parameters are parameter values for the query. - /// The first parameter replaces @P0, second @P1 etc etc. - /// - /// - public List> Query(string Sql, params object[] Items) - { - List Params = new List(Items.Length); - for (int i = 0; i < Items.Length; i++) - { - DbParameter Param = this.CreateParam(); - Param.ParameterName = "@P" + i; - Param.Value = Items[i]; - Params.Add(Param); - } - - return this.Query(Sql, Params); - } - - /// - /// Queries the database, and returns a result set - /// - /// The SQL Statement to run on the database - /// A list of sql params to add to the command - /// - public List> Query(string Sql, List Params) - { - // Create our Rows result - List> Rows = new List>(); - - // Increase Query Count - NumQueries++; - - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - { - // Add params - foreach (DbParameter Param in Params) - Command.Parameters.Add(Param); - - // Execute the query - using (DbDataReader Reader = Command.ExecuteReader()) - { - // If we have rows, add them to the list - if (Reader.HasRows) - { - // Add each row to the rows list - while (Reader.Read()) - { - Dictionary Row = new Dictionary(Reader.FieldCount); - for (int i = 0; i < Reader.FieldCount; ++i) - Row.Add(Reader.GetName(i), Reader.GetValue(i)); - - Rows.Add(Row); - } - } - - // Cleanup - Reader.Close(); - } - } - - // Return Rows - return Rows; - } - - /// - /// Queries the database, and returns 1 row at a time until all rows are returned - /// - /// The SQL Statement to run on the database - /// - public IEnumerable> QueryReader(string Sql) - { - // Increase Query Count - NumQueries++; - - // Create the SQL Command, and execute the reader - using (DbCommand Command = this.CreateCommand(Sql)) - using (DbDataReader Reader = Command.ExecuteReader()) - { - // If we have rows, add them to the list - if (Reader.HasRows) - { - // Add each row to the rows list - while (Reader.Read()) - { - Dictionary Row = new Dictionary(Reader.FieldCount); - for (int i = 0; i < Reader.FieldCount; ++i) - Row.Add(Reader.GetName(i), Reader.GetValue(i)); - - yield return Row; - } - } - - // Cleanup - Reader.Close(); - } - } - - /// - /// Executes a command, and returns 1 row at a time until all rows are returned - /// - /// The database command to execute the reader on - /// - public IEnumerable> QueryReader(DbCommand Command) - { - // Increase Query Count - NumQueries++; - - // Execute the query - using (Command) - using (DbDataReader Reader = Command.ExecuteReader()) - { - // If we have rows, add them to the list - if (Reader.HasRows) - { - // Add each row to the rows list - while (Reader.Read()) - { - Dictionary Row = new Dictionary(Reader.FieldCount); - for (int i = 0; i < Reader.FieldCount; ++i) - Row.Add(Reader.GetName(i), Reader.GetValue(i)); - - yield return Row; - } - } - - // Cleanup - Reader.Close(); - } - } - - - /// - /// Executes a command, and returns the resulting rows - /// - /// The database command to execute the reader on - /// - public List> ExecuteReader(DbCommand Command) - { - // Execute the query - List> Rows = new List>(); - - // Increase Query Count - NumQueries++; - - using (Command) - using (DbDataReader Reader = Command.ExecuteReader()) - { - // If we have rows, add them to the list - if (Reader.HasRows) - { - // Add each row to the rows list - while (Reader.Read()) - { - Dictionary Row = new Dictionary(Reader.FieldCount); - for (int i = 0; i < Reader.FieldCount; ++i) - Row.Add(Reader.GetName(i), Reader.GetValue(i)); - - Rows.Add(Row); - } - } - - // Cleanup - Reader.Close(); - } - - // Return Rows - return Rows; - } - - /// - /// Executes a statement on the database (Update, Delete, Insert) - /// - /// The SQL statement to be executes - /// Returns the number of rows affected by the statement - public int Execute(string Sql) - { - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - return Command.ExecuteNonQuery(); - } - - /// - /// Executes a statement on the database (Update, Delete, Insert) - /// - /// The SQL statement to be executed - /// A list of Sqlparameters - /// Returns the number of rows affected by the statement - public int Execute(string Sql, List Params) - { - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - { - // Increase Query Count - NumQueries++; - - // Add params - foreach (DbParameter Param in Params) - Command.Parameters.Add(Param); - - // Execute command, and dispose of the command - return Command.ExecuteNonQuery(); - } - } - - /// - /// Executes a statement on the database (Update, Delete, Insert) - /// - /// The SQL statement to be executed - /// Additional parameters are parameter values for the query. - /// The first parameter replaces @P0, second @P1 etc etc. - /// - /// Returns the number of rows affected by the statement - public int Execute(string Sql, params object[] Items) - { - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - { - // Add params - for (int i = 0; i < Items.Length; i++) - { - DbParameter Param = this.CreateParam(); - Param.ParameterName = "@P" + i; - Param.Value = Items[i]; - Command.Parameters.Add(Param); - } - - // Increase Query Count - NumQueries++; - - // Execute command, and dispose of the command - return Command.ExecuteNonQuery(); - } - } - - /// - /// Executes the query, and returns the first column of the first row in the result - /// set returned by the query. Additional columns or rows are ignored. - /// - /// The SQL statement to be executed - /// - public object ExecuteScalar(string Sql) - { - // Increase Query Count - NumQueries++; - - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - return Command.ExecuteScalar(); - } - - /// - /// Executes the query, and returns the first column of the first row in the result - /// set returned by the query. Additional columns or rows are ignored. - /// - /// The SQL statement to be executed - /// A list of Sqlparameters - /// - public object ExecuteScalar(string Sql, List Params) - { - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - { - // Increase Query Count - NumQueries++; - - // Add params - foreach (DbParameter Param in Params) - Command.Parameters.Add(Param); - - // Execute command, and dispose of the command - return Command.ExecuteScalar(); - } - } - - /// - /// Executes the query, and returns the first column of the first row in the result - /// set returned by the query. Additional columns or rows are ignored. - /// - /// The SQL statement to be executed - /// - /// - public object ExecuteScalar(string Sql, params object[] Items) - { - // Create the SQL Command - using (DbCommand Command = this.CreateCommand(Sql)) - { - // Add params - for (int i = 0; i < Items.Length; i++) - { - DbParameter Param = this.CreateParam(); - Param.ParameterName = "@P" + i; - Param.Value = Items[i]; - Command.Parameters.Add(Param); - } - - // Increase Query Count - NumQueries++; - - // Execute command, and dispose of the command - return Command.ExecuteScalar(); - } - } - - /// - /// Begins a new database transaction - /// - /// - public DbTransaction BeginTransaction() - { - return Connection.BeginTransaction(); - } - - /// - /// Begins a new database transaction - /// - /// - /// - public DbTransaction BeginTransaction(IsolationLevel Level) - { - return Connection.BeginTransaction(Level); - } - - /// - /// Converts a database string name to a DatabaseEngine type. - /// - /// - /// - public static DatabaseEngine GetDatabaseEngine(string Name) - { - return ((DatabaseEngine)Enum.Parse(typeof(DatabaseEngine), Name, true)); - } + /// + /// Returns whether the Database connection is open + /// + public bool IsConnected { + get { return (Connection.State == ConnectionState.Open); } } + + /// + /// Returns the current conenction state of the database + /// + public ConnectionState State { + get { return Connection.State; } + } + + /// + /// Gets the number of queries ran by this instance + /// + public int NumQueries = 0; + + /// + /// Random, yes... But its used here when building queries dynamically + /// + protected static char Comma = ','; + + /// + /// Indicates whether the disposed method was called + /// + protected bool IsDisposed = false; + + /// + /// Constructor + /// + /// The string name, for the GetDatabaseEngine() method + /// The Database server IP Address + /// The Database server Port Number + /// The name of the database + /// A username, with database privliages + /// The password to the User + public DatabaseDriver(string Engine, string Host, int Port, string DatabaseName, string User, string Pass, DatabaseEngine[] allowedEngines) { + // Set class variables, and create a new connection builder + this.DatabaseEngine = GetDatabaseEngine(Engine); + DbConnectionStringBuilder Builder; + + // Establish the connection + if(this.DatabaseEngine == DatabaseEngine.Sqlite && allowedEngines.Contains(DatabaseEngine.Sqlite)) { + // Create the connection + Builder = new SQLiteConnectionStringBuilder(); + Builder.Add("Data Source", Path.Combine(StaticConfig.RootPath, DatabaseName + ".sqlite3")); + Connection = new SQLiteConnection(Builder.ConnectionString); + } else if(this.DatabaseEngine == DatabaseEngine.Mysql && allowedEngines.Contains(DatabaseEngine.Mysql)) { + // Create the connection + Builder = new MySqlConnectionStringBuilder(); + Builder.Add("Server", Host); + Builder.Add("Port", Port); + Builder.Add("User ID", User); + Builder.Add("Password", Pass); + Builder.Add("Database", DatabaseName); + Builder.Add("Convert Zero Datetime", "true"); + Connection = new MySqlConnection(Builder.ConnectionString); + } else { + throw new Exception("Invalid Database type."); + } + } + + /// + /// Destructor + /// + ~DatabaseDriver() { + Dispose(); + } + + /// + /// Disposes the DB connection + /// + public void Dispose() { + if(Connection != null && !IsDisposed) { + try { + Connection.Close(); + Connection.Dispose(); + } catch(ObjectDisposedException) { } + + IsDisposed = true; + } + } + + /// + /// Opens the database connection + /// + public void Connect() { + if(Connection.State != ConnectionState.Open) { + try { + Connection.Open(); + } catch(Exception e) { + throw new DbConnectException("Unable to etablish database connection", e); + } + } + } + + /// + /// Closes the connection to the database + /// + public void Close() { + try { + if(Connection.State != ConnectionState.Closed) + Connection.Close(); + } catch(ObjectDisposedException) { } + } + + /// + /// Creates a new command to be executed on the database + /// + /// + public DbCommand CreateCommand(string QueryString) { + if(DatabaseEngine == Database.DatabaseEngine.Sqlite) + return new SQLiteCommand(QueryString, Connection as SQLiteConnection); + else + return new MySqlCommand(QueryString, Connection as MySqlConnection); + } + + /// + /// Creates a DbParameter using the current Database engine's Parameter object + /// + /// + public DbParameter CreateParam() { + if(DatabaseEngine == Database.DatabaseEngine.Sqlite) + return (new SQLiteParameter() as DbParameter); + else + return (new MySqlParameter() as DbParameter); + } + + /// + /// Queries the database, and returns a result set + /// + /// The SQL Statement to run on the database + /// + public List> Query(string Sql) { + return this.Query(Sql, new List()); + } + + /// + /// Queries the database, and returns a result set + /// + /// The SQL Statement to run on the database + /// Additional parameters are parameter values for the query. + /// The first parameter replaces @P0, second @P1 etc etc. + /// + /// + public List> Query(string Sql, params object[] Items) { + List Params = new List(Items.Length); + for(int i = 0; i < Items.Length; i++) { + DbParameter Param = this.CreateParam(); + Param.ParameterName = "@P" + i; + Param.Value = Items[i]; + Params.Add(Param); + } + + return this.Query(Sql, Params); + } + + /// + /// Queries the database, and returns a result set + /// + /// The SQL Statement to run on the database + /// A list of sql params to add to the command + /// + public List> Query(string Sql, List Params) { + // Create our Rows result + List> Rows = new List>(); + + // Increase Query Count + NumQueries++; + + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Add params + foreach(DbParameter Param in Params) + Command.Parameters.Add(Param); + + // Execute the query + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + Rows.Add(Row); + } + } + + // Cleanup + Reader.Close(); + } + } + + // Return Rows + return Rows; + } + + /// + /// Queries the database, and returns 1 row at a time until all rows are returned + /// + /// The SQL Statement to run on the database + /// + public IEnumerable> QueryReader(string Sql) { + // Increase Query Count + NumQueries++; + + // Create the SQL Command, and execute the reader + using(DbCommand Command = this.CreateCommand(Sql)) + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + yield return Row; + } + } + + // Cleanup + Reader.Close(); + } + } + + /// + /// Executes a command, and returns 1 row at a time until all rows are returned + /// + /// The database command to execute the reader on + /// + public IEnumerable> QueryReader(DbCommand Command) { + // Increase Query Count + NumQueries++; + + // Execute the query + using(Command) + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + yield return Row; + } + } + + // Cleanup + Reader.Close(); + } + } + + + /// + /// Executes a command, and returns the resulting rows + /// + /// The database command to execute the reader on + /// + public List> ExecuteReader(DbCommand Command) { + // Execute the query + List> Rows = new List>(); + + // Increase Query Count + NumQueries++; + + using(Command) + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + Rows.Add(Row); + } + } + + // Cleanup + Reader.Close(); + } + + // Return Rows + return Rows; + } + + /// + /// Executes a statement on the database (Update, Delete, Insert) + /// + /// The SQL statement to be executes + /// Returns the number of rows affected by the statement + public int Execute(string Sql) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) + return Command.ExecuteNonQuery(); + } + + /// + /// Executes a statement on the database (Update, Delete, Insert) + /// + /// The SQL statement to be executed + /// A list of Sqlparameters + /// Returns the number of rows affected by the statement + public int Execute(string Sql, List Params) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Increase Query Count + NumQueries++; + + // Add params + foreach(DbParameter Param in Params) + Command.Parameters.Add(Param); + + // Execute command, and dispose of the command + return Command.ExecuteNonQuery(); + } + } + + /// + /// Executes a statement on the database (Update, Delete, Insert) + /// + /// The SQL statement to be executed + /// Additional parameters are parameter values for the query. + /// The first parameter replaces @P0, second @P1 etc etc. + /// + /// Returns the number of rows affected by the statement + public int Execute(string Sql, params object[] Items) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Add params + for(int i = 0; i < Items.Length; i++) { + DbParameter Param = this.CreateParam(); + Param.ParameterName = "@P" + i; + Param.Value = Items[i]; + Command.Parameters.Add(Param); + } + + // Increase Query Count + NumQueries++; + + // Execute command, and dispose of the command + return Command.ExecuteNonQuery(); + } + } + + /// + /// Executes the query, and returns the first column of the first row in the result + /// set returned by the query. Additional columns or rows are ignored. + /// + /// The SQL statement to be executed + /// + public object ExecuteScalar(string Sql) { + // Increase Query Count + NumQueries++; + + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) + return Command.ExecuteScalar(); + } + + /// + /// Executes the query, and returns the first column of the first row in the result + /// set returned by the query. Additional columns or rows are ignored. + /// + /// The SQL statement to be executed + /// A list of Sqlparameters + /// + public object ExecuteScalar(string Sql, List Params) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Increase Query Count + NumQueries++; + + // Add params + foreach(DbParameter Param in Params) + Command.Parameters.Add(Param); + + // Execute command, and dispose of the command + return Command.ExecuteScalar(); + } + } + + /// + /// Executes the query, and returns the first column of the first row in the result + /// set returned by the query. Additional columns or rows are ignored. + /// + /// The SQL statement to be executed + /// + /// + public object ExecuteScalar(string Sql, params object[] Items) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Add params + for(int i = 0; i < Items.Length; i++) { + DbParameter Param = this.CreateParam(); + Param.ParameterName = "@P" + i; + Param.Value = Items[i]; + Command.Parameters.Add(Param); + } + + // Increase Query Count + NumQueries++; + + // Execute command, and dispose of the command + return Command.ExecuteScalar(); + } + } + + /// + /// Begins a new database transaction + /// + /// + public DbTransaction BeginTransaction() { + return Connection.BeginTransaction(); + } + + /// + /// Begins a new database transaction + /// + /// + /// + public DbTransaction BeginTransaction(IsolationLevel Level) { + return Connection.BeginTransaction(Level); + } + + /// + /// Converts a database string name to a DatabaseEngine type. + /// + /// + /// + public static DatabaseEngine GetDatabaseEngine(string Name) { + return ((DatabaseEngine)Enum.Parse(typeof(DatabaseEngine), Name, true)); + } + } } diff --git a/TimeKeeper/Database/DatabaseEngine.cs b/TimeKeeper/Database/DatabaseEngine.cs index f60591b..9e8aeac 100644 --- a/TimeKeeper/Database/DatabaseEngine.cs +++ b/TimeKeeper/Database/DatabaseEngine.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BF2Statistics.Database +namespace TimeKeeper.Database { public enum DatabaseEngine { diff --git a/TimeKeeper/Database/GamespyDatabase.cs b/TimeKeeper/Database/GamespyDatabase.cs deleted file mode 100644 index 689c35a..0000000 --- a/TimeKeeper/Database/GamespyDatabase.cs +++ /dev/null @@ -1,298 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace BF2Statistics.Database -{ - /// - /// A class to provide common tasks against the Gamespy Login Database - /// - public class GamespyDatabase : DatabaseDriver, IDisposable - { - /// - /// Constructor - /// - public GamespyDatabase() : - base( - MainForm.Config.GamespyDBEngine, - MainForm.Config.GamespyDBHost, - MainForm.Config.GamespyDBPort, - MainForm.Config.GamespyDBName, - MainForm.Config.GamespyDBUser, - MainForm.Config.GamespyDBPass - ) - { - // Try and Reconnect - try - { - Connect(); - - // Try to get the database version - try - { - if (base.Query("SELECT dbver FROM _version LIMIT 1").Count == 0) - throw new Exception(); - } - catch - { - // If an exception is thrown, table doesnt exist... fresh install - if (DatabaseEngine == DatabaseEngine.Sqlite) - base.Execute(Utils.GetResourceAsString("BF2Statistics.SQL.SQLite.Gamespy.sql")); - else - base.Execute(Utils.GetResourceAsString("BF2Statistics.SQL.MySQL.Gamespy.sql")); - } - } - catch (Exception) - { - if (Connection != null) - Connection.Dispose(); - - throw; - } - } - - /// - /// Destructor - /// - ~GamespyDatabase() - { - if (!IsDisposed) - base.Dispose(); - } - - /// - /// Fetches an account from the gamespy database - /// - /// The user's Nick - /// - public Dictionary GetUser(string Nick) - { - // Fetch the user - var Rows = base.Query("SELECT * FROM accounts WHERE name=@P0", Nick); - return (Rows.Count == 0) ? null : Rows[0]; - } - - /// - /// Fetches an account from the gamespy database - /// - /// The account player ID - /// - public Dictionary GetUser(int Pid) - { - // Fetch the user - var Rows = base.Query("SELECT * FROM accounts WHERE id=@P0", Pid); - return (Rows.Count == 0) ? null : Rows[0]; - } - - /// - /// Fetches an account from the gamespy database - /// - /// Account email - /// Account Password - /// - public Dictionary GetUser(string Email, string Password) - { - var Rows = base.Query("SELECT * FROM accounts WHERE email=@P0 AND password=@P1", Email, Password); - return (Rows.Count == 0) ? null : Rows[0]; - } - - /// - /// Returns a list of player names that are similar to the passed parameter - /// - /// - /// - public List GetUsersLike(string Nick) - { - // Generate our return list - List List = new List(); - var Rows = base.Query("SELECT name FROM accounts WHERE name LIKE @P0", "%" + Nick + "%"); - foreach (Dictionary Account in Rows) - List.Add(Account["name"].ToString()); - - return List; - } - - /// - /// Returns wether an account exists from the provided Nick - /// - /// - /// - public bool UserExists(string Nick) - { - // Fetch the user - return (base.Query("SELECT id FROM accounts WHERE name=@P0", Nick).Count != 0); - } - - /// - /// Returns wether an account exists from the provided Account Id - /// - /// - /// - public bool UserExists(int PID) - { - // Fetch the user - return (base.Query("SELECT name FROM accounts WHERE id=@P0", PID).Count != 0); - } - - /// - /// Creates a new Gamespy Account - /// - /// Used by the login server when a create account request is made - /// The Account Name - /// The Account Password - /// The Account Email Address - /// The Country Code for this Account - /// A bool indicating whether the account was created sucessfully - public bool CreateUser(string Nick, string Pass, string Email, string Country) - { - int Pid = 0; - - // Attempt to connect to stats database, and get a PID from there - /*try - { - // try see if the player ID exists in the stats database - using (StatsDatabase Db = new StatsDatabase()) - { - // NOTE: online account names in the stats DB start with a single space! - var Row = Db.Query("SELECT id FROM player WHERE upper(name) = upper(@P0)", " " + Nick); - Pid = (Row.Count == 0) ? GenerateAccountId() : Int32.Parse(Row[0]["id"].ToString()); - } - } - catch - {*/ - Pid = GenerateAccountId(); - //} - - // Create the user in the database - int Rows = base.Execute("INSERT INTO accounts(id, name, password, email, country) VALUES(@P0, @P1, @P2, @P3, @P4)", - Pid, Nick, Pass, Email, Country - ); - - return (Rows != 0); - } - - /// - /// Generates a new Account Id - /// - /// - private int GenerateAccountId() - { - var Row = base.Query("SELECT COALESCE(MAX(id), 500000000) AS max FROM accounts"); - int max = Int32.Parse(Row[0]["max"].ToString()) + 1; - return (max < 500000000) ? 500000000 : max; - } - - /// - /// Creates a new Gamespy Account - /// - /// Only used in the Gamespy Account Creation Form - /// The Profile Id to assign this account - /// The Account Name - /// The Account Password - /// The Account Email Address - /// The Country Code for this Account - /// A bool indicating whether the account was created sucessfully - public bool CreateUser(int Pid, string Nick, string Pass, string Email, string Country) - { - // Make sure the user doesnt exist! - if (UserExists(Pid)) - throw new Exception("Account ID is already taken!"); - else if(UserExists(Nick)) - throw new Exception("Account username is already taken!"); - - // Create the user in the database - int Rows = base.Execute("INSERT INTO accounts(id, name, password, email, country) VALUES(@P0, @P1, @P2, @P3, @P4)", - Pid, Nick, Pass, Email, Country - ); - - return (Rows != 0); - } - - /// - /// Updates an Accounts Country Code - /// - /// - /// - public void UpdateUser(string Nick, string Country) - { - base.Execute("UPDATE accounts SET country=@P0 WHERE name=@P1", Nick, Country); - } - - /// - /// Updates an Account's information by ID - /// - /// The Current Account ID - /// New Account ID - /// New Account Name - /// New Account Password - /// New Account Email Address - public void UpdateUser(int Id, int NewPid, string NewNick, string NewPassword, string NewEmail) - { - base.Execute("UPDATE accounts SET id=@P0, name=@P1, password=@P2, email=@P3 WHERE id=@P4", - NewPid, NewNick, NewPassword, NewEmail, Id); - } - - /// - /// Deletes a Gamespy Account - /// - /// - /// - public int DeleteUser(string Nick) - { - return base.Execute("DELETE FROM accounts WHERE name=@P0", Nick); - } - - /// - /// Deletes a Gamespy Account - /// - /// - /// - public int DeleteUser(int Pid) - { - return base.Execute("DELETE FROM accounts WHERE id=@P0", Pid); - } - - /// - /// Fetches a Gamespy Account id from an account name - /// - /// - /// - public int GetPID(string Nick) - { - var Rows = base.Query("SELECT id FROM accounts WHERE name=@P0", Nick); - return (Rows.Count == 0) ? 0 : Int32.Parse(Rows[0]["id"].ToString()); - } - - /// - /// Sets the Account (Player) Id for an account by Name - /// - /// The account Nick we are setting the new Pid for - /// The new Pid - /// - public int SetPID(string Nick, int Pid) - { - // If no user exists, return code -1 - if (!UserExists(Nick)) - return -1; - - // If the Pid already exists, return -2 - if (UserExists(Pid)) - return -2; - - // If PID is false, the PID is not taken - int Success = base.Execute("UPDATE accounts SET id=@P0 WHERE name=@P1", Pid, Nick); - return (Success > 0) ? 1 : 0; - } - - /// - /// Returns the number of accounts in the database - /// - /// - public int GetNumAccounts() - { - var Row = base.Query("SELECT COUNT(id) AS count FROM accounts"); - return Int32.Parse(Row[0]["count"].ToString()); - } - } -} diff --git a/TimeKeeper/Database/SQL/MySQL.Install.sql b/TimeKeeper/Database/SQL/MySQL.Install.sql new file mode 100644 index 0000000..ac6eda6 --- /dev/null +++ b/TimeKeeper/Database/SQL/MySQL.Install.sql @@ -0,0 +1,98 @@ +-- phpMyAdmin SQL Dump +-- version 3.4.11.1deb2+deb7u2 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Erstellungszeit: 26. Jan 2016 um 10:01 +-- Server Version: 5.6.25 +-- PHP-Version: 5.4.45-1~dotdeb+7.1 + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + +-- +-- Datenbank: `worktime` +-- + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `location` +-- + +CREATE TABLE IF NOT EXISTS `location` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `tag` varchar(10) NOT NULL, + `weeklength` float NOT NULL, + `days` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `month` +-- + +CREATE TABLE IF NOT EXISTS `month` ( + `year` int(11) NOT NULL, + `month` int(11) NOT NULL, + `duration` double NOT NULL, + `location` int(11) DEFAULT NULL, + UNIQUE KEY `year` (`year`,`month`,`location`), + KEY `location` (`location`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `work` +-- + +CREATE TABLE IF NOT EXISTS `work` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `date` date NOT NULL, + `start` time NOT NULL, + `stop` time NOT NULL, + `pause` int(11) DEFAULT NULL, + `type` enum('ok','free','we','ill','vac','feiertag') NOT NULL, + `notice` varchar(200) DEFAULT NULL, + `location` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `location` (`location`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `_version` +-- + +CREATE TABLE IF NOT EXISTS `_version` ( + `dbver` int(4) NOT NULL, + `dbdate` datetime NOT NULL, + PRIMARY KEY (`dbver`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Constraints der exportierten Tabellen +-- + +-- +-- Constraints der Tabelle `month` +-- +ALTER TABLE `month` + ADD CONSTRAINT `month_ibfk_1` FOREIGN KEY (`location`) REFERENCES `location` (`id`) ON DELETE SET NULL ON UPDATE SET NULL; + +-- +-- Constraints der Tabelle `work` +-- +ALTER TABLE `work` + ADD CONSTRAINT `work_ibfk_1` FOREIGN KEY (`location`) REFERENCES `location` (`id`) ON DELETE SET NULL ON UPDATE SET NULL; + +-- +-- Daten +-- + +INSERT INTO `_version` (`dbver` ,`dbdate`) VALUES ('1', CURRENT_TIMESTAMP); diff --git a/TimeKeeper/Database/TDatabase.cs b/TimeKeeper/Database/TDatabase.cs new file mode 100644 index 0000000..12c0f1c --- /dev/null +++ b/TimeKeeper/Database/TDatabase.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TimeKeeper.Models.Types; + +namespace TimeKeeper.Database { + public class TDatabase : DatabaseDriver, IDisposable { + private static TDatabase instance; + + private TDatabase() : base(StaticConfig.DbConfig.Engine, StaticConfig.DbConfig.Host, StaticConfig.DbConfig.Port, StaticConfig.DbConfig.Db, StaticConfig.DbConfig.User, StaticConfig.DbConfig.Pass, new DatabaseEngine[] { DatabaseEngine.Mysql}) { + // Try and Reconnect + try { + Connect(); + + // Try to get the database version + try { + if(base.Query("SELECT dbver FROM _version LIMIT 1").Count == 0) + throw new Exception(); + } catch { + base.Execute(Utils.GetResourceAsString("TimeKeeper.Database.SQL.MySQL.Install.sql")); + } + } catch(Exception) { + if(Connection != null) + Connection.Dispose(); + + throw; + } + } + + public static TDatabase getInstance() { + if(instance == null) { + instance = new TDatabase(); + } + return instance; + } + + ~TDatabase() { + if(!IsDisposed) + base.Dispose(); + } + + internal void addWorking(WorkMessage m) { + List> dayItems = this.getWorkOnDay(m.time); + if(dayItems.Count == 0 && m.working == 1) { + this.insertStartWork(m.time, m.jobID); + } else if(dayItems.Count > 0) { + int started = -1; + int job = -1; + foreach(Dictionary dayItem in dayItems) { + if((TimeSpan)dayItem["stop"] == TimeSpan.Zero) { + started = (int)dayItem["id"]; + job = (int)dayItem["location"]; + break; + } + } + if(started != -1 && m.working == 0 && m.jobID == job) { + this.updateStopWorking(started, m.time); + } else if(started == -1 && m.working == 1) { + this.insertStartWork(m.time, m.jobID); + } else { + throw new NotImplementedException(); + } + } else { + throw new NotImplementedException(); + } + } + + private void updateStopWorking(Int32 started, DateTime time) { + base.Execute("UPDATE `work` SET stop=@P0 WHERE id=@P1", + time.ToString("HH:mm:ss"), started.ToString()); + } + + internal bool insertStartWork(DateTime time, Int32 jobID) { + int Rows = base.Execute("INSERT INTO `work` (`date`, `start`, `type`, `location`) VALUES (@P0, @P1, @P2, @P3)", + time.ToString("yyyy-MM-dd"), time.ToString("HH:mm:ss"), "ok", jobID.ToString() + ); + return (Rows != 0); + } + + internal List> getWorkOnDay(DateTime time) { + return base.Query("SELECT * FROM `work` WHERE date=@P0 ORDER BY `start` ASC", time.ToString("yyyy-MM-dd")); + } + + /// + /// Returns the number of accounts in the database + /// + /// + public int GetNumAccounts() { + var Row = base.Query("SELECT COUNT(id) AS count FROM accounts"); + return Int32.Parse(Row[0]["count"].ToString()); + } + } +} diff --git a/TimeKeeper/Exceptions/DbConnectException.cs b/TimeKeeper/Exceptions/DbConnectException.cs new file mode 100644 index 0000000..71545b6 --- /dev/null +++ b/TimeKeeper/Exceptions/DbConnectException.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimeKeeper.Exceptions { + class DbConnectException : Exception { + public DbConnectException(string Message, Exception Inner) : base(Message, Inner) { } + } +} diff --git a/TimeKeeper/Misc/StaticConfig.cs b/TimeKeeper/Misc/StaticConfig.cs new file mode 100644 index 0000000..99fba76 --- /dev/null +++ b/TimeKeeper/Misc/StaticConfig.cs @@ -0,0 +1,17 @@ +using BlubbFish.Utils; +using System.Windows.Forms; + +namespace TimeKeeper { + class StaticConfig { + public static class DbConfig { + private static InIReader i = InIReader.getInstance("settings.ini"); + public static string Engine { get { return i.getValue("database", "engine"); } } + public static string Host { get { return i.getValue("database", "host"); } } + public static int Port { get { return int.Parse(i.getValue("database", "port")); } } + public static string Db { get { return i.getValue("database", "db"); } } + public static string User { get { return i.getValue("database", "user"); } } + public static string Pass { get { return i.getValue("database", "pass"); } } + } + public static readonly string RootPath = Application.StartupPath; + } +} diff --git a/TimeKeeper/Misc/Utils.cs b/TimeKeeper/Misc/Utils.cs new file mode 100644 index 0000000..6f2a9e1 --- /dev/null +++ b/TimeKeeper/Misc/Utils.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace TimeKeeper { + class Utils { + public static string GetResourceAsString(string ResName) { + string Res = ""; + using(Stream ResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ResName)) { + using(StreamReader Reader = new StreamReader(ResourceStream)) { + Res = Reader.ReadToEnd(); + } + } + return Res; + } + } +} diff --git a/TimeKeeper/Models/MDatabase.cs b/TimeKeeper/Models/MDatabase.cs new file mode 100644 index 0000000..cf737d7 --- /dev/null +++ b/TimeKeeper/Models/MDatabase.cs @@ -0,0 +1,31 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimeKeeper.Database; +using TimeKeeper.Models.Types; + +namespace TimeKeeper.Models { + class Database : OwnModel { + private TDatabase database; + + public Queue Messages { get; internal set; } + + protected override void init() { + this.database = TDatabase.getInstance(); + } + + private Database() { + this.init(); + } + + internal void checkinMessages() { + while(this.Messages.Count > 0) { + WorkMessage m = this.Messages.Dequeue(); + this.database.addWorking(m); + } + } + } +} diff --git a/TimeKeeper/Models/MTray.cs b/TimeKeeper/Models/MTray.cs index 0f6dedb..d7d117d 100644 --- a/TimeKeeper/Models/MTray.cs +++ b/TimeKeeper/Models/MTray.cs @@ -18,10 +18,12 @@ namespace TimeKeeper.Models { private Thread setTimeThread; private InIReader settingsfile; private FileLogger sLogger; - private Stack MessagesValue = new Stack(); + private Queue MessagesValue = new Queue(); + private Database DatabaseModel; + private Boolean initComplete = false; private Tray() { - this.sLogger = FileLogger.getInstance("serial.log", true); + this.sLogger = FileLogger.getInstance("serial.log", false); this.init(); } @@ -35,13 +37,15 @@ namespace TimeKeeper.Models { set { this.OffsetTimeValue = value; this.update(); } } - public Stack Messages { + public Queue Messages { get { return this.MessagesValue; } } - public void MessagesPush(WorkMessages m) { - this.MessagesValue.Push(m); + public void MessagesPush(WorkMessage m) { + this.MessagesValue.Enqueue(m); this.update(); + this.DatabaseModel.Messages = this.Messages; + this.DatabaseModel.checkinMessages(); } override protected void init() { @@ -52,6 +56,7 @@ namespace TimeKeeper.Models { this.serialConnectThread.Start(); this.setTimeThread = new Thread(timeRunner); this.setTimeThread.Start(); + this.DatabaseModel = Database.Instance; } internal void Dispose() { @@ -63,7 +68,9 @@ namespace TimeKeeper.Models { } private void timeRunner() { - Thread.Sleep(1000 * 10); + while(!this.initComplete) { + Thread.Sleep(100); + } while(true) { DateTime n = DateTime.UtcNow; this.DataSendHandler("time=" + ((int)((n - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds)).ToString()); @@ -90,21 +97,23 @@ namespace TimeKeeper.Models { private void DataReceivedHandler(Object sender, SerialDataReceivedEventArgs e) { SerialPort sp = (SerialPort)sender; string s = sp.ReadLine().Trim(); - sLogger.setLine("<-: " + s); + sLogger.setLine("<-: " + s, DateTime.Now); this.parseSerial(s); } [MethodImpl(MethodImplOptions.Synchronized)] private void DataSendHandler(String v) { - sLogger.setLine("->: " + v); + sLogger.setLine("->: " + v, DateTime.Now); this.serial.WriteLine(v); } private void parseSerial(String s) { if(s == "requestKeep=1") { this.DataSendHandler("keep=1"); - } else if(s == "Init...." || s == "Init loading!" || s == "Init finished!") { + } else if(s == "Init...." || s == "Init loading!") { //Ignore that Stuff + } else if(s == "Init finished!") { + this.initComplete = true; } else if((s.Length > 4 && s.Substring(0, 4) == "d->:") || (s.Length > 4 && s.Substring(0, 4) == "i<-:")) { //Ignore that Stuff also.... } else if(s.Length > 2 && s.Substring(0, 2) == "t=") { @@ -134,7 +143,7 @@ namespace TimeKeeper.Models { working = int.Parse(t[1]); } } - this.MessagesPush(new WorkMessages(userID, time, jobID, working)); + this.MessagesPush(new WorkMessage(userID, time, jobID, working)); } private void setOffset(String v) { diff --git a/TimeKeeper/Models/Types/WorkMessages.cs b/TimeKeeper/Models/Types/WorkMessage.cs similarity index 74% rename from TimeKeeper/Models/Types/WorkMessages.cs rename to TimeKeeper/Models/Types/WorkMessage.cs index c529668..4af57ad 100644 --- a/TimeKeeper/Models/Types/WorkMessages.cs +++ b/TimeKeeper/Models/Types/WorkMessage.cs @@ -5,13 +5,13 @@ using System.Text; using System.Threading.Tasks; namespace TimeKeeper.Models.Types { - class WorkMessages { + class WorkMessage { public Int32 jobID; public DateTime time; public Int64 userID; public Int32 working; - public WorkMessages(Int64 userID, DateTime time, Int32 jobID, Int32 working) { + public WorkMessage(Int64 userID, DateTime time, Int32 jobID, Int32 working) { this.userID = userID; this.time = time; this.jobID = jobID; diff --git a/TimeKeeper/Program.cs b/TimeKeeper/Program.cs index 953e0e5..be7e5de 100644 --- a/TimeKeeper/Program.cs +++ b/TimeKeeper/Program.cs @@ -13,6 +13,9 @@ namespace TimeKeeper { t.execute(); Application.Run(); } catch(Exception e) { + if(e.InnerException != null) { + e = e.InnerException; + } MessageBox.Show("Fehler: " + e.Message + "\nStack: " + e.StackTrace, "Exception: " + e.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error); } } diff --git a/TimeKeeper/TimeKeeper.csproj b/TimeKeeper/TimeKeeper.csproj index 97d3a5e..e873357 100644 --- a/TimeKeeper/TimeKeeper.csproj +++ b/TimeKeeper/TimeKeeper.csproj @@ -13,7 +13,7 @@ 512 - AnyCPU + x64 true full false @@ -23,7 +23,7 @@ 4 - AnyCPU + x64 pdbonly true bin\Release\ @@ -38,8 +38,15 @@ Resources\Icons\main.ico + + ..\lib\MySql.Data.dll + + + False + ..\lib\System.Data.SQLite.dll + @@ -51,9 +58,15 @@ + + + + + + - + @@ -61,6 +74,7 @@ True Resources.resx + Form @@ -89,10 +103,12 @@ + +