[DB] Some code refactoring

This commit is contained in:
emeric
2016-04-15 23:43:59 +02:00
parent 0dace5cbdf
commit 7723d461a5
17 changed files with 164 additions and 454 deletions
+3
View File
@@ -2,6 +2,9 @@
[Book]
- Make the feature?
[Build]
- Makefile per directory. Use the include flags only where needed?
[Cover]
- Handle preferred cover file names ("front.xxx", "cover.xxx", ...)
- Implement a cache and a grabber from some web service (mandatory for artists?)
+2 -4
View File
@@ -7,6 +7,7 @@ lms_SOURCES = \
$(srcdir)/cover/CoverArtGrabber.cpp \
$(srcdir)/database/Artist.cpp \
$(srcdir)/database/DatabaseHandler.cpp \
$(srcdir)/database/DatabaseUpdater.cpp \
$(srcdir)/database/MediaDirectory.cpp \
$(srcdir)/database/Playlist.cpp \
$(srcdir)/database/Release.cpp \
@@ -15,13 +16,9 @@ lms_SOURCES = \
$(srcdir)/database/Track.cpp \
$(srcdir)/database/User.cpp \
$(srcdir)/database/Video.cpp \
$(srcdir)/database-updater/DatabaseUpdater.cpp \
$(srcdir)/database-updater/Checksum.cpp \
$(srcdir)/image/Image.cpp \
$(srcdir)/logger/Logger.cpp \
$(srcdir)/metadata/AvFormat.cpp \
$(srcdir)/service/ServiceManager.cpp \
$(srcdir)/service/DatabaseUpdateService.cpp \
$(srcdir)/ui/LmsApplication.cpp \
$(srcdir)/ui/auth/LmsAuth.cpp \
$(srcdir)/ui/audio/AudioPlayer.cpp \
@@ -57,6 +54,7 @@ lms_SOURCES = \
$(srcdir)/ui/settings/SettingsMediaDirectoryFormView.cpp \
$(srcdir)/ui/settings/SettingsUserFormView.cpp \
$(srcdir)/ui/settings/SettingsUsers.cpp \
$(srcdir)/utils/Checksum.cpp \
$(srcdir)/utils/Utils.cpp
if VIDEO
+2
View File
@@ -83,6 +83,8 @@ Handler::Handler(Wt::Dbo::SqlConnectionPool& connectionPool)
_session.mapClass<Database::Artist>("artist");
_session.mapClass<Database::Genre>("genre");
_session.mapClass<Database::Track>("track");
_session.mapClass<Database::Classification>("classification");
_session.mapClass<Database::ClassificationData>("classification_data");
_session.mapClass<Database::Playlist>("playlist");
_session.mapClass<Database::PlaylistEntry>("playlist_entry");
_session.mapClass<Database::Release>("release");
@@ -17,19 +17,19 @@
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdexcept>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <boost/asio/placeholders.hpp>
#include "logger/Logger.hpp"
#include "utils/Utils.hpp"
#include "database/Types.hpp"
#include "Checksum.hpp"
#include "DatabaseUpdater.hpp"
#include "cover/CoverArtGrabber.hpp"
#include "utils/Utils.hpp"
#include "utils/Checksum.hpp"
#include "Types.hpp"
#include "DatabaseUpdater.hpp"
namespace {
@@ -115,23 +115,40 @@ isPathInParentPath(const boost::filesystem::path& path, const boost::filesystem:
} // namespace
namespace DatabaseUpdater {
namespace Database {
using namespace Database;
Updater& Updater::instance(void)
{
static Updater updater;
return updater;
}
Updater::Updater(Wt::Dbo::SqlConnectionPool &connectionPool, MetaData::Parser& parser)
Updater::Updater()
: _running(false),
_scheduleTimer(_ioService),
_db(connectionPool),
_metadataParser(parser)
_scheduleTimer(_ioService)
{
_ioService.setThreadCount(1);
}
void
Updater::setConnectionPool(Wt::Dbo::SqlConnectionPool& connectionPool)
{
_db = new Database::Handler(connectionPool);
}
void
Updater::restart(void)
{
stop();
start();
}
void
Updater::start(void)
{
if (_db == nullptr)
throw std::logic_error("uninitialized db!");
_running = true;
// post some jobs in the io_service
@@ -154,9 +171,9 @@ Updater::stop(void)
void
Updater::processNextJob(void)
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(_db.getSession());
MediaDirectorySettings::pointer settings = MediaDirectorySettings::get(_db->getSession());
if (settings->getManualScanRequested()) {
LMS_LOG(DBUPDATER, INFO) << "Manual scan requested!";
@@ -229,9 +246,9 @@ Updater::process(boost::system::error_code err)
std::vector<RootDirectory> rootDirectories;
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
for (MediaDirectory::pointer directory : MediaDirectory::getAll(_db.getSession()))
for (MediaDirectory::pointer directory : MediaDirectory::getAll(_db->getSession()))
rootDirectories.push_back( RootDirectory( directory->getType(), directory->getPath() ));
}
@@ -253,9 +270,9 @@ Updater::process(boost::system::error_code err)
// Update database stats
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db.getSession());
Database::MediaDirectorySettings::pointer settings = Database::MediaDirectorySettings::get(_db->getSession());
if (stats.nbChanges() > 0)
settings.modify()->setLastUpdate(now);
@@ -279,10 +296,10 @@ Updater::process(boost::system::error_code err)
void
Updater::updateFileExtensions()
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
_audioFileExtensions = MediaDirectorySettings::get(_db.getSession())->getAudioFileExtensions();
_videoFileExtensions = MediaDirectorySettings::get(_db.getSession())->getVideoFileExtensions();
_audioFileExtensions = MediaDirectorySettings::get(_db->getSession())->getAudioFileExtensions();
_videoFileExtensions = MediaDirectorySettings::get(_db->getSession())->getVideoFileExtensions();
}
Artist::pointer
@@ -293,9 +310,9 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
// First try to get by MBID
if (!mbid.empty())
{
artist = Artist::getByMBID( _db.getSession(), mbid );
artist = Artist::getByMBID( _db->getSession(), mbid );
if (!artist)
artist = Artist::create( _db.getSession(), name, mbid);
artist = Artist::create( _db->getSession(), name, mbid);
return artist;
}
@@ -303,7 +320,7 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
// Fall back on artist name (collisions may occur)
if (!name.empty())
{
for (Artist::pointer sameNamedArtist : Artist::getByName( _db.getSession(), name ))
for (Artist::pointer sameNamedArtist : Artist::getByName( _db->getSession(), name ))
{
if (sameNamedArtist->getMBID().empty())
{
@@ -314,12 +331,12 @@ Updater::getArtist( const boost::filesystem::path& file, const std::string& name
// No Artist found with the same name and without MBID -> creating
if (!artist)
artist = Artist::create( _db.getSession(), name);
artist = Artist::create( _db->getSession(), name);
return artist;
}
return Artist::getNone( _db.getSession() );
return Artist::getNone( _db->getSession() );
}
Release::pointer
@@ -330,9 +347,9 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
// First try to get by MBID
if (!mbid.empty())
{
release = Release::getByMBID( _db.getSession(), mbid );
release = Release::getByMBID( _db->getSession(), mbid );
if (!release)
release = Release::create( _db.getSession(), name, mbid);
release = Release::create( _db->getSession(), name, mbid);
return release;
}
@@ -340,7 +357,7 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
// Fall back on release name (collisions may occur)
if (!name.empty())
{
for (Release::pointer sameNamedRelease : Release::getByName( _db.getSession(), name ))
for (Release::pointer sameNamedRelease : Release::getByName( _db->getSession(), name ))
{
if (sameNamedRelease->getMBID().empty())
{
@@ -351,12 +368,12 @@ Updater::getRelease( const boost::filesystem::path& file, const std::string& nam
// No release found with the same name and without MBID -> creating
if (!release)
release = Release::create( _db.getSession(), name);
release = Release::create( _db->getSession(), name);
return release;
}
return Release::getNone( _db.getSession() );
return Release::getNone( _db->getSession() );
}
std::vector<Genre::pointer>
@@ -366,15 +383,15 @@ Updater::getGenres( const std::list<std::string>& names)
for (const std::string& name : names)
{
Genre::pointer genre ( Genre::getByName(_db.getSession(), name) );
Genre::pointer genre ( Genre::getByName(_db->getSession(), name) );
if (!genre)
genre = Genre::create(_db.getSession(), name);
genre = Genre::create(_db->getSession(), name);
genres.push_back( genre );
}
if (genres.empty())
genres.push_back( Genre::getNone( _db.getSession() ));
genres.push_back( Genre::getNone( _db->getSession() ));
return genres;
}
@@ -386,9 +403,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
// Skip file if last write is the same
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
Wt::Dbo::ptr<Track> track = Track::getByPath(_db.getSession(), file);
Wt::Dbo::ptr<Track> track = Track::getByPath(_db->getSession(), file);
if (track && track->getLastWriteTime() == lastWriteTime)
{
@@ -412,9 +429,9 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
std::vector<unsigned char> checksum ;
computeCrc(file, checksum);
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
Wt::Dbo::ptr<Track> track = Track::getByPath(_db.getSession(), file);
Wt::Dbo::ptr<Track> track = Track::getByPath(_db->getSession(), file);
// We estimate this is a audio file if:
// - we found a least one audio stream
@@ -510,7 +527,7 @@ Updater::processAudioFile( const boost::filesystem::path& file, Stats& stats)
if (!track)
{
// Create a new song
track = Track::create(_db.getSession(), file);
track = Track::create(_db->getSession(), file);
LMS_LOG(DBUPDATER, INFO) << "Adding '" << file << "'";
stats.nbAdded++;
}
@@ -675,8 +692,8 @@ Updater::checkAudioFiles( Stats& stats )
{
LMS_LOG(DBUPDATER, INFO) << "Checking audio files...";
std::vector<boost::filesystem::path> trackPaths = Track::getAllPaths(_db.getSession());;
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db.getSession(), Database::MediaDirectory::Audio);
std::vector<boost::filesystem::path> trackPaths = Track::getAllPaths(_db->getSession());;
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db->getSession(), Database::MediaDirectory::Audio);
LMS_LOG(DBUPDATER, DEBUG) << "Checking tracks...";
for (auto& trackPath : trackPaths)
@@ -686,9 +703,9 @@ Updater::checkAudioFiles( Stats& stats )
if (!checkFile(trackPath, rootDirs, _audioFileExtensions))
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
Track::pointer track = Track::getByPath(_db.getSession(), trackPath);
Track::pointer track = Track::getByPath(_db->getSession(), trackPath);
if (track)
{
track.remove();
@@ -699,10 +716,10 @@ Updater::checkAudioFiles( Stats& stats )
LMS_LOG(DBUPDATER, DEBUG) << "Checking Genres...";
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
// Now process orphan Genre (no track)
auto genres = Genre::getAll(_db.getSession());
auto genres = Genre::getAll(_db->getSession());
for (auto genre : genres)
{
if (genre->getTracks().size() == 0)
@@ -715,9 +732,9 @@ Updater::checkAudioFiles( Stats& stats )
LMS_LOG(DBUPDATER, DEBUG) << "Checking artists...";
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
auto artists = Artist::getAllOrphans(_db.getSession());
auto artists = Artist::getAllOrphans(_db->getSession());
for (auto artist : artists)
{
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan artist '" << artist->getName() << "'";
@@ -727,9 +744,9 @@ Updater::checkAudioFiles( Stats& stats )
LMS_LOG(DBUPDATER, DEBUG) << "Checking releases...";
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
auto releases = Release::getAllOrphans(_db.getSession());
auto releases = Release::getAllOrphans(_db->getSession());
for (auto release : releases)
{
LMS_LOG(DBUPDATER, DEBUG) << "Removing orphan release '" << release->getName() << "'";
@@ -745,15 +762,15 @@ Updater::checkDuplicatedAudioFiles(Stats& stats)
{
LMS_LOG(DBUPDATER, INFO) << "Checking duplicated audio files";
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
std::vector<Track::pointer> tracks = Database::Track::getMBIDDuplicates(_db.getSession());
std::vector<Track::pointer> tracks = Database::Track::getMBIDDuplicates(_db->getSession());
for (Track::pointer track : tracks)
{
LMS_LOG(DBUPDATER, INFO) << "Found duplicated MBID [" << track->getMBID() << "], file: " << track->getPath() << " - " << track->getArtist()->getName() << " - " << track->getName();
}
tracks = Database::Track::getChecksumDuplicates(_db.getSession());
tracks = Database::Track::getChecksumDuplicates(_db->getSession());
for (Track::pointer track : tracks)
{
LMS_LOG(DBUPDATER, INFO) << "Found duplicated checksum [" << bufferToString(track->getChecksum()) << "], file: " << track->getPath() << " - " << track->getArtist()->getName() << " - " << track->getName();
@@ -766,8 +783,8 @@ Updater::checkDuplicatedAudioFiles(Stats& stats)
void
Updater::checkVideoFiles( Stats& stats )
{
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db.getSession(), Database::MediaDirectory::Video);
std::vector<boost::filesystem::path> videoPaths = Video::getAllPaths(_db.getSession());
std::vector<boost::filesystem::path> rootDirs = getRootDirectoriesByType(_db->getSession(), Database::MediaDirectory::Video);
std::vector<boost::filesystem::path> videoPaths = Video::getAllPaths(_db->getSession());
LMS_LOG(DBUPDATER, DEBUG) << "Checking videos...";
for (auto& videoPath : videoPaths)
@@ -777,9 +794,9 @@ Updater::checkVideoFiles( Stats& stats )
if (!checkFile(videoPath, rootDirs, _videoFileExtensions))
{
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
Video::pointer video = Video::getByPath(_db.getSession(), videoPath);
Video::pointer video = Video::getByPath(_db->getSession(), videoPath);
if (video)
{
video.remove();
@@ -797,10 +814,10 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
// Check last update time
boost::posix_time::ptime lastWriteTime (boost::posix_time::from_time_t( boost::filesystem::last_write_time( file ) ) );
Wt::Dbo::Transaction transaction(_db.getSession());
Wt::Dbo::Transaction transaction(_db->getSession());
// Skip file if last write is the same
Wt::Dbo::ptr<Video> video = Video::getByPath(_db.getSession(), file);
Wt::Dbo::ptr<Video> video = Video::getByPath(_db->getSession(), file);
if (video && video->getLastWriteTime() == lastWriteTime)
return;
@@ -841,7 +858,7 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
// Today we are very aggressive, but we could also guess names from path, etc.
if (!video)
{
video = Video::create(_db.getSession(), file);
video = Video::create(_db->getSession(), file);
LMS_LOG(DBUPDATER, DEBUG) << "Adding '" << file << "'";
stats.nbAdded++;
}
@@ -860,4 +877,4 @@ Updater::processVideoFile( const boost::filesystem::path& file, Stats& stats)
transaction.commit();
}
} // namespace DatabaseUpdater
} // namespace Database
@@ -20,28 +20,22 @@
#ifndef DB_UPDATER_HPP
#define DB_UPDATER_HPP
#include <boost/asio/deadline_timer.hpp>
#include <Wt/WIOService>
#include <Wt/WSignal>
#include "metadata/MetaData.hpp"
#include <mutex>
#include <boost/asio/deadline_timer.hpp>
#include "metadata/AvFormat.hpp"
#include "database/DatabaseHandler.hpp"
namespace DatabaseUpdater {
namespace Database {
class Updater
{
public:
Updater(Wt::Dbo::SqlConnectionPool& connectionPool, MetaData::Parser& parser);
void setAudioExtensions(const std::vector<std::string>& extensions);
void setVideoExtensions(const std::vector<std::string>& extensions);
void start();
void stop();
private:
struct Stats
{
std::size_t nbSkipped = 0; // no change since last scan
@@ -55,6 +49,25 @@ class Updater
std::size_t nbChanges() const { return nbAdded + nbRemoved + nbModified;}
};
static Updater& instance();
void setConnectionPool(Wt::Dbo::SqlConnectionPool& connectionPool);
void setAudioExtensions(const std::vector<std::string>& extensions);
void setVideoExtensions(const std::vector<std::string>& extensions);
void start();
void stop();
void restart();
Wt::Signal<Stats>& changed() { return _sigChanged; }
std::mutex& getMutex(void) { return _mutex; }
private:
Updater();
struct RootDirectory
{
Database::MediaDirectory::Type type;
@@ -96,19 +109,21 @@ class Updater
bool _running;
Wt::WIOService _ioService;
Wt::Signal<Stats> _sigChanged;
std::mutex _mutex;
boost::asio::deadline_timer _scheduleTimer;
Database::Handler _db;
Database::Handler* _db = nullptr;
std::vector<boost::filesystem::path> _audioFileExtensions;
std::vector<boost::filesystem::path> _videoFileExtensions;
MetaData::Parser& _metadataParser;
MetaData::AvFormat _metadataParser;
}; // class Updater
} // DatabaseUpdater
} // Database
#endif
+10 -1
View File
@@ -37,6 +37,8 @@ class Artist;
class Release;
class Track;
class PlaylistEntry;
class Classification;
class ClassificationData;
class Genre
{
@@ -156,6 +158,8 @@ class Track
void setArtist(Wt::Dbo::ptr<Artist> artist) { _artist = artist; }
void setRelease(Wt::Dbo::ptr<Release> release) { _release = release; }
void setGenres(std::vector<Genre::pointer> genres);
void addClassifification(Wt::Dbo::ptr<Classification> classification);
void addClassifificationData(Wt::Dbo::ptr<ClassificationData> classificationData);
int getTrackNumber(void) const { return _trackNumber; }
int getTotalTrackNumber(void) const { return _totalTrackNumber; }
@@ -175,6 +179,8 @@ class Track
Wt::Dbo::ptr<Release> getRelease(void) const { return _release; }
std::vector< Genre::pointer > getGenres(void) const;
bool hasGenre(Genre::pointer genre) const { return _genres.count(genre); }
std::vector< Wt::Dbo::ptr<Classification> > getClassifications(void) const;
std::vector< Wt::Dbo::ptr<ClassificationData> > getClassificationData(void) const;
template<class Action>
void persist(Action& a)
@@ -198,6 +204,8 @@ class Track
Wt::Dbo::belongsTo(a, _artist, "artist", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _genres, Wt::Dbo::ManyToMany, "track_genre", "", Wt::Dbo::OnDeleteCascade);
Wt::Dbo::hasMany(a, _playlistEntries, Wt::Dbo::ManyToOne, "track");
Wt::Dbo::hasMany(a, _classifications, Wt::Dbo::ManyToOne, "track");
Wt::Dbo::hasMany(a, _classificationData, Wt::Dbo::ManyToOne, "track");
}
private:
@@ -228,7 +236,8 @@ class Track
Wt::Dbo::ptr<Release> _release;
Wt::Dbo::collection< Genre::pointer > _genres; // Genres that are related to this track
Wt::Dbo::collection< Wt::Dbo::ptr<PlaylistEntry> > _playlistEntries;
Wt::Dbo::collection< Wt::Dbo::ptr<Classification> > _classifications;
Wt::Dbo::collection< Wt::Dbo::ptr<ClassificationData> > _classificationData;
};
+1
View File
@@ -22,6 +22,7 @@
#include "Artist.hpp"
#include "Track.hpp"
#include "Playlist.hpp"
#include "Classification.hpp"
#include "Release.hpp"
#include "Video.hpp"
#include "MediaDirectory.hpp"
+15 -19
View File
@@ -19,18 +19,17 @@
#include <boost/filesystem.hpp>
#include <Wt/WServer>
#include "config/config.h"
#include "av/AvInfo.hpp"
#include "av/AvTranscoder.hpp"
#include "logger/Logger.hpp"
#include "image/Image.hpp"
#include "database/DatabaseUpdater.hpp"
#include "ui/LmsApplication.hpp"
#include "service/ServiceManager.hpp"
#include "service/DatabaseUpdateService.hpp"
#include <Wt/WServer>
int main(int argc, char* argv[])
{
@@ -49,8 +48,6 @@ int main(int argc, char* argv[])
Wt::WServer::instance()->logger().configure("*"); // log everything
Service::ServiceManager& serviceManager = Service::ServiceManager::instance();
// lib init
Image::init(argv[0]);
Av::AvInit();
@@ -60,30 +57,29 @@ int main(int argc, char* argv[])
// Initializing a connection pool to the database that will be shared along services
std::unique_ptr<Wt::Dbo::SqlConnectionPool> connectionPool( Database::Handler::createConnectionPool("/var/lms/lms.db")); // TODO use $datadir from autotools
serviceManager.add( std::make_shared<Service::DatabaseUpdateService>(*connectionPool));
Database::Updater::instance().setConnectionPool(*connectionPool);
// bind entry point
server.addEntryPoint(Wt::Application, boost::bind(UserInterface::LmsApplication::create, _1, boost::ref(*connectionPool)));
// Starting the main server
// Start
LMS_LOG(MAIN, INFO) << "Starting database updater...";
Database::Updater::instance().start();
LMS_LOG(MAIN, INFO) << "Starting server...";
server.start();
// Start underlying services
LMS_LOG(MAIN, INFO) << "Starting services...";
serviceManager.start();
// Wait
LMS_LOG(MAIN, INFO) << "Now running...";
// Waiting for shutdown command
Wt::WServer::waitForShutdown(argv[0]);
LMS_LOG(MAIN, INFO) << "Stopping services...";
serviceManager.stop();
serviceManager.clear();
// Stop
LMS_LOG(MAIN, INFO) << "Stopping server...";
server.stop();
Database::Updater::instance().stop();
LMS_LOG(MAIN, INFO) << "Stopping database updater...";
Database::Updater::instance().stop();
res = EXIT_SUCCESS;
}
-52
View File
@@ -1,52 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/thread.hpp>
#include "DatabaseUpdateService.hpp"
namespace Service {
DatabaseUpdateService::DatabaseUpdateService(Wt::Dbo::SqlConnectionPool &connectionPool)
: _metadataParser(),
_databaseUpdater( connectionPool, _metadataParser)
{
}
void
DatabaseUpdateService::start(void)
{
_databaseUpdater.start();
}
void
DatabaseUpdateService::stop(void)
{
_databaseUpdater.stop();
}
void
DatabaseUpdateService::restart(void)
{
stop();
start();
}
} // namespace Service
-55
View File
@@ -1,55 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DB_UPDATE_SERVICE_HPP
#define DB_UPDATE_SERVICE_HPP
#include <boost/thread.hpp>
#include <boost/asio/io_service.hpp>
#include "metadata/AvFormat.hpp"
#include "database-updater/DatabaseUpdater.hpp"
#include "Service.hpp"
namespace Service {
class DatabaseUpdateService : public Service
{
public:
typedef std::shared_ptr<DatabaseUpdateService> pointer;
DatabaseUpdateService(Wt::Dbo::SqlConnectionPool &connectionPool);
// Service interface
void start(void);
void stop(void);
void restart(void);
private:
MetaData::AvFormat _metadataParser;
DatabaseUpdater::Updater _databaseUpdater; // Todo use handler
};
} // namespace Service
#endif
-51
View File
@@ -1,51 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERVICE_HPP
#define SERVICE_HPP
#include <boost/thread.hpp>
#include <memory>
#include <set>
namespace Service {
// Interface class wrapper for running services
class Service
{
public:
typedef std::shared_ptr<Service> pointer;
Service(const Service&) = delete;
Service& operator=(const Service&) = delete;
Service() {}
virtual ~Service() {}
virtual void start(void) = 0;
virtual void stop(void) = 0;
virtual void restart(void) = 0;
};
} // namespace Service
#endif
-84
View File
@@ -1,84 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ServiceManager.hpp"
namespace Service {
ServiceManager&
ServiceManager::instance()
{
static ServiceManager instance;
return instance;
}
ServiceManager::ServiceManager()
{
}
ServiceManager::~ServiceManager()
{
stop();
}
void
ServiceManager::add(Service::pointer service)
{
_services.insert(service);
service->start();
}
void
ServiceManager::del(Service::pointer service)
{
service->stop();
_services.erase(service);
}
void
ServiceManager::clear(void)
{
stop();
_services.clear();
}
void
ServiceManager::start(void)
{
for (Service::pointer service : _services)
service->start();
}
void
ServiceManager::stop(void)
{
for (Service::pointer service : _services)
service->stop();
}
void
ServiceManager::restart(void)
{
for (Service::pointer service : _services)
service->restart();
}
} // namespace Service
-77
View File
@@ -1,77 +0,0 @@
/*
* Copyright (C) 2013 Emeric Poupon
*
* This file is part of LMS.
*
* LMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LMS. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SERVICE_CONTROLER_HPP
#define SERVICE_CONTROLER_HPP
#include <set>
#include "Service.hpp"
namespace Service {
// Start/Stop/Reload Services
class ServiceManager
{
public:
static ServiceManager& instance();
~ServiceManager();
void add(Service::pointer service);
void del(Service::pointer service);
void clear();
void start();
void stop();
void restart();
template <class T> typename T::pointer get();
boost::mutex& mutex() { return _mutex;}
private:
ServiceManager();
ServiceManager(ServiceManager const&); // Don't Implement
void operator=(ServiceManager const&); // Don't implement
boost::mutex _mutex;
std::set<Service::pointer> _services;
};
template <class T> typename T::pointer
ServiceManager::get()
{
std::set<Service::pointer>::iterator it;
for (Service::pointer service : _services)
{
if (typeid(*(service)) == typeid(T)) {
return std::dynamic_pointer_cast<T>(service);
}
}
return std::shared_ptr<T>();
}
} // namespace Service
#endif
+21 -28
View File
@@ -30,8 +30,7 @@
#include "SettingsUsers.hpp"
#include "logger/Logger.hpp"
#include "service/ServiceManager.hpp"
#include "service/DatabaseUpdateService.hpp"
#include "database/DatabaseUpdater.hpp"
#include "LmsApplication.hpp"
@@ -74,11 +73,29 @@ Settings::Settings(Wt::WContainerWidget* parent)
if (userIsAdmin)
{
MediaDirectories* mediaDirectories = new MediaDirectories();
mediaDirectories->changed().connect(this, &Settings::handleDatabaseDirectoriesChanged);
mediaDirectories->changed().connect(std::bind([=]
{
LMS_LOG(UI, INFO) << "Media directories have changed: requesting imediate scan";
// On directory add or delete, request an immediate scan
//
{
Wt::Dbo::Transaction transaction(DboSession());
Database::MediaDirectorySettings::get(DboSession()).modify()->setManualScanRequested(true);
}
{
std::lock_guard<std::mutex> lock(Database::Updater::instance().getMutex());
Database::Updater::instance().restart();
}
}));
menu->addItem("Media Folders", mediaDirectories)->setPathComponent("mediadirectories");
DatabaseFormView* databaseFormView = new DatabaseFormView();
databaseFormView->changed().connect(this, &Settings::restartDatabaseUpdateService);
databaseFormView->changed().connect(std::bind([=]
{
std::lock_guard<std::mutex> lock(Database::Updater::instance().getMutex());
Database::Updater::instance().restart();
}));
menu->addItem("Database", databaseFormView)->setPathComponent("database");
menu->addItem("Users", new Users())->setPathComponent("users");
@@ -90,29 +107,5 @@ Settings::Settings(Wt::WContainerWidget* parent)
}
void
Settings::handleDatabaseDirectoriesChanged()
{
LMS_LOG(UI, INFO) << "Media directories have changed: requesting imediate scan";
// On directory add or delete, request an immediate scan
{
Wt::Dbo::Transaction transaction(DboSession());
Database::MediaDirectorySettings::get(DboSession()).modify()->setManualScanRequested(true);
}
restartDatabaseUpdateService();
}
void
Settings::restartDatabaseUpdateService()
{
// Restarting the update service
boost::lock_guard<boost::mutex> serviceLock (Service::ServiceManager::instance().mutex());
Service::DatabaseUpdateService::pointer service = Service::ServiceManager::instance().get<Service::DatabaseUpdateService>();
if (service)
service->restart();
}
} // namespace Settings
} // namespace UserInterface
-5
View File
@@ -28,11 +28,6 @@ class Settings : public Wt::WContainerWidget
Settings(Wt::WContainerWidget* parent = 0);
private:
void handleDatabaseDirectoriesChanged();
void restartDatabaseUpdateService(void);
};
} // namespace Settings
@@ -20,6 +20,6 @@
#include <vector>
#include <boost/filesystem.hpp>
// TODO move to utils
void computeCrc(const boost::filesystem::path& p, std::vector<unsigned char>& checksum);