diff --git a/TODO b/TODO index 51a0ca71..379524c9 100644 --- a/TODO +++ b/TODO @@ -13,6 +13,7 @@ - Use Inotify like system to watch modified/added files? - count scan import errors - handle access rights problems (instead of aborting) +- make a single connection pool and make everybody use it (database, UI sessions, etc.) [Metadata] - OGG metadata -> properly handle metadata nested in the audio stream @@ -39,6 +40,7 @@ [Settings] - logout users that are being changed (loss of admin admin rights), or make sure they are still admin when they make changes - "signal not exposed" problem if a user logout and login again. Bad resource destruction? + - add a scroll area in order for settings to work on mobile devices [user/transcoding] - Prefered codecs for video - use a slider instead of a combo box for the bitrates? @@ -71,6 +73,7 @@ [Lms API] - Implement partial text search options in the GetXXX messages +- Make it REST ? [REST API] - Make another dedicated REST API. Maybe use the SubSonic API or Ampache API? diff --git a/src/database-updater/DatabaseUpdater.cpp b/src/database-updater/DatabaseUpdater.cpp index 5dc2af7a..5f3159f0 100644 --- a/src/database-updater/DatabaseUpdater.cpp +++ b/src/database-updater/DatabaseUpdater.cpp @@ -19,7 +19,6 @@ #include -#include #include #include @@ -73,7 +72,7 @@ isFileSupported(const boost::filesystem::path& file, const std::vector res; std::vector rootDirs = Database::MediaDirectory::getByType(session, type); - BOOST_FOREACH(Database::MediaDirectory::pointer rootDir, rootDirs) + for (auto rootDir : rootDirs) res.push_back(rootDir->getPath()); return res; @@ -102,10 +101,10 @@ namespace DatabaseUpdater { using namespace Database; -Updater::Updater(boost::filesystem::path dbPath, MetaData::Parser& parser) +Updater::Updater(Wt::Dbo::SqlConnectionPool &connectionPool, MetaData::Parser& parser) : _running(false), _scheduleTimer(_ioService), -_db(dbPath), +_db(connectionPool), _metadataParser(parser) { _ioService.setThreadCount(1); @@ -114,14 +113,14 @@ _metadataParser(parser) void Updater::setAudioExtensions(const std::vector& extensions) { - BOOST_FOREACH(const std::string& extension, extensions) + for (const std::string& extension : extensions) _audioExtensions.push_back("." + extension); } void Updater::setVideoExtensions(const std::vector& extensions) { - BOOST_FOREACH(const std::string& extension, extensions) + for (const std::string& extension : extensions) _videoExtensions.push_back("." + extension); } @@ -226,7 +225,7 @@ Updater::process(boost::system::error_code err) { Wt::Dbo::Transaction transaction(_db.getSession()); std::vector mediaDirectories = MediaDirectory::getAll(_db.getSession()); - BOOST_FOREACH(MediaDirectory::pointer directory, mediaDirectories) + for (MediaDirectory::pointer directory : mediaDirectories) rootDirectories.push_back( std::make_pair( directory->getPath(), directory->getType() )); } @@ -604,7 +603,7 @@ Updater::checkFile(const boost::filesystem::path& p, const std::vector& extensions); void setVideoExtensions(const std::vector& extensions); diff --git a/src/database/DatabaseHandler.cpp b/src/database/DatabaseHandler.cpp index 81255287..ba5b4883 100644 --- a/src/database/DatabaseHandler.cpp +++ b/src/database/DatabaseHandler.cpp @@ -17,6 +17,9 @@ * along with LMS. If not, see . */ +#include +#include + #include #include #include @@ -72,11 +75,10 @@ Handler::getPasswordService() } -Handler::Handler(boost::filesystem::path db) -: -_dbBackend( db.string() ) +Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool) { - _session.setConnection(_dbBackend); + _session.setConnectionPool(connectionPool); + _session.mapClass("artist"); _session.mapClass("genre"); _session.mapClass("track"); @@ -94,17 +96,15 @@ _dbBackend( db.string() ) try { _session.createTables(); - _dbBackend.executeSql("CREATE INDEX artist_name_idx ON artist(name)"); - _dbBackend.executeSql("CREATE INDEX genre_name_idx ON genre(name)"); - _dbBackend.executeSql("CREATE INDEX release_name_idx ON release(name)"); - _dbBackend.executeSql("CREATE INDEX track_name_idx ON track(name)"); + _session.execute("CREATE INDEX artist_name_idx ON artist(name)"); + _session.execute("CREATE INDEX genre_name_idx ON genre(name)"); + _session.execute("CREATE INDEX release_name_idx ON release(name)"); + _session.execute("CREATE INDEX track_name_idx ON track(name)"); } catch(std::exception& e) { LMS_LOG(MOD_DB, SEV_ERROR) << "Cannot create tables: " << e.what(); } - _dbBackend.executeSql("pragma journal_mode=WAL"); - _users = new UserDatabase(_session); } @@ -149,5 +149,16 @@ Handler::getUser(const Wt::Auth::User& authUser) return user; } +Wt::Dbo::SqlConnectionPool* +Handler::createConnectionPool(boost::filesystem::path p) +{ + Wt::Dbo::backend::Sqlite3 *connection = new Wt::Dbo::backend::Sqlite3(p.string()); + + connection->executeSql("pragma journal_mode=WAL"); + + // connection->setProperty("show-queries", "true"); + return new Wt::Dbo::FixedSqlConnectionPool(connection, 10); +} + } // namespace Database diff --git a/src/database/DatabaseHandler.hpp b/src/database/DatabaseHandler.hpp index 4c81a10b..38978325 100644 --- a/src/database/DatabaseHandler.hpp +++ b/src/database/DatabaseHandler.hpp @@ -23,7 +23,8 @@ #include #include -#include +#include + #include #include #include @@ -39,7 +40,7 @@ class Handler { public: - Handler(boost::filesystem::path db); + Handler(Wt::Dbo::SqlConnectionPool& connectionPool); ~Handler(); Wt::Dbo::Session& getSession() { return _session; } @@ -56,12 +57,11 @@ class Handler static const Wt::Auth::AuthService& getAuthService(); static const Wt::Auth::PasswordService& getPasswordService(); + static Wt::Dbo::SqlConnectionPool* createConnectionPool(boost::filesystem::path db); private: - Wt::Dbo::backend::Sqlite3 _dbBackend; Wt::Dbo::Session _session; - UserDatabase* _users; Wt::Auth::Login _login; diff --git a/src/lms-api/server/Connection.cpp b/src/lms-api/server/Connection.cpp index 27203b62..f8d0e688 100644 --- a/src/lms-api/server/Connection.cpp +++ b/src/lms-api/server/Connection.cpp @@ -39,11 +39,11 @@ namespace Server { Connection::Connection(boost::asio::io_service& ioService, boost::asio::ssl::context& context, ConnectionManager& manager, - const boost::filesystem::path& dbPath) + Wt::Dbo::SqlConnectionPool& connectionPool) : _closing(false), _socket(ioService, context), _connectionManager(manager), -_requestHandler(dbPath) +_requestHandler(connectionPool) { LMS_LOG(MOD_REMOTE, SEV_DEBUG) << "Server::Connection::Connection, Creating connection"; } diff --git a/src/lms-api/server/Connection.hpp b/src/lms-api/server/Connection.hpp index 72fdca27..b254733f 100644 --- a/src/lms-api/server/Connection.hpp +++ b/src/lms-api/server/Connection.hpp @@ -50,7 +50,7 @@ class Connection : public std::enable_shared_from_this /// Construct a connection with the given io_service. explicit Connection(boost::asio::io_service& ioService, boost::asio::ssl::context& context, ConnectionManager& manager, - const boost::filesystem::path& dbPath); + Wt::Dbo::SqlConnectionPool& connectionPool); ssl_socket::lowest_layer_type& getSocket() {return _socket.lowest_layer();} diff --git a/src/lms-api/server/RequestHandler.cpp b/src/lms-api/server/RequestHandler.cpp index 3f27c21b..861a14d7 100644 --- a/src/lms-api/server/RequestHandler.cpp +++ b/src/lms-api/server/RequestHandler.cpp @@ -24,8 +24,8 @@ namespace LmsAPI { namespace Server { -RequestHandler::RequestHandler(boost::filesystem::path dbPath) -: _db( dbPath ), +RequestHandler::RequestHandler(Wt::Dbo::SqlConnectionPool &connectionPool) +: _db( connectionPool ), _authRequestHandler(_db), _audioCollectionRequestHandler(_db), _mediaRequestHandler(_db) diff --git a/src/lms-api/server/RequestHandler.hpp b/src/lms-api/server/RequestHandler.hpp index 84f184e3..9db747f4 100644 --- a/src/lms-api/server/RequestHandler.hpp +++ b/src/lms-api/server/RequestHandler.hpp @@ -20,7 +20,7 @@ #ifndef REMOTE_REQUEST_HANDLER #define REMOTE_REQUEST_HANDLER -#include +#include #include "messages.pb.h" @@ -37,7 +37,7 @@ class RequestHandler { public: - RequestHandler(boost::filesystem::path dbPath); + RequestHandler(Wt::Dbo::SqlConnectionPool& connectionPool); ~RequestHandler(); bool process(const ClientMessage& request, ServerMessage& response); diff --git a/src/lms-api/server/Server.cpp b/src/lms-api/server/Server.cpp index 6d095521..f7292d10 100644 --- a/src/lms-api/server/Server.cpp +++ b/src/lms-api/server/Server.cpp @@ -34,12 +34,12 @@ Server::Server(const endpoint_type& bindEndpoint, boost::filesystem::path certPath, boost::filesystem::path privKeyPath, boost::filesystem::path dhPath, - boost::filesystem::path dbPath) + Wt::Dbo::SqlConnectionPool& connectionPool) : _acceptor(_ioService, bindEndpoint, true /*SO_REUSEADDR*/), _connectionManager(), _context(boost::asio::ssl::context::tlsv1_server), -_dbPath(dbPath) +_connectionPool(connectionPool) { _ioService.setThreadCount(1); // TODO parametrize @@ -68,7 +68,7 @@ Server::start() void Server::asyncAccept() { - std::shared_ptr newConnection = std::make_shared(_ioService, _context, _connectionManager, _dbPath); + std::shared_ptr newConnection = std::make_shared(_ioService, _context, _connectionManager, _connectionPool); _acceptor.async_accept(newConnection->getSocket(), boost::bind(&Server::handleAccept, this, newConnection, boost::asio::placeholders::error)); diff --git a/src/lms-api/server/Server.hpp b/src/lms-api/server/Server.hpp index 57b77a2b..e92c9384 100644 --- a/src/lms-api/server/Server.hpp +++ b/src/lms-api/server/Server.hpp @@ -21,6 +21,7 @@ #define REMOTE_SERVER_HPP #include +#include #include #include @@ -49,7 +50,7 @@ class Server boost::filesystem::path certPath, boost::filesystem::path privKeyPath, boost::filesystem::path dhPath, - boost::filesystem::path dbPath); + Wt::Dbo::SqlConnectionPool& connectionPool); // Run the server's io_service loop. void start(); @@ -72,7 +73,7 @@ class Server boost::asio::ssl::context _context; /// The database to be used for requests - boost::filesystem::path _dbPath; + Wt::Dbo::SqlConnectionPool& _connectionPool; }; } // namespace Server diff --git a/src/main/main.cpp b/src/main/main.cpp index 54af36fb..697c727d 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -73,12 +73,15 @@ int main(int argc, char* argv[]) Transcode::AvConvTranscoder::init(); Database::Handler::configureAuth(); + // Initializing a connection pool to the database that will be shared along services + std::unique_ptr connectionPool( Database::Handler::createConnectionPool( ConfigReader::instance().getString("main.database.path") )); + LMS_LOG(MOD_MAIN, SEV_INFO) << "Starting services..."; - serviceManager.startService( std::make_shared() ); - serviceManager.startService( std::make_shared(boost::filesystem::path(argv[0]))); + serviceManager.startService( std::make_shared(*connectionPool)); + serviceManager.startService( std::make_shared(boost::filesystem::path(argv[0]), *connectionPool)); #if defined HAVE_LMSAPI - serviceManager.startService( std::make_shared( )); + serviceManager.startService( std::make_shared(*connectionPool)); #endif LMS_LOG(MOD_MAIN, SEV_NOTICE) << "Now running..."; @@ -86,7 +89,6 @@ int main(int argc, char* argv[]) serviceManager.run(); res = EXIT_SUCCESS; - } // TODO catch setting not found exception catch( libconfig::ParseException& e) diff --git a/src/service/DatabaseUpdateService.cpp b/src/service/DatabaseUpdateService.cpp index 73ae911a..09482f78 100644 --- a/src/service/DatabaseUpdateService.cpp +++ b/src/service/DatabaseUpdateService.cpp @@ -38,10 +38,9 @@ static std::vector splitStrings(const std::string& source) namespace Service { -DatabaseUpdateService::DatabaseUpdateService() +DatabaseUpdateService::DatabaseUpdateService(Wt::Dbo::SqlConnectionPool &connectionPool) : _metadataParser(), - _databaseUpdater( ConfigReader::instance().getString("main.database.path"), - _metadataParser) + _databaseUpdater( connectionPool, _metadataParser) { _databaseUpdater.setAudioExtensions(splitStrings(ConfigReader::instance().getString("main.database.audio_extensions"))); _databaseUpdater.setVideoExtensions(splitStrings(ConfigReader::instance().getString("main.database.video_extensions"))); diff --git a/src/service/DatabaseUpdateService.hpp b/src/service/DatabaseUpdateService.hpp index 55bfadaa..2dbb0b97 100644 --- a/src/service/DatabaseUpdateService.hpp +++ b/src/service/DatabaseUpdateService.hpp @@ -36,7 +36,7 @@ class DatabaseUpdateService : public Service typedef std::shared_ptr pointer; - DatabaseUpdateService(); + DatabaseUpdateService(Wt::Dbo::SqlConnectionPool &connectionPool); // Service interface void start(void); diff --git a/src/service/LmsAPIServerService.cpp b/src/service/LmsAPIServerService.cpp index 94c0cbb1..a5985b79 100644 --- a/src/service/LmsAPIServerService.cpp +++ b/src/service/LmsAPIServerService.cpp @@ -26,7 +26,7 @@ namespace Service { -LmsAPIService::LmsAPIService() +LmsAPIService::LmsAPIService(Wt::Dbo::SqlConnectionPool& connectionPool) : _server( boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string(ConfigReader::instance().getString("remote.listen-endpoint.addr")), @@ -34,7 +34,7 @@ LmsAPIService::LmsAPIService() ConfigReader::instance().getString("remote.ssl-crypto.cert"), ConfigReader::instance().getString("remote.ssl-crypto.key"), ConfigReader::instance().getString("remote.ssl-crypto.dh"), - ConfigReader::instance().getString("main.database.path")) + connectionPool) { } diff --git a/src/service/LmsAPIServerService.hpp b/src/service/LmsAPIServerService.hpp index 06aaa556..099f597f 100644 --- a/src/service/LmsAPIServerService.hpp +++ b/src/service/LmsAPIServerService.hpp @@ -20,7 +20,7 @@ #ifndef REMOTE_SERVER_SERVICE_HPP #define REMOTE_SERVER_SERVICE_HPP -#include +#include #include "config/config.h" @@ -34,7 +34,7 @@ class LmsAPIService : public Service { public: - LmsAPIService(); + LmsAPIService(Wt::Dbo::SqlConnectionPool& connectionPool); void start(void); void stop(void); diff --git a/src/service/UserInterfaceService.cpp b/src/service/UserInterfaceService.cpp index cf937897..2fec2fe1 100644 --- a/src/service/UserInterfaceService.cpp +++ b/src/service/UserInterfaceService.cpp @@ -17,6 +17,8 @@ * along with LMS. If not, see . */ +#include + #include "logger/Logger.hpp" #include "UserInterfaceService.hpp" @@ -26,7 +28,7 @@ namespace Service { -UserInterfaceService::UserInterfaceService( boost::filesystem::path runAppPath) +UserInterfaceService::UserInterfaceService( boost::filesystem::path runAppPath, Wt::Dbo::SqlConnectionPool& connectionPool) : _server(runAppPath.string()) { std::vector args; @@ -54,7 +56,7 @@ UserInterfaceService::UserInterfaceService( boost::filesystem::path runAppPath) _server.setServerConfiguration (argc, const_cast(argv)); // bind entry point - _server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, ConfigReader::instance().getString("main.database.path"))); + _server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, boost::ref(connectionPool))); } diff --git a/src/service/UserInterfaceService.hpp b/src/service/UserInterfaceService.hpp index c023a3f6..e9396471 100644 --- a/src/service/UserInterfaceService.hpp +++ b/src/service/UserInterfaceService.hpp @@ -32,7 +32,7 @@ class UserInterfaceService : public Service { public: - UserInterfaceService(boost::filesystem::path runAppPath); + UserInterfaceService(boost::filesystem::path runAppPath, Wt::Dbo::SqlConnectionPool& connectionPool); void start(void); void stop(void); diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index 7817c614..e41347d1 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -63,13 +63,13 @@ bool agentIsMobile() namespace UserInterface { Wt::WApplication* -LmsApplication::create(const Wt::WEnvironment& env, boost::filesystem::path dbPath) +LmsApplication::create(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool) { /* * You could read information from the environment to decide whether * the user has permission to start a new application */ - return new LmsApplication(env, dbPath); + return new LmsApplication(env, connectionPool); } LmsApplication* @@ -84,9 +84,9 @@ LmsApplication::instance() * constructor so it is typically also an argument for your custom * application constructor. */ -LmsApplication::LmsApplication(const Wt::WEnvironment& env, boost::filesystem::path dbPath) +LmsApplication::LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool) : Wt::WApplication(env), - _db(dbPath), + _db(connectionPool), _coverResource(nullptr) { @@ -182,6 +182,7 @@ LmsApplication::handleAuthEvent(void) Wt::WStackedWidget *contentsStack = new Wt::WStackedWidget(); contentsStack->setOverflow(Wt::WContainerWidget::OverflowAuto); + contentsStack->addStyleClass("contents"); // Setup a Left-aligned menu. Wt::WMenu *leftMenu = new Wt::WMenu(contentsStack); diff --git a/src/ui/LmsApplication.hpp b/src/ui/LmsApplication.hpp index 3a559953..b2946991 100644 --- a/src/ui/LmsApplication.hpp +++ b/src/ui/LmsApplication.hpp @@ -23,6 +23,8 @@ #include #include +#include + #include "database/DatabaseHandler.hpp" #include "resource/CoverResource.hpp" @@ -31,10 +33,10 @@ namespace UserInterface { class LmsApplication : public Wt::WApplication { public: - static Wt::WApplication *create(const Wt::WEnvironment& env, boost::filesystem::path dbPath); + static Wt::WApplication *create(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool); static LmsApplication* instance(); - LmsApplication(const Wt::WEnvironment& env, boost::filesystem::path dbPath); + LmsApplication(const Wt::WEnvironment& env, Wt::Dbo::SqlConnectionPool& connectionPool); // Session application data CoverResource* getCoverResource() { return _coverResource; } diff --git a/test/CheckDatabaseUser.cpp b/test/CheckDatabaseUser.cpp index 45a0f432..1c5a0ad3 100644 --- a/test/CheckDatabaseUser.cpp +++ b/test/CheckDatabaseUser.cpp @@ -29,7 +29,9 @@ int main(void) // Set up the database session Database::Handler::configureAuth(); - Database::Handler db("test_user.db"); + std::unique_ptr connectionPool( Database::Handler::createConnectionPool("test_user.db")); + + Database::Handler db(*connectionPool); Wt::Dbo::Transaction transaction(db.getSession()); diff --git a/test/CheckDbBasics.cpp b/test/CheckDbBasics.cpp index b67101b7..83267eb8 100644 --- a/test/CheckDbBasics.cpp +++ b/test/CheckDbBasics.cpp @@ -31,7 +31,9 @@ int main(void) boost::filesystem::remove("test.db"); - Handler db("test.db"); + std::unique_ptr connectionPool(Database::Handler::createConnectionPool( "test.db")); + + Handler db( *connectionPool ); // Create { diff --git a/test/DatabaseIntegrity.cpp b/test/DatabaseIntegrity.cpp index 4c0c0265..4b3d97dc 100644 --- a/test/DatabaseIntegrity.cpp +++ b/test/DatabaseIntegrity.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include "database/DatabaseHandler.hpp" @@ -32,7 +32,9 @@ int main(void) std::cout << "Starting test!" << std::endl; // Set up the long living database session - Database::Handler database("test.db"); + std::unique_ptr connectionPool(Database::Handler::createConnectionPool( "test.db")); + + Database::Handler database(*connectionPool); Wt::Dbo::Transaction transaction(database.getSession()); @@ -40,7 +42,8 @@ int main(void) std::cout << "Found " << tracks.size() << " tracks!" << std::endl; - BOOST_FOREACH(Database::Track::pointer track, tracks ) { + for (auto track : tracks) + { assert( !track->getName().empty() ); assert( !track->getGenres().empty() ); assert( !track->getDuration().is_not_a_date_time() );