diff --git a/src/Makefile.am b/src/Makefile.am index 1e8f7830..cc1a0817 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,7 +20,6 @@ lms_SOURCES = \ $(srcdir)/database/User.cpp \ $(srcdir)/image/Image.cpp \ $(srcdir)/main/main.cpp \ - $(srcdir)/main/Services.cpp \ $(srcdir)/metadata/AvFormat.cpp \ $(srcdir)/metadata/TagLibParser.cpp \ $(srcdir)/scanner/MediaScanner.cpp \ diff --git a/src/api/subsonic/SubsonicResource.cpp b/src/api/subsonic/SubsonicResource.cpp index 4d0aeba6..71f70c53 100644 --- a/src/api/subsonic/SubsonicResource.cpp +++ b/src/api/subsonic/SubsonicResource.cpp @@ -32,7 +32,7 @@ #include "database/Release.hpp" #include "database/Track.hpp" #include "database/TrackList.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "similarity/SimilaritySearcher.hpp" #include "utils/Logger.hpp" #include "utils/Utils.hpp" @@ -880,7 +880,7 @@ Response handleGetArtistInfoRequestCommon(RequestContext& context, bool id3) if (!artist->getMBID().empty()) artistInfoNode.createChild("musicBrainzId").setValue(artist->getMBID()); - auto similarArtistsId {getServices().similaritySearcher->getSimilarArtists(context.db.getSession(), artist.id(), count)}; + auto similarArtistsId {getService()->getSimilarArtists(context.db.getSession(), artist.id(), count)}; for ( const auto& similarArtistId : similarArtistsId ) { Database::Artist::pointer similarArtist {Database::Artist::getById(context.db.getSession(), similarArtistId)}; @@ -1059,7 +1059,7 @@ handleGetSimilarSongsRequestCommon(RequestContext& context, bool id3) // "Returns a random collection of songs from the given artist and similar artists" auto tracks {artist->getRandomTracks(count / 2)}; - auto similarArtistsId {getServices().similaritySearcher->getSimilarArtists(context.db.getSession(), artist.id(), 5)}; + auto similarArtistsId {getService()->getSimilarArtists(context.db.getSession(), artist.id(), 5)}; for ( const auto& similarArtistId : similarArtistsId ) { Database::Artist::pointer similarArtist {Database::Artist::getById(context.db.getSession(), similarArtistId)}; @@ -1433,10 +1433,10 @@ handleGetCoverArt(RequestContext& context, Wt::Http::ResponseContinuation* conti switch (id.type) { case Id::Type::Track: - cover = getServices().coverArtGrabber->getFromTrack(context.db.getSession(), id.value, Image::Format::JPEG, size); + cover = getService()->getFromTrack(context.db.getSession(), id.value, Image::Format::JPEG, size); break; case Id::Type::Release: - cover = getServices().coverArtGrabber->getFromRelease(context.db.getSession(), id.value, Image::Format::JPEG, size); + cover = getService()->getFromRelease(context.db.getSession(), id.value, Image::Format::JPEG, size); break; default: throw Error {Error::CustomType::BadId}; diff --git a/src/main/Services.hpp b/src/main/Service.hpp similarity index 55% rename from src/main/Services.hpp rename to src/main/Service.hpp index a70fb35b..e72ef990 100644 --- a/src/main/Services.hpp +++ b/src/main/Service.hpp @@ -19,26 +19,36 @@ #include -namespace CoverArt +template +class ServiceProvider { - class Grabber; -} + public: -namespace Scanner { - class MediaScanner; -} + template + static + T& + create(Args&&... args) + { + assign(std::make_unique(std::forward(args)...)); + return *get(); + } + static void assign(std::unique_ptr service) { _service = std::move(service); } + static void clear() { _service.reset(); } -namespace Similarity { - class Searcher; -} + static T* get() { return _service.get(); } - -struct Services -{ - std::unique_ptr coverArtGrabber; - std::unique_ptr mediaScanner; - std::unique_ptr similaritySearcher; + private: + static std::unique_ptr _service; }; -Services& getServices(); +template +std::unique_ptr ServiceProvider::_service = {}; + +template +T* +getService() +{ + return ServiceProvider::get(); +} + diff --git a/src/main/Services.cpp b/src/main/Services.cpp deleted file mode 100644 index c74b3109..00000000 --- a/src/main/Services.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2019 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 . - */ - -#include "Services.hpp" - -#include "cover/CoverArtGrabber.hpp" -#include "scanner/MediaScanner.hpp" -#include "similarity/SimilaritySearcher.hpp" - -Services& getServices() -{ - static Services services; - return services; -} - diff --git a/src/main/main.cpp b/src/main/main.cpp index 648f4025..0afbd125 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -34,7 +34,7 @@ #include "ui/LmsApplication.hpp" #include "utils/Config.hpp" #include "utils/Logger.hpp" -#include "Services.hpp" +#include "Service.hpp" std::vector generateWtConfig(std::string execPath) { @@ -127,15 +127,16 @@ int main(int argc, char* argv[]) UserInterface::LmsApplicationGroupContainer appGroups; // Service initialization order is important - getServices().mediaScanner = std::make_unique(*connectionPool); + Scanner::MediaScanner& mediaScanner {ServiceProvider::create(*connectionPool)}; Similarity::FeaturesScannerAddon similarityFeaturesScannerAddon(*connectionPool); - getServices().mediaScanner->setAddon(similarityFeaturesScannerAddon); - getServices().coverArtGrabber = std::make_unique(); - getServices().coverArtGrabber->setDefaultCover(server.appRoot() + "/images/unknown-cover.jpg"); + mediaScanner.setAddon(similarityFeaturesScannerAddon); - getServices().similaritySearcher = std::make_unique(similarityFeaturesScannerAddon); + CoverArt::Grabber& coverArtGrabber {ServiceProvider::create()}; + coverArtGrabber.setDefaultCover(server.appRoot() + "/images/unknown-cover.jpg"); + + ServiceProvider::create(similarityFeaturesScannerAddon); API::Subsonic::SubsonicResource subsonicResource {*connectionPool}; @@ -153,7 +154,7 @@ int main(int argc, char* argv[]) // Start LMS_LOG(MAIN, INFO) << "Starting media scanner..."; - getServices().mediaScanner->start(); + mediaScanner.start(); LMS_LOG(MAIN, INFO) << "Starting server..."; server.start(); @@ -167,7 +168,7 @@ int main(int argc, char* argv[]) server.stop(); LMS_LOG(MAIN, INFO) << "Stopping media scanner..."; - getServices().mediaScanner->stop(); + mediaScanner.stop(); LMS_LOG(MAIN, INFO) << "Clean stop!"; res = EXIT_SUCCESS; diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index 4fcef0a3..0937abaa 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -36,7 +36,7 @@ #include "database/Cluster.hpp" #include "database/Release.hpp" #include "explore/Explore.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "utils/Logger.hpp" #include "utils/Utils.hpp" @@ -459,7 +459,7 @@ LmsApplication::createHome() // Events from MediaScanner std::string sessionId = LmsApp->sessionId(); - getServices().mediaScanner->scanComplete().connect([=] (Scanner::MediaScanner::Stats stats) + getService()->scanComplete().connect([=] (Scanner::MediaScanner::Stats stats) { // Runs from media scanner context Wt::WServer::instance()->post(sessionId, [=] diff --git a/src/ui/PlayQueueView.cpp b/src/ui/PlayQueueView.cpp index ad4a925e..8734b830 100644 --- a/src/ui/PlayQueueView.cpp +++ b/src/ui/PlayQueueView.cpp @@ -22,7 +22,7 @@ #include #include "database/TrackList.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "similarity/SimilaritySearcher.hpp" #include "utils/Logger.hpp" #include "LmsApplication.hpp" @@ -399,7 +399,7 @@ PlayQueue::addRadioTrack() if (trackIds.empty()) return; - auto res = getServices().similaritySearcher->getSimilarTracks(LmsApp->getDboSession(), std::set(trackIds.begin(), trackIds.end()), 1); + auto res = getService()->getSimilarTracks(LmsApp->getDboSession(), std::set(trackIds.begin(), trackIds.end()), 1); for (auto trackId : res) { auto trackToAdd = Database::Track::getById(LmsApp->getDboSession(), trackId); diff --git a/src/ui/admin/DatabaseSettingsView.cpp b/src/ui/admin/DatabaseSettingsView.cpp index 65ec7a6c..59ae5fd1 100644 --- a/src/ui/admin/DatabaseSettingsView.cpp +++ b/src/ui/admin/DatabaseSettingsView.cpp @@ -28,7 +28,7 @@ #include #include "database/Cluster.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "utils/Logger.hpp" #include "utils/Utils.hpp" @@ -288,7 +288,7 @@ DatabaseSettingsView::refreshView() { model->saveData(); - getServices().mediaScanner->reschedule(); + getService()->reschedule(); LmsApp->notifyMsg(MsgType::Success, Wt::WString::tr("Lms.Admin.Database.settings-saved")); } @@ -305,7 +305,7 @@ DatabaseSettingsView::refreshView() immScanBtn->clicked().connect([=] () { - getServices().mediaScanner->scheduleImmediateScan(); + getService()->scheduleImmediateScan(); LmsApp->notifyMsg(MsgType::Info, Wt::WString::tr("Lms.Admin.Database.scan-launched")); }); diff --git a/src/ui/explore/ArtistInfoView.cpp b/src/ui/explore/ArtistInfoView.cpp index dc979220..d253eacd 100644 --- a/src/ui/explore/ArtistInfoView.cpp +++ b/src/ui/explore/ArtistInfoView.cpp @@ -20,7 +20,7 @@ #include "ArtistInfoView.hpp" #include "database/Artist.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "similarity/SimilaritySearcher.hpp" #include "utils/Utils.hpp" @@ -63,7 +63,7 @@ ArtistInfo::refresh() if (!artistId) return; - auto artistsIds = getServices().similaritySearcher->getSimilarArtists(LmsApp->getDboSession(), *artistId, 5); + auto artistsIds = getService()->getSimilarArtists(LmsApp->getDboSession(), *artistId, 5); Wt::Dbo::Transaction transaction(LmsApp->getDboSession()); diff --git a/src/ui/explore/ReleaseInfoView.cpp b/src/ui/explore/ReleaseInfoView.cpp index ffd89b14..11861075 100644 --- a/src/ui/explore/ReleaseInfoView.cpp +++ b/src/ui/explore/ReleaseInfoView.cpp @@ -22,7 +22,7 @@ #include #include "database/Release.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "similarity/SimilaritySearcher.hpp" #include "utils/Utils.hpp" @@ -68,7 +68,7 @@ ReleaseInfo::refresh() if (!releaseId) return; - std::vector releasesIds {getServices().similaritySearcher->getSimilarReleases(LmsApp->getDboSession(), *releaseId, 5)}; + std::vector releasesIds {getService()->getSimilarReleases(LmsApp->getDboSession(), *releaseId, 5)}; Wt::Dbo::Transaction transaction {LmsApp->getDboSession()}; diff --git a/src/ui/resource/ImageResource.cpp b/src/ui/resource/ImageResource.cpp index 46bf0e1e..3752179b 100644 --- a/src/ui/resource/ImageResource.cpp +++ b/src/ui/resource/ImageResource.cpp @@ -24,7 +24,7 @@ #include "cover/CoverArtGrabber.hpp" #include "database/Track.hpp" -#include "main/Services.hpp" +#include "main/Service.hpp" #include "utils/Exception.hpp" #include "utils/Logger.hpp" #include "utils/Utils.hpp" @@ -80,7 +80,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons // transactions are not thread safe { Wt::WApplication::UpdateLock lock(LmsApp); - cover = getServices().coverArtGrabber->getFromTrack(LmsApp->getDboSession(), *trackId, Image::Format::JPEG, *size); + cover = getService()->getFromTrack(LmsApp->getDboSession(), *trackId, Image::Format::JPEG, *size); } } else if (releaseIdStr) @@ -92,7 +92,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons // transactions are not thread safe { Wt::WApplication::UpdateLock lock(LmsApp); - cover = getServices().coverArtGrabber->getFromRelease(LmsApp->getDboSession(), *releaseId, Image::Format::JPEG, *size); + cover = getService()->getFromRelease(LmsApp->getDboSession(), *releaseId, Image::Format::JPEG, *size); } } else