From 0f626f7716b7542e676a30f66c37db1afda07b46 Mon Sep 17 00:00:00 2001 From: emeric Date: Fri, 4 Oct 2024 10:06:45 +0200 Subject: [PATCH] Centralized default path for config file, fixes #525 --- src/libs/core/include/core/SystemPaths.hpp | 27 ++ src/lms/main.cpp | 304 +++++++++--------- src/tools/cover/LmsCover.cpp | 3 +- src/tools/db-generator/LmsDbGenerator.cpp | 3 +- .../recommendation/LmsRecommendation.cpp | 3 +- 5 files changed, 193 insertions(+), 147 deletions(-) create mode 100644 src/libs/core/include/core/SystemPaths.hpp diff --git a/src/libs/core/include/core/SystemPaths.hpp b/src/libs/core/include/core/SystemPaths.hpp new file mode 100644 index 00000000..7a6e0e46 --- /dev/null +++ b/src/libs/core/include/core/SystemPaths.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2024 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 + +namespace lms::core +{ + static inline const std::filesystem::path sysconfDirectory{ "/etc" }; +} \ No newline at end of file diff --git a/src/lms/main.cpp b/src/lms/main.cpp index 63cb1309..f2586a48 100644 --- a/src/lms/main.cpp +++ b/src/lms/main.cpp @@ -30,6 +30,7 @@ #include "core/ITraceLogger.hpp" #include "core/Service.hpp" #include "core/String.hpp" +#include "core/SystemPaths.hpp" #include "core/WtLogger.hpp" #include "database/Db.hpp" #include "database/Session.hpp" @@ -50,180 +51,195 @@ namespace lms { - std::size_t getThreadCount() + namespace { - const unsigned long configHttpServerThreadCount{ core::Service::get()->getULong("http-server-thread-count", 0) }; - - // Reserve at least 2 threads since we still have some blocking IO (for example when reading from ffmpeg) - return configHttpServerThreadCount ? configHttpServerThreadCount : std::max(2, std::thread::hardware_concurrency()); - } - - core::logging::Severity getLogMinSeverity() - { - std::string_view minSeverity{ core::Service::get()->getString("log-min-severity", "info") }; - - if (minSeverity == "debug") - return core::logging::Severity::DEBUG; - else if (minSeverity == "info") - return core::logging::Severity::INFO; - else if (minSeverity == "warning") - return core::logging::Severity::WARNING; - else if (minSeverity == "error") - return core::logging::Severity::ERROR; - else if (minSeverity == "fatal") - return core::logging::Severity::FATAL; - - throw core::LmsException{ "Invalid config value for 'log-min-severity'" }; - } - - std::optional getTracingLevel() - { - std::string_view tracingLevel{ core::Service::get()->getString("tracing-level", "disabled") }; - - if (tracingLevel == "disabled") - return std::nullopt; - else if (tracingLevel == "overview") - return core::tracing::Level::Overview; - else if (tracingLevel == "detailed") - return core::tracing::Level::Detailed; - - throw core::LmsException{ "Invalid config value for 'tracing-level'" }; - } - - std::vector generateWtConfig(std::string execPath, core::logging::Severity minSeverity) - { - std::vector args; - - const std::filesystem::path wtConfigPath{ core::Service::get()->getPath("working-dir") / "wt_config.xml" }; - const std::filesystem::path wtLogFilePath{ core::Service::get()->getPath("log-file", "/var/log/lms.log") }; - const std::filesystem::path wtAccessLogFilePath{ core::Service::get()->getPath("access-log-file", "/var/log/lms.access.log") }; - const std::filesystem::path wtResourcesPath{ core::Service::get()->getPath("wt-resources", "/usr/share/Wt/resources") }; - - args.push_back(execPath); - args.push_back("--config=" + wtConfigPath.string()); - args.push_back("--docroot=" + std::string{ core::Service::get()->getString("docroot") }); - args.push_back("--approot=" + std::string{ core::Service::get()->getString("approot") }); - args.push_back("--deploy-path=" + std::string{ core::Service::get()->getString("deploy-path", "/") }); - if (!wtResourcesPath.empty()) - args.push_back("--resources-dir=" + wtResourcesPath.string()); - - if (core::Service::get()->getBool("tls-enable", false)) + std::size_t getThreadCount() { - args.push_back("--https-port=" + std::to_string(core::Service::get()->getULong("listen-port", 5082))); - args.push_back("--https-address=" + std::string{ core::Service::get()->getString("listen-addr", "0.0.0.0") }); - args.push_back("--ssl-certificate=" + std::string{ core::Service::get()->getString("tls-cert") }); - args.push_back("--ssl-private-key=" + std::string{ core::Service::get()->getString("tls-key") }); - args.push_back("--ssl-tmp-dh=" + std::string{ core::Service::get()->getString("tls-dh") }); - } - else - { - args.push_back("--http-port=" + std::to_string(core::Service::get()->getULong("listen-port", 5082))); - args.push_back("--http-address=" + std::string{ core::Service::get()->getString("listen-addr", "0.0.0.0") }); + const unsigned long configHttpServerThreadCount{ core::Service::get()->getULong("http-server-thread-count", 0) }; + + // Reserve at least 2 threads since we still have some blocking IO (for example when reading from ffmpeg) + return configHttpServerThreadCount ? configHttpServerThreadCount : std::max(2, std::thread::hardware_concurrency()); } - if (!wtAccessLogFilePath.empty()) - args.push_back("--accesslog=" + wtAccessLogFilePath.string()); - - args.push_back("--threads=" + std::to_string(getThreadCount())); - - // Generate the wt_config.xml file - boost::property_tree::ptree pt; - - pt.put("server.application-settings..location", "*"); - pt.put("server.application-settings.log-file", wtLogFilePath.string()); - - // log-config - pt.put("server.application-settings.log-config", core::logging::WtLogger::computeLogConfig(minSeverity)); - pt.put("server.application-settings.behind-reverse-proxy", core::Service::get()->getBool("behind-reverse-proxy", false)); - + core::logging::Severity getLogMinSeverity() { - boost::property_tree::ptree viewport; - viewport.put(".name", "viewport"); - viewport.put(".content", "width=device-width, initial-scale=1, user-scalable=no"); - pt.add_child("server.application-settings.head-matter.meta", viewport); - } - { - boost::property_tree::ptree themeColor; - themeColor.put(".name", "theme-color"); - themeColor.put(".content", "#303030"); - pt.add_child("server.application-settings.head-matter.meta", themeColor); + std::string_view minSeverity{ core::Service::get()->getString("log-min-severity", "info") }; + + if (minSeverity == "debug") + return core::logging::Severity::DEBUG; + else if (minSeverity == "info") + return core::logging::Severity::INFO; + else if (minSeverity == "warning") + return core::logging::Severity::WARNING; + else if (minSeverity == "error") + return core::logging::Severity::ERROR; + else if (minSeverity == "fatal") + return core::logging::Severity::FATAL; + + throw core::LmsException{ "Invalid config value for 'log-min-severity'" }; } + std::optional getTracingLevel() { - std::ofstream oss{ wtConfigPath.string().c_str(), std::ios::out }; - if (!oss) - throw core::LmsException{ "Can't open '" + wtConfigPath.string() + "' for writing!" }; + std::string_view tracingLevel{ core::Service::get()->getString("tracing-level", "disabled") }; - boost::property_tree::xml_parser::write_xml(oss, pt); + if (tracingLevel == "disabled") + return std::nullopt; + else if (tracingLevel == "overview") + return core::tracing::Level::Overview; + else if (tracingLevel == "detailed") + return core::tracing::Level::Detailed; - if (!oss) - throw core::LmsException{ "Can't write in file '" + wtConfigPath.string() + "', no space left?" }; + throw core::LmsException{ "Invalid config value for 'tracing-level'" }; } - return args; - } + std::vector generateWtConfig(std::string execPath, core::logging::Severity minSeverity) + { + std::vector args; - void proxyScannerEventsToApplication(scanner::IScannerService& scanner, Wt::WServer& server) - { - auto postAll{ [](Wt::WServer& server, std::function cb) { - server.postAll([cb = std::move(cb)] { - // may be nullptr, see https://redmine.webtoolkit.eu/issues/8202 - if (LmsApp) - cb(); - }); - } }; + const std::filesystem::path wtConfigPath{ core::Service::get()->getPath("working-dir") / "wt_config.xml" }; + const std::filesystem::path wtLogFilePath{ core::Service::get()->getPath("log-file", "/var/log/lms.log") }; + const std::filesystem::path wtAccessLogFilePath{ core::Service::get()->getPath("access-log-file", "/var/log/lms.access.log") }; + const std::filesystem::path wtResourcesPath{ core::Service::get()->getPath("wt-resources", "/usr/share/Wt/resources") }; - scanner.getEvents().scanAborted.connect([&] { - postAll(server, [] { - LmsApp->getScannerEvents().scanAborted.emit(); - LmsApp->triggerUpdate(); - }); - }); + args.push_back(execPath); + args.push_back("--config=" + wtConfigPath.string()); + args.push_back("--docroot=" + std::string{ core::Service::get()->getString("docroot") }); + args.push_back("--approot=" + std::string{ core::Service::get()->getString("approot") }); + args.push_back("--deploy-path=" + std::string{ core::Service::get()->getString("deploy-path", "/") }); + if (!wtResourcesPath.empty()) + args.push_back("--resources-dir=" + wtResourcesPath.string()); - scanner.getEvents().scanStarted.connect([&] { - postAll(server, [] { - LmsApp->getScannerEvents().scanStarted.emit(); - LmsApp->triggerUpdate(); - }); - }); + if (core::Service::get()->getBool("tls-enable", false)) + { + args.push_back("--https-port=" + std::to_string(core::Service::get()->getULong("listen-port", 5082))); + args.push_back("--https-address=" + std::string{ core::Service::get()->getString("listen-addr", "0.0.0.0") }); + args.push_back("--ssl-certificate=" + std::string{ core::Service::get()->getString("tls-cert") }); + args.push_back("--ssl-private-key=" + std::string{ core::Service::get()->getString("tls-key") }); + args.push_back("--ssl-tmp-dh=" + std::string{ core::Service::get()->getString("tls-dh") }); + } + else + { + args.push_back("--http-port=" + std::to_string(core::Service::get()->getULong("listen-port", 5082))); + args.push_back("--http-address=" + std::string{ core::Service::get()->getString("listen-addr", "0.0.0.0") }); + } - scanner.getEvents().scanComplete.connect([&](const scanner::ScanStats& stats) { - postAll(server, [=] { - LmsApp->getScannerEvents().scanComplete.emit(stats); - LmsApp->triggerUpdate(); - }); - }); + if (!wtAccessLogFilePath.empty()) + args.push_back("--accesslog=" + wtAccessLogFilePath.string()); - scanner.getEvents().scanInProgress.connect([&](const scanner::ScanStepStats& stats) { - postAll(server, [=] { - LmsApp->getScannerEvents().scanInProgress.emit(stats); - LmsApp->triggerUpdate(); - }); - }); + args.push_back("--threads=" + std::to_string(getThreadCount())); - scanner.getEvents().scanScheduled.connect([&](const Wt::WDateTime dateTime) { - postAll(server, [=] { - LmsApp->getScannerEvents().scanScheduled.emit(dateTime); - LmsApp->triggerUpdate(); + // Generate the wt_config.xml file + boost::property_tree::ptree pt; + + pt.put("server.application-settings..location", "*"); + pt.put("server.application-settings.log-file", wtLogFilePath.string()); + + // log-config + pt.put("server.application-settings.log-config", core::logging::WtLogger::computeLogConfig(minSeverity)); + pt.put("server.application-settings.behind-reverse-proxy", core::Service::get()->getBool("behind-reverse-proxy", false)); + + { + boost::property_tree::ptree viewport; + viewport.put(".name", "viewport"); + viewport.put(".content", "width=device-width, initial-scale=1, user-scalable=no"); + pt.add_child("server.application-settings.head-matter.meta", viewport); + } + { + boost::property_tree::ptree themeColor; + themeColor.put(".name", "theme-color"); + themeColor.put(".content", "#303030"); + pt.add_child("server.application-settings.head-matter.meta", themeColor); + } + + { + std::ofstream oss{ wtConfigPath.string().c_str(), std::ios::out }; + if (!oss) + throw core::LmsException{ "Can't open '" + wtConfigPath.string() + "' for writing!" }; + + boost::property_tree::xml_parser::write_xml(oss, pt); + + if (!oss) + throw core::LmsException{ "Can't write in file '" + wtConfigPath.string() + "', no space left?" }; + } + + return args; + } + + void proxyScannerEventsToApplication(scanner::IScannerService& scanner, Wt::WServer& server) + { + auto postAll{ [](Wt::WServer& server, std::function cb) { + server.postAll([cb = std::move(cb)] { + // may be nullptr, see https://redmine.webtoolkit.eu/issues/8202 + if (LmsApp) + cb(); + }); + } }; + + scanner.getEvents().scanAborted.connect([&] { + postAll(server, [] { + LmsApp->getScannerEvents().scanAborted.emit(); + LmsApp->triggerUpdate(); + }); }); - }); - } + + scanner.getEvents().scanStarted.connect([&] { + postAll(server, [] { + LmsApp->getScannerEvents().scanStarted.emit(); + LmsApp->triggerUpdate(); + }); + }); + + scanner.getEvents().scanComplete.connect([&](const scanner::ScanStats& stats) { + postAll(server, [=] { + LmsApp->getScannerEvents().scanComplete.emit(stats); + LmsApp->triggerUpdate(); + }); + }); + + scanner.getEvents().scanInProgress.connect([&](const scanner::ScanStepStats& stats) { + postAll(server, [=] { + LmsApp->getScannerEvents().scanInProgress.emit(stats); + LmsApp->triggerUpdate(); + }); + }); + + scanner.getEvents().scanScheduled.connect([&](const Wt::WDateTime dateTime) { + postAll(server, [=] { + LmsApp->getScannerEvents().scanScheduled.emit(dateTime); + LmsApp->triggerUpdate(); + }); + }); + } + } // namespace int main(int argc, char* argv[]) { - std::filesystem::path configFilePath{ "/etc/lms.conf" }; + std::filesystem::path configFilePath{ core::sysconfDirectory / "lms.conf" }; int res{ EXIT_FAILURE }; assert(argc > 0); assert(argv[0] != NULL); + auto displayUsage{ [&](std::ostream& os) { + os << "Usage:\t" << argv[0] << "\t[conf_file]\n\n" + << "Options:\n" + << "\tconf_file:\t path to the LMS configuration file (defaults to " << configFilePath << ")\n\n"; + } }; + if (argc == 2) - configFilePath = std::string(argv[1], 0, 256); + { + const std::string_view arg{ argv[1] }; + if (arg == "-h" || arg == "--help") + { + displayUsage(std::cout); + return EXIT_SUCCESS; + } + configFilePath = std::string(arg, 0, 256); + } else if (argc > 2) { - std::cerr << "Usage:\t" << argv[0] << "\t[conf_file]\n\n" - << "Options:\n" - << "\tconf_file:\t path to the LMS configuration file (defaults to " << configFilePath << ")\n\n"; + displayUsage(std::cerr); return EXIT_FAILURE; } diff --git a/src/tools/cover/LmsCover.cpp b/src/tools/cover/LmsCover.cpp index ce5f5320..dee31376 100644 --- a/src/tools/cover/LmsCover.cpp +++ b/src/tools/cover/LmsCover.cpp @@ -28,6 +28,7 @@ #include "core/ILogger.hpp" #include "core/Service.hpp" #include "core/StreamLogger.hpp" +#include "core/SystemPaths.hpp" #include "database/Db.hpp" #include "database/Release.hpp" #include "database/Session.hpp" @@ -66,7 +67,7 @@ int main(int argc, char* argv[]) core::Service logger{ std::make_unique(std::cout) }; po::options_description desc{ "Allowed options" }; - desc.add_options()("help,h", "print usage message")("conf,c", po::value()->default_value("/etc/lms.conf"), "LMS config file")("default-cover,d", po::value(), "Default cover path")("tracks,t", "dump covers for tracks")("size,s", po::value()->default_value(512), "Requested cover size")("quality,q", po::value()->default_value(75), "JPEG quality (1-100)"); + desc.add_options()("help,h", "print usage message")("conf,c", po::value()->default_value(core::sysconfDirectory / "lms.conf"), "LMS config file")("default-cover,d", po::value(), "Default cover path")("tracks,t", "dump covers for tracks")("size,s", po::value()->default_value(512), "Requested cover size")("quality,q", po::value()->default_value(75), "JPEG quality (1-100)"); po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); diff --git a/src/tools/db-generator/LmsDbGenerator.cpp b/src/tools/db-generator/LmsDbGenerator.cpp index e41882ed..b046e04b 100644 --- a/src/tools/db-generator/LmsDbGenerator.cpp +++ b/src/tools/db-generator/LmsDbGenerator.cpp @@ -32,6 +32,7 @@ #include "core/Random.hpp" #include "core/Service.hpp" #include "core/StreamLogger.hpp" +#include "core/SystemPaths.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Db.hpp" @@ -177,7 +178,7 @@ int main(int argc, char* argv[]) const GeneratorParameters defaultParams; program_options::options_description options{ "Options" }; - options.add_options()("conf,c", program_options::value()->default_value("/etc/lms.conf"), "lms config file")("media-library-count", program_options::value()->default_value(defaultParams.mediaLibraryCount), "Number of media libraries to use")("release-count-per-batch", program_options::value()->default_value(defaultParams.releaseCountPerBatch), "Number of releases to generate before committing transaction")("release-count", program_options::value()->default_value(defaultParams.releaseCount), "Number of releases to generate")("track-count-per-release", program_options::value()->default_value(defaultParams.trackCountPerRelease), "Number of tracks per release")("compilation-ratio", program_options::value()->default_value(defaultParams.compilationRatio), "Compilation ratio (compilation means all tracks have a different artist)")("track-path", program_options::value()->required(), "Path of a valid track file, that will be used for all generated tracks")("genre-count", program_options::value()->default_value(defaultParams.genreCount), "Number of genres to generate")("genre-count-per-track", program_options::value()->default_value(defaultParams.genreCountPerTrack), "Number of genres to assign to each track")("mood-count", program_options::value()->default_value(defaultParams.moodCount), "Number of moods to generate")("mood-count-per-track", program_options::value()->default_value(defaultParams.moodCountPerTrack), "Number of moods to assign to each track")("help,h", "produce help message"); + options.add_options()("conf,c", program_options::value()->default_value(core::sysconfDirectory / "lms.conf"), "lms config file")("media-library-count", program_options::value()->default_value(defaultParams.mediaLibraryCount), "Number of media libraries to use")("release-count-per-batch", program_options::value()->default_value(defaultParams.releaseCountPerBatch), "Number of releases to generate before committing transaction")("release-count", program_options::value()->default_value(defaultParams.releaseCount), "Number of releases to generate")("track-count-per-release", program_options::value()->default_value(defaultParams.trackCountPerRelease), "Number of tracks per release")("compilation-ratio", program_options::value()->default_value(defaultParams.compilationRatio), "Compilation ratio (compilation means all tracks have a different artist)")("track-path", program_options::value()->required(), "Path of a valid track file, that will be used for all generated tracks")("genre-count", program_options::value()->default_value(defaultParams.genreCount), "Number of genres to generate")("genre-count-per-track", program_options::value()->default_value(defaultParams.genreCountPerTrack), "Number of genres to assign to each track")("mood-count", program_options::value()->default_value(defaultParams.moodCount), "Number of moods to generate")("mood-count-per-track", program_options::value()->default_value(defaultParams.moodCountPerTrack), "Number of moods to assign to each track")("help,h", "produce help message"); program_options::variables_map vm; program_options::store(program_options::parse_command_line(argc, argv, options), vm); diff --git a/src/tools/recommendation/LmsRecommendation.cpp b/src/tools/recommendation/LmsRecommendation.cpp index 578de0ba..0dd76576 100644 --- a/src/tools/recommendation/LmsRecommendation.cpp +++ b/src/tools/recommendation/LmsRecommendation.cpp @@ -27,6 +27,7 @@ #include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/StreamLogger.hpp" +#include "core/SystemPaths.hpp" #include "database/Artist.hpp" #include "database/Cluster.hpp" #include "database/Db.hpp" @@ -132,7 +133,7 @@ int main(int argc, char* argv[]) core::Service logger{ std::make_unique(std::cout) }; po::options_description desc{ "Allowed options" }; - desc.add_options()("help,h", "print usage message")("conf,c", po::value()->default_value("/etc/lms.conf"), "LMS config file")("artists,a", "Display recommendation for artists")("releases,r", "Display recommendation for releases")("tracks,t", "Display recommendation for tracks")("max,m", po::value()->default_value(3), "Max similarity result count"); + desc.add_options()("help,h", "print usage message")("conf,c", po::value()->default_value(core::sysconfDirectory / "lms.conf"), "LMS config file")("artists,a", "Display recommendation for artists")("releases,r", "Display recommendation for releases")("tracks,t", "Display recommendation for tracks")("max,m", po::value()->default_value(3), "Max similarity result count"); po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm);