From 524cc11b3fe1c096fbdeca0e276f2717f4e6af34 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Fri, 10 Nov 2017 16:29:19 +0100 Subject: [PATCH] Added possibility to configure the application with a config file or with command line arguments. Currently only selection of the database system and options for those systems are available. --- source/calendarwebapp/authenticator.d | 10 ++- source/calendarwebapp/configuration.d | 125 +++++++++++++++++++++----- source/calendarwebapp/event.d | 10 ++- 3 files changed, 114 insertions(+), 31 deletions(-) diff --git a/source/calendarwebapp/authenticator.d b/source/calendarwebapp/authenticator.d index 09d8d56..84ed9cb 100644 --- a/source/calendarwebapp/authenticator.d +++ b/source/calendarwebapp/authenticator.d @@ -92,6 +92,7 @@ private: @Autowire MySQLPool pool; @Autowire PasswordHasher passwordHasher; + @Value("mysql.table.users") string usersTableName; public: Nullable!AuthInfo checkUser(string username, string password) @trusted @@ -100,7 +101,8 @@ public: scope (exit) cn.close(); auto prepared = cn.prepare( - "SELECT id, username, passwordHash, privilege FROM users WHERE username = ?"); + "SELECT id, username, passwordHash, privilege FROM " + ~ usersTableName ~ " WHERE username = ?"); prepared.setArg(0, username); auto result = prepared.query(); /* checkHash should be called using vibe.core.concurrency.async to @@ -123,7 +125,7 @@ public: scope (exit) cn.close; auto prepared = cn.prepare( - "INSERT INTO users (username, passwordHash, privilege) VALUES(?, ?, ?)"); + "INSERT INTO " ~ usersTableName ~ " (username, passwordHash, privilege) VALUES(?, ?, ?)"); prepared.setArgs(authInfo.username, authInfo.passwordHash, authInfo.privilege.to!uint); prepared.exec(); } @@ -136,7 +138,7 @@ public: auto cn = pool.lockConnection(); scope (exit) cn.close; - auto prepared = cn.prepare("SELECT id, username, passwordHash, privilege FROM users"); + auto prepared = cn.prepare("SELECT id, username, passwordHash, privilege FROM " ~ usersTableName ~ ""); return prepared.querySet.map!(r => toAuthInfo(r)).inputRangeObject; } @@ -145,7 +147,7 @@ public: auto cn = pool.lockConnection(); scope (exit) cn.close; - auto prepared = cn.prepare("DELETE FROM users WHERE id = ?"); + auto prepared = cn.prepare("DELETE FROM " ~ usersTableName ~ " WHERE id = ?"); prepared.setArg(0, id.to!uint); prepared.exec(); } diff --git a/source/calendarwebapp/configuration.d b/source/calendarwebapp/configuration.d index ddf38af..a010cc4 100644 --- a/source/calendarwebapp/configuration.d +++ b/source/calendarwebapp/configuration.d @@ -3,32 +3,50 @@ module calendarwebapp.configuration; import botan.rng.auto_rng : AutoSeededRNG; import botan.rng.rng : RandomNumberGenerator; -import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator, - MySQLAuthenticator; +import calendarwebapp.authenticator : Authenticator; import calendarwebapp.calendarwebapp : CalendarWebapp; -import calendarwebapp.event : EventStore, MongoDBEventStore, MySQLEventStore; +import calendarwebapp.event : EventStore; import calendarwebapp.passhash : BcryptPasswordHasher, PasswordHasher; -import mysql : MySQLPool; - import poodinis; -import vibe.db.mongo.client : MongoClient; +import vibe.core.log : logInfo; import vibe.db.mongo.collection : MongoCollection; -import vibe.db.mongo.mongo : connectMongoDB; class Context : ApplicationContext { public: override void registerDependencies(shared(DependencyContainer) container) { - auto mongoClient = connectMongoDB("localhost"); - auto pool = new MySQLPool("localhost", "username", "password", "CalendarWebapp"); - container.register!MySQLPool.existingInstance(pool); - container.register!MongoClient.existingInstance(mongoClient); - container.register!(EventStore, MySQLEventStore); - container.register!(Authenticator, MySQLAuthenticator); + container.register!(ValueInjector!Arguments, AppArgumentsInjector); + auto arguments = container.resolve!(AppArgumentsInjector).get(""); + final switch (arguments.database) with (DatabaseArgument) + { + case mongodb: + import vibe.db.mongo.client : MongoClient; + import vibe.db.mongo.mongo : connectMongoDB; + import calendarwebapp.authenticator : MongoDBAuthenticator; + import calendarwebapp.event : MongoDBEventStore; + auto mongoClient = connectMongoDB(arguments.mongodb.host); + container.register!MongoClient.existingInstance(mongoClient); + container.register!(EventStore, MongoDBEventStore!()); + container.register!(Authenticator, MongoDBAuthenticator!()); + logInfo("Using MongoDB as database system"); + break; + case mysql: + import mysql : MySQLPool; + import calendarwebapp.authenticator : MySQLAuthenticator; + import calendarwebapp.event : MySQLEventStore; + + auto pool = new MySQLPool(arguments.mysql.host, arguments.mysql.username, + arguments.mysql.password, arguments.mysql.database); + container.register!MySQLPool.existingInstance(pool); + container.register!(EventStore, MySQLEventStore); + container.register!(Authenticator, MySQLAuthenticator); + logInfo("Using MySQL as database system"); + break; + } container.register!(PasswordHasher, BcryptPasswordHasher); container.register!(RandomNumberGenerator, AutoSeededRNG); container.register!CalendarWebapp; @@ -41,19 +59,18 @@ class StringInjector : ValueInjector!string { private: string[string] config; + @Value() Arguments arguments; + bool initialized = false; public: - this() const @safe pure nothrow - { - // dfmt off - config = ["Database name" : "CalendarWebapp", - "Users collection name": "users", - "Events collection name" : "events"]; - // dfmt on - } - override string get(string key) const @safe pure nothrow + override string get(string key) @safe nothrow { + if (!initialized) + { + config = ["MongoDB database name" : arguments.mongodb.database, + "mysql.table.users" : "users", "mysql.table.events" : "events"]; + } return config[key]; } } @@ -61,8 +78,10 @@ public: class MongoCollectionInjector : ValueInjector!MongoCollection { private: + import vibe.db.mongo.client : MongoClient; + @Autowire MongoClient mongoClient; - @Value("Database name") + @Value("MongoDB database name") string databaseName; public: @@ -71,3 +90,63 @@ public: return mongoClient.getCollection(databaseName ~ "." ~ key); } } + +class AppArgumentsInjector : ValueInjector!Arguments +{ +private: + Arguments arguments; +public: + + this() + { + import vibe.core.args : readOption; + + readOption("database", &arguments.database, "The database system to use."); + readOption("mongodb.host", &arguments.mongodb.host, + "The host of the MongoDB instance to use."); + readOption("mongodb.database", &arguments.mongodb.database, + "The name of the MongoDB database to use."); + readOption("mysql.host", &arguments.mysql.host, "The host of the MySQL instance to use."); + readOption("mysql.username", &arguments.mysql.username, + "The username to use for logging into the MySQL instance."); + readOption("mysql.password", &arguments.mysql.password, + "The password to use for logging into the MySQL instance."); + readOption("mysql.database", &arguments.mysql.database, + "The name of the MySQL database to use."); + } + + override Arguments get(string key) @safe + { + import std.exception : enforce; + + enforce(key == "", "There is only one instance of Arguments, to inject it use @Value()."); + return arguments; + } +} + +enum DatabaseArgument +{ + mongodb, + mysql +} + +struct MySQLArguments +{ + string host = "localhost"; + string username = "username"; + string password = "password"; + string database = "CalendarWebapp"; +} + +struct MongoDBArguments +{ + string host = "localhost"; + string database = "CalendarWebapp"; +} + +struct Arguments +{ + DatabaseArgument database = DatabaseArgument.mongodb; + MySQLArguments mysql; + MongoDBArguments mongodb; +} diff --git a/source/calendarwebapp/event.d b/source/calendarwebapp/event.d index bde695d..587c89a 100644 --- a/source/calendarwebapp/event.d +++ b/source/calendarwebapp/event.d @@ -73,6 +73,8 @@ class MySQLEventStore : EventStore private: import mysql; + @Value("mysql.table.events") string eventsTableName; + public: Event getEvent(string id) { @@ -80,7 +82,7 @@ public: scope (exit) cn.close; auto prepared = cn.prepare( - "SELECT id begin end name description type shout FROM events WHERE id = ?"); + "SELECT id begin end name description type shout FROM " ~ eventsTableName ~ " WHERE id = ?"); prepared.setArg(0, id.to!uint); return toEvent(prepared.query.front); } @@ -91,7 +93,7 @@ public: scope (exit) cn.close; auto prepared = cn.prepare( - "SELECT id, begin, end, name, description, type, shout FROM events"); + "SELECT id, begin, end, name, description, type, shout FROM " ~ eventsTableName ~ ""); return prepared.querySet.map!(r => toEvent(r)).inputRangeObject; } @@ -101,7 +103,7 @@ public: scope (exit) cn.close; auto prepared = cn.prepare( - "INSERT INTO events (begin, end, name, description, type, shout) VALUES(?, ?, ?, ?, ?, ?)"); + "INSERT INTO " ~ eventsTableName ~ " (begin, end, name, description, type, shout) VALUES(?, ?, ?, ?, ?, ?)"); prepared.setArgs(event.begin, event.end, event.name, event.description, event.type.to!uint, event.shout); prepared.exec(); @@ -119,7 +121,7 @@ public: auto cn = pool.lockConnection(); scope (exit) cn.close; - auto prepared = cn.prepare("DELETE FROM events WHERE id = ?"); + auto prepared = cn.prepare("DELETE FROM " ~ eventsTableName ~ " WHERE id = ?"); prepared.setArg(0, id.to!uint); prepared.exec(); }