From b69e0c0c3d7cc43479013f700981d87033f0bf54 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 19 Nov 2019 18:14:23 +0100 Subject: [PATCH] Split the LMS_LOG macro to work either with a ostream logger or a wt logger --- src/Makefile.am | 6 ++- src/api/subsonic/SubsonicResource.cpp | 22 ++++----- src/av/AvTranscoder.cpp | 2 +- src/main/main.cpp | 47 ++++++++++--------- .../features/AcousticBrainzUtils.cpp | 2 +- .../features/SimilarityFeaturesCache.cpp | 4 +- src/ui/Auth.cpp | 6 +-- src/ui/LmsApplication.cpp | 8 ++-- src/ui/PlayQueueView.cpp | 2 +- src/ui/SettingsView.cpp | 6 +-- src/ui/admin/DatabaseSettingsView.cpp | 4 +- src/ui/admin/DatabaseStatus.cpp | 2 +- src/ui/admin/InitWizardView.cpp | 4 +- src/ui/admin/UserView.cpp | 6 +-- src/ui/explore/ArtistInfoView.cpp | 2 +- src/ui/explore/ReleaseInfoView.cpp | 2 +- src/ui/resource/ImageResource.cpp | 4 +- src/utils/Logger.cpp | 18 +++++++ src/utils/Logger.hpp | 32 ++++++++++--- src/utils/Service.hpp | 39 ++++++++------- src/utils/StreamLogger.cpp | 32 +++++++++++++ src/utils/StreamLogger.hpp | 34 ++++++++++++++ src/utils/WtLogger.cpp | 32 +++++++++++++ src/utils/WtLogger.hpp | 29 ++++++++++++ test/Makefile.am | 1 + test/database/DatabaseTest.cpp | 5 ++ tools/metadata/LmsMetadata.cpp | 4 ++ tools/metadata/Makefile.am | 1 + .../LmsSimilarityParameters.cpp | 6 ++- tools/similarity-parameters/Makefile.am | 1 + tools/similarity/LmsSimilarity.cpp | 6 ++- tools/similarity/Makefile.am | 1 + 32 files changed, 282 insertions(+), 88 deletions(-) create mode 100644 src/utils/StreamLogger.cpp create mode 100644 src/utils/StreamLogger.hpp create mode 100644 src/utils/WtLogger.cpp create mode 100644 src/utils/WtLogger.hpp diff --git a/src/Makefile.am b/src/Makefile.am index baccea91..47aa79e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -151,8 +151,12 @@ lms_SOURCES = \ $(srcdir)/utils/Path.cpp \ $(srcdir)/utils/Path.hpp \ $(srcdir)/utils/Service.hpp \ + $(srcdir)/utils/StreamLogger.cpp \ + $(srcdir)/utils/StreamLogger.hpp \ $(srcdir)/utils/Utils.cpp \ - $(srcdir)/utils/Utils.hpp + $(srcdir)/utils/Utils.hpp \ + $(srcdir)/utils/WtLogger.cpp \ + $(srcdir)/utils/WtLogger.hpp lms_CXXFLAGS=-std=c++17 -I$(srcdir)/ui $(MAGICKXX_CFLAGS) -D_REENTRANT lms_LDADD=$(MAGICKXX_LIBS) diff --git a/src/api/subsonic/SubsonicResource.cpp b/src/api/subsonic/SubsonicResource.cpp index 52b2dbc2..9cfea1f3 100644 --- a/src/api/subsonic/SubsonicResource.cpp +++ b/src/api/subsonic/SubsonicResource.cpp @@ -595,10 +595,10 @@ handleChangePassword(RequestContext& context) std::string username {getMandatoryParameterAs(context.parameters, "username")}; std::string password {decodePasswordIfNeeded(getMandatoryParameterAs(context.parameters, "password"))}; - if (!getService()->evaluatePasswordStrength(username, password)) + if (!ServiceProvider::get()->evaluatePasswordStrength(username, password)) throw PasswordTooWeakGenericError {}; - const User::PasswordHash hash {getService()->hashPassword(password)}; + const User::PasswordHash hash {ServiceProvider::get()->hashPassword(password)}; auto transaction {context.dbSession.createUniqueTransaction()}; @@ -677,10 +677,10 @@ handleCreateUserRequest(RequestContext& context) std::string password {decodePasswordIfNeeded(getMandatoryParameterAs(context.parameters, "password"))}; // Just ignore all the other fields as we don't handle them - if (!getService()->evaluatePasswordStrength(username, password)) + if (!ServiceProvider::get()->evaluatePasswordStrength(username, password)) throw PasswordTooWeakGenericError {}; - const User::PasswordHash hash {getService()->hashPassword(password)}; + const User::PasswordHash hash {ServiceProvider::get()->hashPassword(password)}; auto transaction {context.dbSession.createUniqueTransaction()}; @@ -960,7 +960,7 @@ handleGetArtistInfoRequestCommon(RequestContext& context, bool id3) artistInfoNode.createChild("musicBrainzId").setValue(artist->getMBID()); } - auto similarArtistsId {getService()->getSimilarArtists(context.dbSession, id.value, count)}; + auto similarArtistsId {ServiceProvider::get()->getSimilarArtists(context.dbSession, id.value, count)}; { auto transaction {context.dbSession.createSharedTransaction()}; @@ -1156,7 +1156,7 @@ handleGetSimilarSongsRequestCommon(RequestContext& context, bool id3) // Optional params std::size_t count {getParameterAs(context.parameters, "count").value_or(50)}; - auto similarArtistsId {getService()->getSimilarArtists(context.dbSession, id.value, 5)}; + auto similarArtistsId {ServiceProvider::get()->getSimilarArtists(context.dbSession, id.value, 5)}; auto transaction {context.dbSession.createSharedTransaction()}; @@ -1604,10 +1604,10 @@ handleUpdateUserRequest(RequestContext& context) if (password) { *password = decodePasswordIfNeeded(*password); - if (!getService()->evaluatePasswordStrength(username, *password)) + if (!ServiceProvider::get()->evaluatePasswordStrength(username, *password)) throw PasswordTooWeakGenericError {}; - hash = getService()->hashPassword(*password); + hash = ServiceProvider::get()->hashPassword(*password); } auto transaction {context.dbSession.createUniqueTransaction()}; @@ -1816,10 +1816,10 @@ handleGetCoverArt(RequestContext& context, Wt::Http::ResponseContinuation*) switch (id.type) { case Id::Type::Track: - res.data = getService()->getFromTrack(context.dbSession, id.value, Image::Format::JPEG, size); + res.data = ServiceProvider::get()->getFromTrack(context.dbSession, id.value, Image::Format::JPEG, size); break; case Id::Type::Release: - res.data = getService()->getFromRelease(context.dbSession, id.value, Image::Format::JPEG, size); + res.data = ServiceProvider::get()->getFromRelease(context.dbSession, id.value, Image::Format::JPEG, size); break; default: throw BadParameterGenericError {"id"}; @@ -1908,7 +1908,7 @@ SubsonicResource::handleRequest(const Wt::Http::Request &request, Wt::Http::Resp Session& dbSession {getOrCreateDbSession(_db)}; - switch (getService()->checkUserPassword(dbSession, + switch (ServiceProvider::get()->checkUserPassword(dbSession, boost::asio::ip::address::from_string(request.clientAddress()), clientInfo.user, clientInfo.password)) { diff --git a/src/av/AvTranscoder.cpp b/src/av/AvTranscoder.cpp index fd13e053..1dac0797 100644 --- a/src/av/AvTranscoder.cpp +++ b/src/av/AvTranscoder.cpp @@ -38,7 +38,7 @@ static std::filesystem::path ffmpegPath; void Transcoder::init() { - ffmpegPath = getService()->getPath("ffmpeg-file", "/usr/bin/ffmpeg"); + ffmpegPath = ServiceProvider::get()->getPath("ffmpeg-file", "/usr/bin/ffmpeg"); if (!std::filesystem::exists(ffmpegPath)) throw LmsException {"File '" + ffmpegPath.string() + "' does not exist!"}; } diff --git a/src/main/main.cpp b/src/main/main.cpp index b09f044d..3050be3a 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -35,35 +35,35 @@ #include "similarity/SimilaritySearcher.hpp" #include "ui/LmsApplication.hpp" #include "utils/Config.hpp" -#include "utils/Logger.hpp" #include "utils/Service.hpp" +#include "utils/WtLogger.hpp" std::vector generateWtConfig(std::string execPath) { std::vector args; - const std::filesystem::path wtConfigPath {getService()->getPath("working-dir") / "wt_config.xml"}; - const std::filesystem::path wtLogFilePath {getService()->getPath("log-file", "/var/log/lms.log")}; - const std::filesystem::path wtAccessLogFilePath {getService()->getPath("access-log-file", "/var/log/lms.access.log")}; + const std::filesystem::path wtConfigPath {ServiceProvider::get()->getPath("working-dir") / "wt_config.xml"}; + const std::filesystem::path wtLogFilePath {ServiceProvider::get()->getPath("log-file", "/var/log/lms.log")}; + const std::filesystem::path wtAccessLogFilePath {ServiceProvider::get()->getPath("access-log-file", "/var/log/lms.access.log")}; args.push_back(execPath); args.push_back("--config=" + wtConfigPath.string()); - args.push_back("--docroot=" + getService()->getString("docroot")); - args.push_back("--approot=" + getService()->getString("approot")); - args.push_back("--resources-dir=" + getService()->getString("wt-resources")); + args.push_back("--docroot=" + ServiceProvider::get()->getString("docroot")); + args.push_back("--approot=" + ServiceProvider::get()->getString("approot")); + args.push_back("--resources-dir=" + ServiceProvider::get()->getString("wt-resources")); - if (getService()->getBool("tls-enable", false)) + if (ServiceProvider::get()->getBool("tls-enable", false)) { - args.push_back("--https-port=" + std::to_string( getService()->getULong("listen-port", 5082))); - args.push_back("--https-address=" + getService()->getString("listen-addr", "0.0.0.0")); - args.push_back("--ssl-certificate=" + getService()->getString("tls-cert")); - args.push_back("--ssl-private-key=" + getService()->getString("tls-key")); - args.push_back("--ssl-tmp-dh=" + getService()->getString("tls-dh")); + args.push_back("--https-port=" + std::to_string( ServiceProvider::get()->getULong("listen-port", 5082))); + args.push_back("--https-address=" + ServiceProvider::get()->getString("listen-addr", "0.0.0.0")); + args.push_back("--ssl-certificate=" + ServiceProvider::get()->getString("tls-cert")); + args.push_back("--ssl-private-key=" + ServiceProvider::get()->getString("tls-key")); + args.push_back("--ssl-tmp-dh=" + ServiceProvider::get()->getString("tls-dh")); } else { - args.push_back("--http-port=" + std::to_string( getService()->getULong("listen-port", 5082))); - args.push_back("--http-address=" + getService()->getString("listen-addr", "0.0.0.0")); + args.push_back("--http-port=" + std::to_string( ServiceProvider::get()->getULong("listen-port", 5082))); + args.push_back("--http-address=" + ServiceProvider::get()->getString("listen-addr", "0.0.0.0")); } if (!wtAccessLogFilePath.empty()) @@ -74,8 +74,8 @@ std::vector generateWtConfig(std::string execPath) pt.put("server.application-settings..location", "*"); pt.put("server.application-settings.log-file", wtLogFilePath.string()); - pt.put("server.application-settings.log-config", getService()->getString("log-config", "* -debug -info:WebRequest")); - pt.put("server.application-settings.behind-reverse-proxy", getService()->getBool("behind-reverse-proxy", false)); + pt.put("server.application-settings.log-config", ServiceProvider::get()->getString("log-config", "* -debug -info:WebRequest")); + pt.put("server.application-settings.behind-reverse-proxy", ServiceProvider::get()->getBool("behind-reverse-proxy", false)); pt.put("server.application-settings.progressive-bootstrap", true); std::ofstream oss(wtConfigPath.string().c_str(), std::ios::out); @@ -109,10 +109,11 @@ int main(int argc, char* argv[]) close(STDIN_FILENO); ServiceProvider::create(configFilePath); + ServiceProvider::create(); // Make sure the working directory exists - std::filesystem::create_directories(getService()->getPath("working-dir")); - std::filesystem::create_directories(getService()->getPath("working-dir") / "cache"); + std::filesystem::create_directories(ServiceProvider::get()->getPath("working-dir")); + std::filesystem::create_directories(ServiceProvider::get()->getPath("working-dir") / "cache"); // Construct WT configuration and get the argc/argv back std::vector wtServerArgs = generateWtConfig(argv[0]); @@ -132,13 +133,13 @@ int main(int argc, char* argv[]) Av::Transcoder::init(); // Initializing a connection pool to the database that will be shared along services - Database::Db database {getService()->getPath("working-dir") / "lms.db"}; + Database::Db database {ServiceProvider::get()->getPath("working-dir") / "lms.db"}; UserInterface::LmsApplicationGroupContainer appGroups; // Service initialization order is important - ServiceProvider::create(getService()->getULong("login-throttler-max-entriees", 10000)); - ServiceProvider::create(getService()->getULong("login-throttler-max-entriees", 10000)); + ServiceProvider::create(ServiceProvider::get()->getULong("login-throttler-max-entriees", 10000)); + ServiceProvider::create(ServiceProvider::get()->getULong("login-throttler-max-entriees", 10000)); Scanner::MediaScanner& mediaScanner {ServiceProvider::create(database.createSession())}; Similarity::FeaturesScannerAddon similarityFeaturesScannerAddon {database.createSession()}; @@ -153,7 +154,7 @@ int main(int argc, char* argv[]) API::Subsonic::SubsonicResource subsonicResource {database}; // bind API resources - if (getService()->getBool("api-subsonic", true)) + if (ServiceProvider::get()->getBool("api-subsonic", true)) server.addResource(&subsonicResource, subsonicResource.getPath()); // bind UI entry point diff --git a/src/similarity/features/AcousticBrainzUtils.cpp b/src/similarity/features/AcousticBrainzUtils.cpp index e58121c6..26f74f3b 100644 --- a/src/similarity/features/AcousticBrainzUtils.cpp +++ b/src/similarity/features/AcousticBrainzUtils.cpp @@ -38,7 +38,7 @@ getJsonData(const std::string& mbid) { static const std::string defaultAPIURL = "https://acousticbrainz.org/api/v1/"; - const std::string url {getService()->getString("acousticbrainz-api-url", defaultAPIURL) + mbid + "/low-level"}; + const std::string url {ServiceProvider::get()->getString("acousticbrainz-api-url", defaultAPIURL) + mbid + "/low-level"}; boost::asio::io_service ioService; diff --git a/src/similarity/features/SimilarityFeaturesCache.cpp b/src/similarity/features/SimilarityFeaturesCache.cpp index 1c9ed6b6..8c5589ab 100644 --- a/src/similarity/features/SimilarityFeaturesCache.cpp +++ b/src/similarity/features/SimilarityFeaturesCache.cpp @@ -33,7 +33,7 @@ namespace Similarity { static std::filesystem::path getCacheDirectory() { - return getService()->getPath("working-dir") / "cache" / "features"; + return ServiceProvider::get()->getPath("working-dir") / "cache" / "features"; } static std::filesystem::path getCacheNetworkFilePath() @@ -243,7 +243,7 @@ FeaturesCache::read() void FeaturesCache::write() { - std::filesystem::create_directories(getService()->getPath("working-dir") / "cache" / "features"); + std::filesystem::create_directories(ServiceProvider::get()->getPath("working-dir") / "cache" / "features"); if (!networkToCacheFile(_network, getCacheNetworkFilePath()) || !objectPositionToCacheFile(_trackPositions, getCacheTrackPositionsFilePath())) diff --git a/src/ui/Auth.cpp b/src/ui/Auth.cpp index 3758967b..f1f37124 100644 --- a/src/ui/Auth.cpp +++ b/src/ui/Auth.cpp @@ -43,7 +43,7 @@ static void createAuthToken(Database::IdType userId, const Wt::WDateTime& expiry) { - const std::string secret {getService<::Auth::AuthTokenService>()->createAuthToken(LmsApp->getDbSession(), userId, expiry)}; + const std::string secret {ServiceProvider<::Auth::AuthTokenService>::get()->createAuthToken(LmsApp->getDbSession(), userId, expiry)}; LmsApp->setCookie(authCookieName, secret, @@ -61,7 +61,7 @@ processAuthToken(const Wt::WEnvironment& env) if (!authCookie) return std::nullopt; - const auto res {getService<::Auth::AuthTokenService>()->processAuthToken(LmsApp->getDbSession(), boost::asio::ip::address::from_string(env.clientAddress()), *authCookie)}; + const auto res {ServiceProvider<::Auth::AuthTokenService>::get()->processAuthToken(LmsApp->getDbSession(), boost::asio::ip::address::from_string(env.clientAddress()), *authCookie)}; switch (res.state) { case ::Auth::AuthTokenService::AuthTokenProcessResult::State::NotFound: @@ -124,7 +124,7 @@ class AuthModel : public Wt::WFormModel if (field == PasswordField) { - switch (getService<::Auth::PasswordService>()->checkUserPassword( + switch (ServiceProvider<::Auth::PasswordService>::get()->checkUserPassword( LmsApp->getDbSession(), boost::asio::ip::address::from_string(LmsApp->environment().clientAddress()), valueText(LoginNameField).toUTF8(), diff --git a/src/ui/LmsApplication.cpp b/src/ui/LmsApplication.cpp index a76ea3ee..cc84839b 100644 --- a/src/ui/LmsApplication.cpp +++ b/src/ui/LmsApplication.cpp @@ -529,7 +529,7 @@ LmsApplication::createHome() // Events from MediaScanner { const std::string sessionId {LmsApp->sessionId()}; - getService()->scanComplete().connect(this, [=] () + ServiceProvider::get()->scanComplete().connect(this, [=] () { Wt::WServer::instance()->post(sessionId, [=] { @@ -538,7 +538,7 @@ LmsApplication::createHome() }); }); - getService()->scanInProgress().connect(this, [=] (Scanner::ScanProgressStats stats) + ServiceProvider::get()->scanInProgress().connect(this, [=] (Scanner::ScanProgressStats stats) { Wt::WServer::instance()->post(sessionId, [=] { @@ -547,7 +547,7 @@ LmsApplication::createHome() }); }); - getService()->scheduled().connect(this, [=] (Wt::WDateTime dateTime) + ServiceProvider::get()->scheduled().connect(this, [=] (Wt::WDateTime dateTime) { Wt::WServer::instance()->post(sessionId, [=] { @@ -562,7 +562,7 @@ LmsApplication::createHome() { if (isUserAdmin()) { - const auto& stats {*getService()->getStatus().lastCompleteScanStats}; + const auto& stats {*ServiceProvider::get()->getStatus().lastCompleteScanStats}; notifyMsg(MsgType::Info, Wt::WString::tr("Lms.Admin.Database.scan-complete") .arg(static_cast(stats.nbFiles())) diff --git a/src/ui/PlayQueueView.cpp b/src/ui/PlayQueueView.cpp index 92267aad..2aa2493c 100644 --- a/src/ui/PlayQueueView.cpp +++ b/src/ui/PlayQueueView.cpp @@ -412,7 +412,7 @@ PlayQueue::addSome() void PlayQueue::enqueueRadioTrack() { - const std::vector trackToAddIds {getService()->getSimilarTracksFromTrackList(LmsApp->getDbSession(), _tracklistId, 1)}; + const std::vector trackToAddIds {ServiceProvider::get()->getSimilarTracksFromTrackList(LmsApp->getDbSession(), _tracklistId, 1)}; enqueueTracks(trackToAddIds); } diff --git a/src/ui/SettingsView.cpp b/src/ui/SettingsView.cpp index 3b983866..c1b430b6 100644 --- a/src/ui/SettingsView.cpp +++ b/src/ui/SettingsView.cpp @@ -80,7 +80,7 @@ class SettingsModel : public Wt::WFormModel Database::User::PasswordHash passwordHash; if (!valueText(PasswordField).empty()) - passwordHash = getService<::Auth::PasswordService>()->hashPassword(valueText(PasswordField).toUTF8()); + passwordHash = ServiceProvider<::Auth::PasswordService>::get()->hashPassword(valueText(PasswordField).toUTF8()); auto transaction {LmsApp->getDbSession().createUniqueTransaction()}; @@ -133,7 +133,7 @@ class SettingsModel : public Wt::WFormModel { if (!valueText(PasswordOldField).empty()) { - switch (getService<::Auth::PasswordService>()->checkUserPassword( + switch (ServiceProvider<::Auth::PasswordService>::get()->checkUserPassword( LmsApp->getDbSession(), boost::asio::ip::address::from_string(LmsApp->environment().clientAddress()), LmsApp->getUserLoginName(), @@ -161,7 +161,7 @@ class SettingsModel : public Wt::WFormModel { if (!valueText(PasswordField).empty()) { - if (!getService<::Auth::PasswordService>()->evaluatePasswordStrength(LmsApp->getUserLoginName(), valueText(PasswordField).toUTF8())) + if (!ServiceProvider<::Auth::PasswordService>::get()->evaluatePasswordStrength(LmsApp->getUserLoginName(), valueText(PasswordField).toUTF8())) error = Wt::WString::tr("Lms.password-too-weak"); } else diff --git a/src/ui/admin/DatabaseSettingsView.cpp b/src/ui/admin/DatabaseSettingsView.cpp index b28dcefc..2d2e8613 100644 --- a/src/ui/admin/DatabaseSettingsView.cpp +++ b/src/ui/admin/DatabaseSettingsView.cpp @@ -232,7 +232,7 @@ DatabaseSettingsView::refreshView() { model->saveData(); - getService()->requestReschedule(); + ServiceProvider::get()->requestReschedule(); LmsApp->notifyMsg(MsgType::Success, Wt::WString::tr("Lms.Admin.Database.settings-saved")); } @@ -249,7 +249,7 @@ DatabaseSettingsView::refreshView() immScanBtn->clicked().connect([=] () { - getService()->requestImmediateScan(); + ServiceProvider::get()->requestImmediateScan(); LmsApp->notifyMsg(MsgType::Info, Wt::WString::tr("Lms.Admin.Database.scan-launched")); }); diff --git a/src/ui/admin/DatabaseStatus.cpp b/src/ui/admin/DatabaseStatus.cpp index 4d758eb6..23577bfa 100644 --- a/src/ui/admin/DatabaseStatus.cpp +++ b/src/ui/admin/DatabaseStatus.cpp @@ -136,7 +136,7 @@ DatabaseStatus::refreshContents() Wt::WPushButton* reportBtn {bindNew("btn-report", Wt::WString::tr("Lms.Admin.Database.Status.get-report"))}; - const MediaScanner::Status status {getService()->getStatus()}; + const MediaScanner::Status status {ServiceProvider::get()->getStatus()}; if (status.lastCompleteScanStats) { bindString("last-scan", Wt::WString::tr("Lms.Admin.Database.Status.last-scan-status") diff --git a/src/ui/admin/InitWizardView.cpp b/src/ui/admin/InitWizardView.cpp index 28c7d350..2eeba3e5 100644 --- a/src/ui/admin/InitWizardView.cpp +++ b/src/ui/admin/InitWizardView.cpp @@ -55,7 +55,7 @@ class InitWizardModel : public Wt::WFormModel void saveData() { - const Database::User::PasswordHash passwordHash {getService<::Auth::PasswordService>()->hashPassword(valueText(PasswordField).toUTF8())}; + const Database::User::PasswordHash passwordHash {ServiceProvider<::Auth::PasswordService>::get()->hashPassword(valueText(PasswordField).toUTF8())}; auto transaction(LmsApp->getDbSession().createUniqueTransaction()); @@ -77,7 +77,7 @@ class InitWizardModel : public Wt::WFormModel if (!valueText(PasswordField).empty()) { // Evaluate the strength of the password - if (!getService<::Auth::PasswordService>()->evaluatePasswordStrength(valueText(AdminLoginField).toUTF8(), valueText(PasswordField).toUTF8())) + if (!ServiceProvider<::Auth::PasswordService>::get()->evaluatePasswordStrength(valueText(AdminLoginField).toUTF8(), valueText(PasswordField).toUTF8())) error = Wt::WString::tr("Lms.password-too-weak"); } else diff --git a/src/ui/admin/UserView.cpp b/src/ui/admin/UserView.cpp index a4bec9cc..dd438f88 100644 --- a/src/ui/admin/UserView.cpp +++ b/src/ui/admin/UserView.cpp @@ -82,7 +82,7 @@ class UserModel : public Wt::WFormModel { std::optional passwordHash; if (!valueText(PasswordField).empty()) - passwordHash = getService<::Auth::PasswordService>()->hashPassword(valueText(PasswordField).toUTF8()); + passwordHash = ServiceProvider<::Auth::PasswordService>::get()->hashPassword(valueText(PasswordField).toUTF8()); auto transaction {LmsApp->getDbSession().createUniqueTransaction()}; @@ -174,7 +174,7 @@ class UserModel : public Wt::WFormModel else { // Evaluate the strength of the password for non demo accounts - if (!getService<::Auth::PasswordService>()->evaluatePasswordStrength(getLoginName(), valueText(PasswordField).toUTF8())) + if (!ServiceProvider<::Auth::PasswordService>::get()->evaluatePasswordStrength(getLoginName(), valueText(PasswordField).toUTF8())) error = Wt::WString::tr("Lms.password-too-weak"); } } @@ -270,7 +270,7 @@ UserView::refreshView() // Demo account t->setFormWidget(UserModel::DemoField, std::make_unique()); - if (!userId && getService()->getBool("demo", false)) + if (!userId && ServiceProvider::get()->getBool("demo", false)) t->setCondition("if-demo", true); Wt::WPushButton* saveBtn = t->bindNew("save-btn", Wt::WString::tr(userId ? "Lms.save" : "Lms.create")); diff --git a/src/ui/explore/ArtistInfoView.cpp b/src/ui/explore/ArtistInfoView.cpp index 3c232a7c..5b260cc2 100644 --- a/src/ui/explore/ArtistInfoView.cpp +++ b/src/ui/explore/ArtistInfoView.cpp @@ -63,7 +63,7 @@ ArtistInfo::refresh() if (!artistId) return; - const std::vector artistsIds {getService()->getSimilarArtists(LmsApp->getDbSession(), *artistId, 5)}; + const std::vector artistsIds {ServiceProvider::get()->getSimilarArtists(LmsApp->getDbSession(), *artistId, 5)}; auto transaction {LmsApp->getDbSession().createSharedTransaction()}; diff --git a/src/ui/explore/ReleaseInfoView.cpp b/src/ui/explore/ReleaseInfoView.cpp index d3e7c238..16d14969 100644 --- a/src/ui/explore/ReleaseInfoView.cpp +++ b/src/ui/explore/ReleaseInfoView.cpp @@ -68,7 +68,7 @@ ReleaseInfo::refresh() if (!releaseId) return; - const std::vector releasesIds {getService()->getSimilarReleases(LmsApp->getDbSession(), *releaseId, 5)}; + const std::vector releasesIds {ServiceProvider::get()->getSimilarReleases(LmsApp->getDbSession(), *releaseId, 5)}; auto transaction {LmsApp->getDbSession().createSharedTransaction()}; diff --git a/src/ui/resource/ImageResource.cpp b/src/ui/resource/ImageResource.cpp index f11a7301..114ce5b5 100644 --- a/src/ui/resource/ImageResource.cpp +++ b/src/ui/resource/ImageResource.cpp @@ -80,7 +80,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons // DbSession are not thread safe { Wt::WApplication::UpdateLock lock {LmsApp}; - cover = getService()->getFromTrack(LmsApp->getDbSession(), *trackId, Image::Format::JPEG, *size); + cover = ServiceProvider::get()->getFromTrack(LmsApp->getDbSession(), *trackId, Image::Format::JPEG, *size); } } else if (releaseIdStr) @@ -92,7 +92,7 @@ ImageResource::handleRequest(const Wt::Http::Request& request, Wt::Http::Respons // DbSession are not thread safe { Wt::WApplication::UpdateLock lock {LmsApp}; - cover = getService()->getFromRelease(LmsApp->getDbSession(), *releaseId, Image::Format::JPEG, *size); + cover = ServiceProvider::get()->getFromRelease(LmsApp->getDbSession(), *releaseId, Image::Format::JPEG, *size); } } else diff --git a/src/utils/Logger.cpp b/src/utils/Logger.cpp index c713f7bf..79bfafe9 100644 --- a/src/utils/Logger.cpp +++ b/src/utils/Logger.cpp @@ -54,3 +54,21 @@ const char* getSeverityName(Severity sev) return ""; } +Log::Log(Logger* logger, Module module, Severity severity) + : _module {module}, + _severity {severity}, + _logger {logger} +{} + +Log::~Log() +{ + if (_logger) + _logger->processLog(*this); +} + +std::string +Log::getMessage() const +{ + return _oss.str(); +} + diff --git a/src/utils/Logger.hpp b/src/utils/Logger.hpp index a754f0a9..9597aa5c 100644 --- a/src/utils/Logger.hpp +++ b/src/utils/Logger.hpp @@ -20,9 +20,9 @@ #pragma once #include +#include -#include -#include +#include "Service.hpp" enum class Severity { @@ -54,11 +54,31 @@ enum class Module const char* getModuleName(Module mod); const char* getSeverityName(Severity sev); +class Logger; +class Log +{ + public: + Log(Logger* logger, Module module, Severity severity); + ~Log(); -TODO class logger -TODO class log entry + Module getModule() const { return _module; } + Severity getSeverity() const { return _severity; } + std::string getMessage() const; -TODO configure logger to redirect to either Wt's logger or to a ostream + std::ostringstream& getOstream() { return _oss; } -#define LMS_LOG(module, level) Wt::log(getSeverityName(Severity::level)) << Wt::WLogger::sep << "[" << getModuleName(Module::module) << "]" << Wt::WLogger::sep + private: + Module _module; + Severity _severity; + std::ostringstream _oss; + Logger* _logger {}; +}; + +class Logger +{ + public: + virtual void processLog(const Log& log) = 0; +}; + +#define LMS_LOG(module, severity) Log(ServiceProvider::get(), Module::module, Severity::severity).getOstream() diff --git a/src/utils/Service.hpp b/src/utils/Service.hpp index e72ef990..a18363ce 100644 --- a/src/utils/Service.hpp +++ b/src/utils/Service.hpp @@ -17,38 +17,41 @@ * along with LMS. If not, see . */ -#include +#pragma once -template +#include +#include + +template class ServiceProvider { public: + template + static + Class& + create(Args&&... args) + { + static_assert(std::is_base_of::value); + + assign(std::make_unique(std::forward(args)...)); + return *get(); + } template static - T& + Class& create(Args&&... args) { - assign(std::make_unique(std::forward(args)...)); + assign(std::make_unique(std::forward(args)...)); return *get(); } - static void assign(std::unique_ptr service) { _service = std::move(service); } + + static void assign(std::unique_ptr service) { _service = std::move(service); } static void clear() { _service.reset(); } - static T* get() { return _service.get(); } + static Class* get() { return _service.get(); } private: - static std::unique_ptr _service; + static inline std::unique_ptr _service; }; -template -std::unique_ptr ServiceProvider::_service = {}; - -template -T* -getService() -{ - return ServiceProvider::get(); -} - - diff --git a/src/utils/StreamLogger.cpp b/src/utils/StreamLogger.cpp new file mode 100644 index 00000000..f4fc9cf5 --- /dev/null +++ b/src/utils/StreamLogger.cpp @@ -0,0 +1,32 @@ +/* + * 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 "StreamLogger.hpp" + +StreamLogger::StreamLogger(std::ostream& os) +: _os {os} +{ +} + +void +StreamLogger::processLog(const Log& log) +{ + _os << "[" << getSeverityName(log.getSeverity()) << "] [" << getModuleName(log.getModule()) << "] " << log.getMessage() << std::endl; +} + diff --git a/src/utils/StreamLogger.hpp b/src/utils/StreamLogger.hpp new file mode 100644 index 00000000..8e1af39a --- /dev/null +++ b/src/utils/StreamLogger.hpp @@ -0,0 +1,34 @@ +/* + * 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 . + */ + +#pragma once + +#include "Logger.hpp" + +class StreamLogger final : public Logger +{ + public: + StreamLogger(std::ostream& oss); + + void processLog(const Log& log); + + private: + std::ostream& _os; +}; + diff --git a/src/utils/WtLogger.cpp b/src/utils/WtLogger.cpp new file mode 100644 index 00000000..393ed4df --- /dev/null +++ b/src/utils/WtLogger.cpp @@ -0,0 +1,32 @@ +/* + * 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 "WtLogger.hpp" + +#include +#include + +#include "Logger.hpp" + +void +WtLogger::processLog(const Log& log) +{ + Wt::log(getSeverityName(log.getSeverity())) << Wt::WLogger::sep << "[" << getModuleName(log.getModule()) << "]" << log.getMessage(); +} + diff --git a/src/utils/WtLogger.hpp b/src/utils/WtLogger.hpp new file mode 100644 index 00000000..65b94018 --- /dev/null +++ b/src/utils/WtLogger.hpp @@ -0,0 +1,29 @@ +/* + * 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 . + */ + +#pragma once + +#include "Logger.hpp" + +class WtLogger final : public Logger +{ + public: + void processLog(const Log& log) override; +}; + diff --git a/test/Makefile.am b/test/Makefile.am index 15efaba5..7235da83 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -27,6 +27,7 @@ test_database_SOURCES = \ $(top_srcdir)/src/database/Track.cpp \ $(top_srcdir)/src/database/User.cpp \ $(top_srcdir)/src/utils/Logger.cpp \ + $(top_srcdir)/src/utils/StreamLogger.cpp \ $(top_srcdir)/src/utils/Utils.cpp test_database_CXXFLAGS=-std=c++17 -I${top_srcdir}/src/ diff --git a/test/database/DatabaseTest.cpp b/test/database/DatabaseTest.cpp index e53dc774..0ca35a55 100644 --- a/test/database/DatabaseTest.cpp +++ b/test/database/DatabaseTest.cpp @@ -30,6 +30,8 @@ #include "database/Track.hpp" #include "database/User.hpp" +#include "utils/StreamLogger.hpp" + using namespace Database; #define CHECK(PRED) \ @@ -1253,6 +1255,9 @@ int main() try { + // log to stdout + ServiceProvider::create(std::cout); + const std::filesystem::path tmpFile {std::tmpnam(nullptr)}; ScopedFileDeleter tmpFileDeleter {tmpFile}; diff --git a/tools/metadata/LmsMetadata.cpp b/tools/metadata/LmsMetadata.cpp index a32eb64b..c446693c 100644 --- a/tools/metadata/LmsMetadata.cpp +++ b/tools/metadata/LmsMetadata.cpp @@ -9,6 +9,7 @@ #include "av/AvInfo.hpp" #include "metadata/AvFormat.hpp" #include "metadata/TagLibParser.hpp" +#include "utils/StreamLogger.hpp" std::ostream& operator<<(std::ostream& os, const MetaData::Artist& artist) { @@ -124,6 +125,9 @@ int main(int argc, char *argv[]) try { + // log to stdout + ServiceProvider::create(std::cout); + for (std::size_t i {}; i < static_cast(argc - 1); ++i) { std::filesystem::path file {argv[i + 1]}; diff --git a/tools/metadata/Makefile.am b/tools/metadata/Makefile.am index d6fe053c..027773ec 100644 --- a/tools/metadata/Makefile.am +++ b/tools/metadata/Makefile.am @@ -6,6 +6,7 @@ lms_metadata_SOURCES = \ $(top_srcdir)/src/metadata/AvFormat.cpp \ $(top_srcdir)/src/metadata/TagLibParser.cpp \ $(top_srcdir)/src/utils/Logger.cpp \ + $(top_srcdir)/src/utils/StreamLogger.cpp \ $(top_srcdir)/src/utils/Utils.cpp lms_metadata_CXXFLAGS=-std=c++17 -I$(top_srcdir)/src -D_REENTRANT diff --git a/tools/similarity-parameters/LmsSimilarityParameters.cpp b/tools/similarity-parameters/LmsSimilarityParameters.cpp index a7b5b877..530e9af7 100644 --- a/tools/similarity-parameters/LmsSimilarityParameters.cpp +++ b/tools/similarity-parameters/LmsSimilarityParameters.cpp @@ -6,19 +6,23 @@ #include "database/Db.hpp" #include "utils/Config.hpp" #include "utils/Service.hpp" +#include "utils/StreamLogger.hpp" int main(int argc, char *argv[]) { try { + // log to stdout + ServiceProvider::create(std::cout); + std::filesystem::path configFilePath {"/etc/lms.conf"}; if (argc >= 2) configFilePath = std::string(argv[1], 0, 256); ServiceProvider::create(configFilePath); - Database::Db db {getService()->getPath("working-dir") / "lms.db"}; + Database::Db db {ServiceProvider::get()->getPath("working-dir") / "lms.db"}; auto session {db.createSession()}; /* const FeatureSettings diff --git a/tools/similarity-parameters/Makefile.am b/tools/similarity-parameters/Makefile.am index 71c12de9..acaf7f98 100644 --- a/tools/similarity-parameters/Makefile.am +++ b/tools/similarity-parameters/Makefile.am @@ -18,6 +18,7 @@ lms_similarity_parameters_SOURCES = \ $(top_srcdir)/src/similarity/features/som/Network.cpp \ $(top_srcdir)/src/utils/Config.cpp \ $(top_srcdir)/src/utils/Logger.cpp \ + $(top_srcdir)/src/utils/StreamLogger.cpp \ $(top_srcdir)/src/utils/Utils.cpp lms_similarity_parameters_CXXFLAGS=-std=c++17 -I$(top_srcdir)/src -D_REENTRANT diff --git a/tools/similarity/LmsSimilarity.cpp b/tools/similarity/LmsSimilarity.cpp index ca475b8d..26110e31 100644 --- a/tools/similarity/LmsSimilarity.cpp +++ b/tools/similarity/LmsSimilarity.cpp @@ -7,6 +7,7 @@ #include "database/Session.hpp" #include "utils/Config.hpp" #include "utils/Service.hpp" +#include "utils/StreamLogger.hpp" #include "similarity/features/SimilarityFeaturesSearcher.hpp" int main(int argc, char *argv[]) @@ -15,6 +16,9 @@ int main(int argc, char *argv[]) { using namespace Similarity; + // log to stdout + ServiceProvider::create(std::cout); + const FeatureSettingsMap featuresSettings { // { "lowlevel.average_loudness", 1 }, @@ -34,7 +38,7 @@ int main(int argc, char *argv[]) ServiceProvider::create(configFilePath); - Database::Db db {getService()->getPath("working-dir") / "lms.db"}; + Database::Db db {ServiceProvider::get()->getPath("working-dir") / "lms.db"}; auto session {db.createSession()}; std::cout << "Getting all features..." << std::endl; diff --git a/tools/similarity/Makefile.am b/tools/similarity/Makefile.am index 2bd2c51c..02117e5f 100644 --- a/tools/similarity/Makefile.am +++ b/tools/similarity/Makefile.am @@ -21,6 +21,7 @@ lms_similarity_SOURCES = \ $(top_srcdir)/src/similarity/features/SimilarityFeaturesDefs.cpp \ $(top_srcdir)/src/utils/Config.cpp \ $(top_srcdir)/src/utils/Logger.cpp \ + $(top_srcdir)/src/utils/StreamLogger.cpp \ $(top_srcdir)/src/utils/Utils.cpp lms_similarity_CXXFLAGS=-std=c++17 -I$(top_srcdir)/src -D_REENTRANT