Split the lib in smaller libs to ease unit tests
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
|
||||
add_library(lmsutils SHARED
|
||||
impl/Config.cpp
|
||||
impl/Logger.cpp
|
||||
impl/NetAddress.cpp
|
||||
impl/Path.cpp
|
||||
impl/Random.cpp
|
||||
impl/StreamLogger.cpp
|
||||
impl/String.cpp
|
||||
impl/UUID.cpp
|
||||
impl/WtLogger.cpp
|
||||
)
|
||||
|
||||
target_include_directories(lmsutils INTERFACE
|
||||
include
|
||||
)
|
||||
|
||||
target_include_directories(lmsutils PRIVATE
|
||||
include
|
||||
)
|
||||
|
||||
target_link_libraries(lmsutils PRIVATE
|
||||
config++
|
||||
)
|
||||
|
||||
target_link_libraries(lmsutils PUBLIC
|
||||
stdc++fs
|
||||
)
|
||||
|
||||
install(TARGETS lmsutils DESTINATION lib)
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 "Config.hpp"
|
||||
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
|
||||
std::unique_ptr<IConfig> createConfig(const std::filesystem::path& p)
|
||||
{
|
||||
return std::make_unique<Config>(p);
|
||||
}
|
||||
|
||||
Config::Config(const std::filesystem::path& p)
|
||||
{
|
||||
try
|
||||
{
|
||||
_config.readFile(p.string().c_str());
|
||||
}
|
||||
catch( libconfig::FileIOException& e)
|
||||
{
|
||||
throw LmsException {"Cannot open config file '" + p.string() + "'"};
|
||||
}
|
||||
catch( libconfig::ParseException& e)
|
||||
{
|
||||
throw LmsException {"Cannot parse config file '" + p.string() + "', line = " + std::to_string(e.getLine()) + ", error = '" + e.getError() + "'"};
|
||||
}
|
||||
catch (libconfig::ConfigException& e)
|
||||
{
|
||||
throw LmsException {"Cannot open config file '" + p.string() + "': " + e.what()};
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Config::getString(const std::string& setting, const std::string& def, const std::unordered_set<std::string>& allowedValues)
|
||||
{
|
||||
try {
|
||||
std::string res {(const char*)_config.lookup(setting)};
|
||||
|
||||
if (!allowedValues.empty() && allowedValues.find(res) == std::cend(allowedValues))
|
||||
{
|
||||
LMS_LOG(MAIN, ERROR) << "Invalid setting for '" << setting << "', using default value '" << def << "'";
|
||||
return def;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path
|
||||
Config::getPath(const std::string& setting, const std::filesystem::path& path)
|
||||
{
|
||||
try {
|
||||
const char* res = _config.lookup(setting);
|
||||
return std::filesystem::path {std::string(res)};
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long
|
||||
Config::getULong(const std::string& setting, unsigned long def)
|
||||
{
|
||||
try {
|
||||
return static_cast<unsigned int>(_config.lookup(setting));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
long
|
||||
Config::getLong(const std::string& setting, long def)
|
||||
{
|
||||
try {
|
||||
return _config.lookup(setting);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Config::getBool(const std::string& setting, bool def)
|
||||
{
|
||||
try {
|
||||
return _config.lookup(setting);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "utils/IConfig.hpp"
|
||||
|
||||
#include <libconfig.h++>
|
||||
|
||||
// Used to get config values from configuration files
|
||||
class Config final : public IConfig
|
||||
{
|
||||
public:
|
||||
Config(const std::filesystem::path& p);
|
||||
~Config() = default;
|
||||
|
||||
Config(const Config&) = delete;
|
||||
Config& operator=(const Config&) = delete;
|
||||
Config(Config&&) = delete;
|
||||
Config& operator=(Config&&) = delete;
|
||||
|
||||
// Default values are returned in case of setting not found
|
||||
std::string getString(const std::string& setting, const std::string& def = "", const std::unordered_set<std::string>& allowedValues = {}) override;
|
||||
std::filesystem::path getPath(const std::string& setting, const std::filesystem::path& def = std::filesystem::path()) override;
|
||||
unsigned long getULong(const std::string& setting, unsigned long def = 0) override;
|
||||
long getLong(const std::string& setting, long def = 0) override;
|
||||
bool getBool(const std::string& setting, bool def = false) override;
|
||||
|
||||
private:
|
||||
|
||||
libconfig::Config _config;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 "utils/Logger.hpp"
|
||||
|
||||
const char* getModuleName(Module mod)
|
||||
{
|
||||
switch (mod)
|
||||
{
|
||||
case Module::API_SUBSONIC: return "API_SUBSONIC";
|
||||
case Module::AUTH: return "AUTH";
|
||||
case Module::AV: return "AV";
|
||||
case Module::COVER: return "COVER";
|
||||
case Module::DB: return "DB";
|
||||
case Module::DBUPDATER: return "DB UPDATER";
|
||||
case Module::FEATURE: return "FEATURE";
|
||||
case Module::MAIN: return "MAIN";
|
||||
case Module::METADATA: return "METADATA";
|
||||
case Module::REMOTE: return "REMOTE";
|
||||
case Module::SERVICE: return "SERVICE";
|
||||
case Module::SIMILARITY: return "SIMILARITY";
|
||||
case Module::TRANSCODE: return "TRANSCODE";
|
||||
case Module::UI: return "UI";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const char* getSeverityName(Severity sev)
|
||||
{
|
||||
switch (sev)
|
||||
{
|
||||
case Severity::FATAL: return "fatal";
|
||||
case Severity::ERROR: return "error";
|
||||
case Severity::WARNING: return "warning";
|
||||
case Severity::INFO: return "info";
|
||||
case Severity::DEBUG: return "debug";
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils/NetAddress.hpp"
|
||||
|
||||
namespace std
|
||||
{
|
||||
std::size_t hash<boost::asio::ip::address>::operator()(const boost::asio::ip::address& ipAddr) const
|
||||
{
|
||||
if (ipAddr.is_v4())
|
||||
return ipAddr.to_v4().to_ulong();
|
||||
|
||||
if (ipAddr.is_v6())
|
||||
{
|
||||
const auto& range {ipAddr.to_v6().to_bytes()};
|
||||
std::size_t res {};
|
||||
|
||||
for (auto b : range)
|
||||
res ^= std::hash<char>{}(static_cast<char>(b));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return std::hash<std::string>{}(ipAddr.to_string());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 "utils/Path.hpp"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/crc.hpp> // for boost::crc_32_type
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "utils/Exception.hpp"
|
||||
#include "utils/Logger.hpp"
|
||||
|
||||
void
|
||||
computeCrc(const std::filesystem::path& p, std::vector<unsigned char>& crc)
|
||||
{
|
||||
using crc_type = boost::crc_32_type;
|
||||
crc_type result;
|
||||
|
||||
std::ifstream ifs( p.string().c_str(), std::ios_base::binary );
|
||||
|
||||
if (ifs)
|
||||
{
|
||||
do
|
||||
{
|
||||
std::array<char,1024> buffer;
|
||||
|
||||
ifs.read( buffer.data(), buffer.size() );
|
||||
result.process_bytes( buffer.data(), ifs.gcount() );
|
||||
}
|
||||
while ( ifs );
|
||||
}
|
||||
else
|
||||
{
|
||||
LMS_LOG(DBUPDATER, ERROR) << "Failed to open file '" << p.string() << "'";
|
||||
throw LmsException("Failed to open file '" + p.string() + "'" );
|
||||
}
|
||||
|
||||
|
||||
// Copy the result into a vector of unsigned char
|
||||
const crc_type::value_type checksum = result.checksum();
|
||||
for (std::size_t i = 0; (i+1)*8 <= crc_type::bit_count; i++)
|
||||
{
|
||||
const unsigned char* data = reinterpret_cast<const unsigned char*>( &checksum );
|
||||
crc.push_back(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ensureDirectory(const std::filesystem::path& dir)
|
||||
{
|
||||
if (std::filesystem::exists(dir))
|
||||
return std::filesystem::is_directory(dir);
|
||||
else
|
||||
return std::filesystem::create_directory(dir);
|
||||
}
|
||||
|
||||
Wt::WDateTime
|
||||
getLastWriteTime(const std::filesystem::path& file)
|
||||
{
|
||||
struct stat sb {};
|
||||
|
||||
if (stat(file.string().c_str(), &sb) == -1)
|
||||
throw LmsException("Failed to get stats on file '" + file.string() + "'" );
|
||||
|
||||
return Wt::WDateTime::fromTime_t(sb.st_mtime);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 "utils/Random.hpp"
|
||||
|
||||
namespace Random {
|
||||
|
||||
RandGenerator& getRandGenerator()
|
||||
{
|
||||
static thread_local std::random_device rd;
|
||||
static thread_local std::mt19937 randGenerator(rd());
|
||||
|
||||
return randGenerator;
|
||||
}
|
||||
|
||||
} // Random
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils/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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 "utils/String.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
bool
|
||||
readList(const std::string& str, const std::string& separators, std::list<std::string>& results)
|
||||
{
|
||||
std::string curStr;
|
||||
|
||||
for (char c : str)
|
||||
{
|
||||
if (separators.find(c) != std::string::npos) {
|
||||
if (!curStr.empty()) {
|
||||
results.push_back(curStr);
|
||||
curStr.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (curStr.empty() && std::isspace(c))
|
||||
continue;
|
||||
|
||||
curStr.push_back(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (!curStr.empty())
|
||||
results.push_back(curStr);
|
||||
|
||||
return !str.empty();
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<std::string>
|
||||
readAs(const std::string& str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
splitString(const std::string& string, const std::string& separators)
|
||||
{
|
||||
std::string str {stringTrim(string, separators)};
|
||||
|
||||
std::vector<std::string> res;
|
||||
boost::algorithm::split(res, str, boost::is_any_of(separators), boost::token_compress_on);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter)
|
||||
{
|
||||
return boost::algorithm::join(strings, delimiter);
|
||||
}
|
||||
|
||||
std::string
|
||||
stringTrim(const std::string& str, const std::string& whitespace)
|
||||
{
|
||||
const auto strBegin = str.find_first_not_of(whitespace);
|
||||
if (strBegin == std::string::npos)
|
||||
return ""; // no content
|
||||
|
||||
const auto strEnd = str.find_last_not_of(whitespace);
|
||||
const auto strRange = strEnd - strBegin + 1;
|
||||
|
||||
return str.substr(strBegin, strRange);
|
||||
}
|
||||
|
||||
std::string
|
||||
stringTrimEnd(const std::string& str, const std::string& whitespace)
|
||||
{
|
||||
return str.substr(0, str.find_last_not_of(whitespace)+1);
|
||||
}
|
||||
|
||||
std::string
|
||||
stringToLower(const std::string& str)
|
||||
{
|
||||
return boost::algorithm::to_lower_copy(str);
|
||||
}
|
||||
|
||||
std::string
|
||||
stringToUpper(const std::string& str)
|
||||
{
|
||||
return boost::to_upper_copy<std::string>(str);
|
||||
}
|
||||
|
||||
std::string
|
||||
bufferToString(const std::vector<unsigned char>& data)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
|
||||
for (unsigned char c : data)
|
||||
{
|
||||
oss << std::setw(2) << std::setfill('0') << std::hex << (int)c;
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string
|
||||
replaceInString(const std::string& str, const std::string& from, const std::string& to)
|
||||
{
|
||||
std::string res {str};
|
||||
size_t pos = 0;
|
||||
|
||||
while ((pos = res.find(from, pos)) != std::string::npos)
|
||||
{
|
||||
res.replace(pos, from.length(), to);
|
||||
pos += to.length();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string
|
||||
jsEscape(const std::string& str)
|
||||
{
|
||||
static const std::unordered_map<char, std::string_view> escapeMap
|
||||
{
|
||||
{ '\\', "\\\\" },
|
||||
{ '\n', "\\n" },
|
||||
{ '\r', "\\r" },
|
||||
{ '\t', "\\t" },
|
||||
{ '"', "\\\"" },
|
||||
};
|
||||
|
||||
std::string escaped;
|
||||
escaped.reserve(str.length());
|
||||
|
||||
for (const char c : str)
|
||||
{
|
||||
auto it {escapeMap.find(c)};
|
||||
if (it == std::cend(escapeMap))
|
||||
{
|
||||
escaped += c;
|
||||
continue;
|
||||
}
|
||||
|
||||
escaped += it->second;
|
||||
}
|
||||
|
||||
return escaped;
|
||||
}
|
||||
|
||||
bool
|
||||
stringEndsWith(const std::string& str, const std::string& ending)
|
||||
{
|
||||
return boost::algorithm::ends_with(str, ending);
|
||||
}
|
||||
|
||||
std::optional<std::string>
|
||||
stringFromHex(const std::string& str)
|
||||
{
|
||||
static const char lut[] {"0123456789ABCDEF"};
|
||||
|
||||
if (str.length() % 2 != 0)
|
||||
return std::nullopt;
|
||||
|
||||
std::string res;
|
||||
res.reserve(str.length() / 2);
|
||||
|
||||
auto it {std::cbegin(str)};
|
||||
while (it != std::cend(str))
|
||||
{
|
||||
unsigned val {};
|
||||
|
||||
auto itHigh {std::lower_bound(std::cbegin(lut), std::cend(lut), std::toupper(*(it++)))};
|
||||
auto itLow {std::lower_bound(std::cbegin(lut), std::cend(lut), std::toupper(*(it++)))};
|
||||
|
||||
if (itHigh == std::cend(lut) || itLow == std::cend(lut))
|
||||
return {};
|
||||
|
||||
val = std::distance(std::cbegin(lut), itHigh) << 4;
|
||||
val += std::distance(std::cbegin(lut), itLow );
|
||||
|
||||
res.push_back(static_cast<char>(val));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // StringUtils
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 "utils/UUID.hpp"
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace StringUtils
|
||||
{
|
||||
template <>
|
||||
std::optional<UUID>
|
||||
readAs(const std::string& str)
|
||||
{
|
||||
return UUID::fromString(str);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
stringIsUUID(std::string_view str)
|
||||
{
|
||||
static const std::regex re { R"([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})"};
|
||||
|
||||
return std::regex_match(std::cbegin(str), std::cend(str), re);
|
||||
}
|
||||
|
||||
|
||||
std::optional<UUID>
|
||||
UUID::fromString(std::string_view str)
|
||||
{
|
||||
if (!stringIsUUID(str))
|
||||
return std::nullopt;
|
||||
|
||||
return UUID {str};
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils/WtLogger.hpp"
|
||||
|
||||
#include <Wt/WApplication.h>
|
||||
#include <Wt/WLogger.h>
|
||||
|
||||
#include "utils/Logger.hpp"
|
||||
|
||||
void
|
||||
WtLogger::processLog(const Log& log)
|
||||
{
|
||||
Wt::log(getSeverityName(log.getSeverity())) << Wt::WLogger::sep << "[" << getModuleName(log.getModule()) << "]" << Wt::WLogger::sep << log.getMessage();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
class LmsException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
LmsException(const std::string& error = "") : std::runtime_error {error} {}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
|
||||
// Used to get config values from configuration files
|
||||
class IConfig
|
||||
{
|
||||
public:
|
||||
|
||||
// Default values are returned in case of setting not found
|
||||
virtual std::string getString(const std::string& setting, const std::string& def = "", const std::unordered_set<std::string>& allowedValues = {}) = 0;
|
||||
virtual std::filesystem::path getPath(const std::string& setting, const std::filesystem::path& def = std::filesystem::path()) = 0;
|
||||
virtual unsigned long getULong(const std::string& setting, unsigned long def = 0) = 0;
|
||||
virtual long getLong(const std::string& setting, long def = 0) = 0;
|
||||
virtual bool getBool(const std::string& setting, bool def = false) = 0;
|
||||
};
|
||||
|
||||
|
||||
std::unique_ptr<IConfig> createConfig(const std::filesystem::path& p);
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "Service.hpp"
|
||||
|
||||
enum class Severity
|
||||
{
|
||||
FATAL,
|
||||
ERROR,
|
||||
WARNING,
|
||||
INFO,
|
||||
DEBUG,
|
||||
};
|
||||
|
||||
enum class Module
|
||||
{
|
||||
API_SUBSONIC,
|
||||
AUTH,
|
||||
AV,
|
||||
COVER,
|
||||
DB,
|
||||
DBUPDATER,
|
||||
FEATURE,
|
||||
MAIN,
|
||||
METADATA,
|
||||
REMOTE,
|
||||
SERVICE,
|
||||
SIMILARITY,
|
||||
TRANSCODE,
|
||||
UI,
|
||||
};
|
||||
|
||||
const char* getModuleName(Module mod);
|
||||
const char* getSeverityName(Severity sev);
|
||||
|
||||
class Logger;
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
Log(Logger* logger, Module module, Severity severity);
|
||||
~Log();
|
||||
|
||||
Module getModule() const { return _module; }
|
||||
Severity getSeverity() const { return _severity; }
|
||||
std::string getMessage() const;
|
||||
|
||||
std::ostringstream& getOstream() { return _oss; }
|
||||
|
||||
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<Logger>::get(), Module::module, Severity::severity).getOstream()
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<boost::asio::ip::address>
|
||||
{
|
||||
std::size_t operator()(const boost::asio::ip::address& ipAddr) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Wt/WDateTime.h>
|
||||
|
||||
void computeCrc(const std::filesystem::path& p, std::vector<unsigned char>& checksum);
|
||||
|
||||
// Make sure the given path is a directory
|
||||
// Create it if needed
|
||||
bool ensureDirectory(const std::filesystem::path& dir);
|
||||
|
||||
// Get the last write time since Epoch
|
||||
Wt::WDateTime getLastWriteTime(const std::filesystem::path& dir);
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
|
||||
namespace Random {
|
||||
|
||||
using RandGenerator = std::mt19937;
|
||||
RandGenerator& getRandGenerator();
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
getRandom(T min, T max)
|
||||
{
|
||||
std::uniform_int_distribution<> dist {min, max};
|
||||
return dist (getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T
|
||||
getRealRandom(T min, T max)
|
||||
{
|
||||
std::uniform_real_distribution<> dist {min, max};
|
||||
return dist (getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void
|
||||
shuffleContainer(Container& container)
|
||||
{
|
||||
std::shuffle(std::begin(container), std::end(container), getRandGenerator());
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
typename Container::const_iterator
|
||||
pickRandom(const Container& container)
|
||||
{
|
||||
if (container.empty())
|
||||
return std::end(container);
|
||||
|
||||
return std::next(std::begin(container), getRandom(0, static_cast<int>(container.size() - 1)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
template <typename Class>
|
||||
class ServiceProvider
|
||||
{
|
||||
public:
|
||||
template <class DerivedClass, class ...Args>
|
||||
static
|
||||
Class&
|
||||
create(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<Class, DerivedClass>::value);
|
||||
|
||||
assign(std::make_unique<DerivedClass>(std::forward<Args>(args)...));
|
||||
return *get();
|
||||
}
|
||||
|
||||
template <class ...Args>
|
||||
static
|
||||
Class&
|
||||
create(Args&&... args)
|
||||
{
|
||||
assign(std::make_unique<Class>(std::forward<Args>(args)...));
|
||||
return *get();
|
||||
}
|
||||
|
||||
static
|
||||
Class&
|
||||
assign(std::unique_ptr<Class> service)
|
||||
{
|
||||
_service = std::move(service);
|
||||
return *get();
|
||||
}
|
||||
|
||||
static void clear() { _service.reset(); }
|
||||
|
||||
static Class* get() { return _service.get(); }
|
||||
|
||||
private:
|
||||
static inline std::unique_ptr<Class> _service;
|
||||
};
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
class StreamLogger final : public Logger
|
||||
{
|
||||
public:
|
||||
StreamLogger(std::ostream& oss);
|
||||
|
||||
void processLog(const Log& log);
|
||||
|
||||
private:
|
||||
std::ostream& _os;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace StringUtils {
|
||||
|
||||
|
||||
std::vector<std::string>
|
||||
splitString(const std::string& string, const std::string& separators);
|
||||
|
||||
std::string
|
||||
joinStrings(const std::vector<std::string>& strings, const std::string& delimiter);
|
||||
|
||||
std::string
|
||||
stringTrim(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
std::string
|
||||
stringTrimEnd(const std::string& str, const std::string& whitespaces = " \t");
|
||||
|
||||
std::string
|
||||
stringToLower(const std::string& str);
|
||||
|
||||
std::string
|
||||
stringToUpper(const std::string& str);
|
||||
|
||||
std::string
|
||||
bufferToString(const std::vector<unsigned char>& data);
|
||||
|
||||
template<typename T>
|
||||
std::optional<T> readAs(const std::string& str)
|
||||
{
|
||||
T res;
|
||||
|
||||
std::istringstream iss ( str );
|
||||
iss >> res;
|
||||
if (iss.fail())
|
||||
return std::nullopt;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::optional<std::string>
|
||||
readAs(const std::string& str);
|
||||
|
||||
std::string
|
||||
replaceInString(const std::string& str, const std::string& from, const std::string& to);
|
||||
|
||||
std::string
|
||||
jsEscape(const std::string& str);
|
||||
|
||||
bool
|
||||
stringEndsWith(const std::string& str, const std::string& ending);
|
||||
|
||||
std::optional<std::string>
|
||||
stringFromHex(const std::string& str);
|
||||
|
||||
} // StringUtils
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "utils/String.hpp"
|
||||
|
||||
class UUID
|
||||
{
|
||||
public:
|
||||
|
||||
static std::optional<UUID> fromString(std::string_view str);
|
||||
|
||||
std::string_view getAsString() const { return _value; }
|
||||
|
||||
private:
|
||||
UUID(std::string_view value) : _value {value} {}
|
||||
std::string _value;
|
||||
};
|
||||
|
||||
namespace StringUtils
|
||||
{
|
||||
template <>
|
||||
std::optional<UUID>
|
||||
readAs(const std::string& str);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
template<class T, class Compare = std::less<>>
|
||||
constexpr T clamp(T v, T lo, T hi, Compare comp = {})
|
||||
{
|
||||
assert(!comp(hi, lo));
|
||||
return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
class WtLogger final : public Logger
|
||||
{
|
||||
public:
|
||||
void processLog(const Log& log) override;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user