Split the lib in smaller libs to ease unit tests

This commit is contained in:
emeric
2020-02-13 18:04:35 +01:00
parent 1e2c1caeed
commit 15e53caa2d
131 changed files with 382 additions and 138 deletions
+119
View File
@@ -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;
}
}
+48
View File
@@ -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;
};
+74
View File
@@ -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();
}
+44
View File
@@ -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());
}
}
+89
View File
@@ -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);
}
+33
View File
@@ -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
+32
View File
@@ -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;
}
+208
View File
@@ -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
+52
View File
@@ -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};
}
+32
View File
@@ -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();
}