Skip to content
Snippets Groups Projects
Verified Commit e9a21d19 authored by Timm Fitschen's avatar Timm Fitschen
Browse files

Merge branch 'f-remove-boost-rdep' into f-acm

parents 29c1b077 31074c23
No related branches found
No related tags found
2 merge requests!42Release 0.2.0,!40F dot in username
This commit is part of merge request !40. Comments created here will be created in the context of that merge request.
...@@ -14,10 +14,10 @@ class CaosdbConan(ConanFile): ...@@ -14,10 +14,10 @@ class CaosdbConan(ConanFile):
default_options = {"shared": False, "fPIC": True} default_options = {"shared": False, "fPIC": True}
generators = "cmake" generators = "cmake"
requires = [ requires = [
("boost/1.77.0"),
("grpc/1.39.1"), ("grpc/1.39.1"),
] ]
build_requires = [ build_requires = [
("boost/1.77.0"),
("gtest/1.11.0"), ("gtest/1.11.0"),
] ]
exports = ("*.cmake", "*CMakeLists.txt", "*.in", exports = ("*.cmake", "*CMakeLists.txt", "*.in",
......
...@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ...@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
* Removed boost from the headers. Boost is only a build dependency from now on.
### Deprecated ### Deprecated
### Removed ### Removed
......
...@@ -25,27 +25,20 @@ ...@@ -25,27 +25,20 @@
#include "caosdb/authentication.h" // for Authenticator, PlainPassw... #include "caosdb/authentication.h" // for Authenticator, PlainPassw...
#include "caosdb/certificate_provider.h" // for CertificateProvider, path #include "caosdb/certificate_provider.h" // for CertificateProvider, path
#include "caosdb/exceptions.h" // for ConfigurationError #include "caosdb/exceptions.h" // for ConfigurationError
#include "caosdb/logging.h" // for SinkConfiguration, Loggin...
#include "caosdb/utility.h" // for load_json_file #include "caosdb/utility.h" // for load_json_file
#include <google/protobuf/arena.h> // for Arena #include <google/protobuf/arena.h> // for Arena
#include <google/protobuf/extension_set.h> // for Arena #include <google/protobuf/extension_set.h> // for Arena
#include <grpcpp/security/credentials.h> // for ChannelCredentials #include <grpcpp/security/credentials.h> // for ChannelCredentials
#include <boost/json/object.hpp> // for object
#include <boost/json/value.hpp> // for value
#include <boost/json/value_ref.hpp> // for array, object
// IWYU pragma: no_include "boost/json/fwd.hpp"
#include <filesystem> // for path, exists #include <filesystem> // for path, exists
#include <iosfwd> // for ostream #include <iosfwd> // for ostream
#include <memory> // for shared_ptr, unique_ptr #include <memory> // for shared_ptr, unique_ptr
#include <string> // for string #include <string> // for string
namespace caosdb::configuration { namespace caosdb::configuration {
using boost::json::array;
using boost::json::object;
using boost::json::value;
using caosdb::authentication::Authenticator; using caosdb::authentication::Authenticator;
using caosdb::authentication::PlainPasswordAuthenticator; using caosdb::authentication::PlainPasswordAuthenticator;
using caosdb::exceptions::ConfigurationError; using caosdb::exceptions::ConfigurationError;
using caosdb::utility::JsonValue;
using caosdb::utility::load_json_file; using caosdb::utility::load_json_file;
using google::protobuf::Arena; using google::protobuf::Arena;
using grpc::ChannelCredentials; using grpc::ChannelCredentials;
...@@ -102,69 +95,6 @@ public: ...@@ -102,69 +95,6 @@ public:
[[nodiscard]] auto ToString() const -> std::string override; [[nodiscard]] auto ToString() const -> std::string override;
}; };
/**
* Helper class (no state, just member functions) which should only be used by
* the ConfigurationManager to initialize the logging framework from the stored
* configuration.
*/
class LoggingConfigurationHelper {
public:
friend class ConfigurationManager;
private:
auto ConvertLogLevel(const std::string &string_level) const -> int;
auto CreateConsoleSinkConfiguration(const object &from, const std::string &name, int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration>;
auto CreateSyslogSinkConfiguration(const object &from, const std::string &name, int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration>;
auto CreateFileSinkConfiguration(const object &from, const std::string &name, int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration>;
auto CreateSinkConfiguration(const object &from, const std::string &name, int default_level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration>;
auto CreateLoggingConfiguration(const object &from) const
-> caosdb::logging::LoggingConfiguration;
};
/**
* Helper class (no state, just member functions) which should only be used by
* the ConfigurationManager to construct Connection instances from the stored
* configuration.
*/
class ConnectionConfigurationHelper {
public:
friend class ConfigurationManager;
private:
/**
* @param from - a single connection configuration.
*/
auto CreateCertificateProvider(const object &from) const -> std::unique_ptr<CertificateProvider>;
/**
* @param from - a single connection configuration.
*/
auto CreateAuthenticator(const object &from) const -> std::unique_ptr<Authenticator>;
/**
* @param from - a single connection configuration.
*/
auto CreateConnectionConfiguration(const bool tls, const std::string &host, const int port,
const CertificateProvider *certificate_provider,
const Authenticator *authenticator) const
-> std::unique_ptr<ConnectionConfiguration>;
/**
* @param from - a single connection configuration.
*/
auto IsTls(const object &from) const -> bool;
/**
* @param from - a single connection configuration.
*/
auto CreateConnectionConfiguration(const object &from) const
-> std::unique_ptr<ConnectionConfiguration>;
};
/** /**
* Reads the configuration file and keeps the configuration. Singleton. * Reads the configuration file and keeps the configuration. Singleton.
* *
...@@ -225,11 +155,10 @@ public: ...@@ -225,11 +155,10 @@ public:
private: private:
Arena arena; Arena arena;
value json_configuration; JsonValue json_configuration;
ConnectionConfigurationHelper connection_configuration_helper;
LoggingConfigurationHelper logging_configuration_helper;
inline ConfigurationManager(){ inline ConfigurationManager()
: json_configuration(nullptr){
// InitializeDefaults(); // InitializeDefaults();
}; };
...@@ -242,22 +171,6 @@ private: ...@@ -242,22 +171,6 @@ private:
*/ */
auto InitializeDefaults() -> int; auto InitializeDefaults() -> int;
/**
* Return a json object representing the current configuration.
*/
auto GetConfiguration() const -> const object &;
/**
* Return the connection configurations.
*/
auto GetConnections() const -> const object &;
/**
* Return the configuration for the connection with the given name (as a json
* object).
*/
auto GetConnection(const std::string &name) const -> const object &;
/** /**
* Reset this ConfigurationManager. * Reset this ConfigurationManager.
* *
......
...@@ -23,25 +23,13 @@ ...@@ -23,25 +23,13 @@
#define CAOSDB_UTILS_H #define CAOSDB_UTILS_H
#include "caosdb/data_type.h" // for AtomicDataType #include "caosdb/data_type.h" // for AtomicDataType
#include "caosdb/entity.h" // for Importance, Role #include "caosdb/entity.h" // for Importance, Role
#include <boost/beast/core/detail/base64.hpp> // for encoded_size
#include <boost/beast/core/detail/base64.ipp> // for encode
#include <boost/filesystem/string_file.hpp> // for load_string_file
#include <boost/json/stream_parser.hpp> // for stream_parser
#include <boost/json/value.hpp> // for value
#include <boost/lexical_cast.hpp> // for lexical_cast
#include <cassert> // for assert
#include <cstdlib> // for getenv #include <cstdlib> // for getenv
#include <filesystem> // for path #include <filesystem> // for path
#include <fstream> // for basic_istream<>::__ist... #include <fstream> // for basic_istream<>::__ist...
#include <memory> // for allocator, unique_ptr #include <memory> // for shared_ptr
#include <stdexcept> // for logic_error
#include <string> // for string, operator+, cha... #include <string> // for string, operator+, cha...
#include <type_traits> // for underlying_type_t
#include <typeinfo> // for type_info
namespace caosdb::utility { namespace caosdb::utility {
using boost::json::stream_parser;
using boost::json::value;
using std::ifstream; using std::ifstream;
using std::filesystem::exists; using std::filesystem::exists;
using std::filesystem::path; using std::filesystem::path;
...@@ -49,12 +37,7 @@ using std::filesystem::path; ...@@ -49,12 +37,7 @@ using std::filesystem::path;
/** /**
* @brief Get the name of the enum value. May be useful for higher-order CaosDB clients. * @brief Get the name of the enum value. May be useful for higher-order CaosDB clients.
*/ */
template <typename Enum> auto getEnumNameFromValue(Enum v) -> std::string { template <typename Enum> auto getEnumNameFromValue(Enum v) -> std::string;
if (std::is_same_v<std::underlying_type_t<Enum>, int>) {
return boost::lexical_cast<std::string>(static_cast<int>(v));
}
throw std::logic_error(std::string("Enum type ") + typeid(v).name() + " not implemented.");
}
// Forward declaration of specializations // Forward declaration of specializations
template <> template <>
...@@ -84,11 +67,7 @@ auto getEnumValueFromName<caosdb::entity::Role>(const std::string &name) -> caos ...@@ -84,11 +67,7 @@ auto getEnumValueFromName<caosdb::entity::Role>(const std::string &name) -> caos
/** /**
* @brief Read a text file into a string and return the file's content. * @brief Read a text file into a string and return the file's content.
*/ */
inline auto load_string_file(const path &file_path) -> std::string { auto load_string_file(const path &file_path) -> std::string;
std::string result;
boost::filesystem::load_string_file(file_path.string(), result);
return result;
}
/** /**
* @brief Return the environment variable KEY, or FALLBACK if it does not exist. * @brief Return the environment variable KEY, or FALLBACK if it does not exist.
...@@ -115,37 +94,82 @@ inline auto get_env_fallback(const std::string &key, const std::string &fallback ...@@ -115,37 +94,82 @@ inline auto get_env_fallback(const std::string &key, const std::string &fallback
} }
/** /**
* @brief Encode string as base64 * @brief JsonValue is a thin wrapper around a implementation specific
* third-party json object (e.g. boost).
*/
class JsonValue {
public:
/**
* Default Constructor.
*
* Creates an empty wrapper where `wrapped` is nullptr.
*/
JsonValue() : JsonValue(nullptr) {}
/**
* Constructor.
*
* By calling this constructor the ownership of the `wrapped` parameter is
* transferred to this object.
*/ */
inline auto base64_encode(const std::string &plain) -> std::string { JsonValue(void *wrapped);
auto size_plain = plain.size(); /**
auto size_encoded = boost::beast::detail::base64::encoded_size(size_plain); * Destructor.
*
* Also deletes the `wrapped` object.
*/
~JsonValue();
std::unique_ptr<char[]> encoded(new char[size_encoded]); /**
boost::beast::detail::base64::encode(encoded.get(), plain.c_str(), size_plain); * Copy Constructor.
*
* Also copies the `wrapped` object.
*/
JsonValue(const JsonValue &other);
// the encoded char[] is not null terminated, so explicitely set the length /**
return std::string(encoded.get(), encoded.get() + size_encoded); * Copy Assigment.
} *
* Also copies the `wrapped` object.
*/
auto operator=(const JsonValue &other) -> JsonValue &;
inline auto load_json_file(const path &json_file) -> value { /**
assert(exists(json_file)); * Move Constructor.
*
* Also moves the `wrapped` object.
*/
JsonValue(JsonValue &&other) noexcept;
constexpr auto buffer_size = std::size_t(4096); /**
auto stream = ifstream(json_file); * Move Assigment.
stream.exceptions(std::ios_base::badbit); *
* Also moves the `wrapped` object.
*/
auto operator=(JsonValue &&other) noexcept -> JsonValue &;
stream_parser parser; /**
auto result = std::string(); * Reset this object.
auto buffer = std::string(buffer_size, '\0'); *
while (stream.read(&buffer[0], buffer_size)) { * Also deletes `wrapped` sets it to the nullptr.
parser.write(buffer.c_str(), stream.gcount()); */
} auto Reset() -> void;
parser.write(buffer.c_str(), stream.gcount());
assert(parser.done()); /**
return parser.release(); * An object which represents a JSON value. The object's class is an
} * implementation detail.
*/
std::shared_ptr<void> wrapped;
};
/**
* @brief Load json object from a json file and return it.
*/
auto load_json_file(const path &json_file) -> JsonValue;
/**
* @brief Encode string as base64
*/
auto base64_encode(const std::string &plain) -> std::string;
inline auto get_home_directory() -> const path { inline auto get_home_directory() -> const path {
const auto *const home = getenv("HOME"); const auto *const home = getenv("HOME");
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "caosdb/constants.h" // for LIBCAOSDB_CONF... #include "caosdb/constants.h" // for LIBCAOSDB_CONF...
#include "caosdb/exceptions.h" // for ConfigurationE... #include "caosdb/exceptions.h" // for ConfigurationE...
#include "caosdb/log_level.h" // for CAOSDB_DEFAULT... #include "caosdb/log_level.h" // for CAOSDB_DEFAULT...
#include "caosdb/logging.h" // for SinkConfiguration, Loggin...
#include "caosdb/status_code.h" // for StatusCode #include "caosdb/status_code.h" // for StatusCode
#include "caosdb/utility.h" // for get_home_direc... #include "caosdb/utility.h" // for get_home_direc...
#include <boost/json/impl/object.hpp> // for object::at #include <boost/json/impl/object.hpp> // for object::at
...@@ -44,6 +45,30 @@ ...@@ -44,6 +45,30 @@
#include <string> // for string, operator+ #include <string> // for string, operator+
#include <utility> // for move #include <utility> // for move
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define WRAPPED_JSON_CONFIGURATION(obj) \
(static_cast<value *>((obj)->json_configuration.wrapped.get()))
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define GET_CONNECTIONS \
if (!this->json_configuration.wrapped) { \
throw ConfigurationError("This CaosDB client has not been configured."); \
} \
assert(WRAPPED_JSON_CONFIGURATION(this)->is_object()); \
const auto &configuration = WRAPPED_JSON_CONFIGURATION(this)->as_object(); \
if (!configuration.contains("connections")) { \
throw ConfigurationError("This CaosDB client hasn't any configured connections."); \
} \
const auto &connections_value = configuration.at("connections"); \
if (connections_value.is_null()) { \
throw ConfigurationError("This CaosDB client hasn't any configured connections."); \
} \
assert(connections_value.is_object()); \
const auto &connections = connections_value.as_object(); \
if (connections.empty()) { \
throw ConfigurationError("This CaosDB client hasn't any configured connections."); \
}
namespace caosdb::configuration { namespace caosdb::configuration {
using boost::json::object; using boost::json::object;
using boost::json::value; using boost::json::value;
...@@ -151,8 +176,7 @@ auto TlsConnectionConfiguration::ToString() const -> std::string { ...@@ -151,8 +176,7 @@ auto TlsConnectionConfiguration::ToString() const -> std::string {
"," + this->certificate_provider + ")"; "," + this->certificate_provider + ")";
} }
auto ConnectionConfigurationHelper::CreateCertificateProvider(const object &from) const auto CreateCertificateProvider(const object &from) -> std::unique_ptr<CertificateProvider> {
-> std::unique_ptr<CertificateProvider> {
std::unique_ptr<CertificateProvider> certificate_provider; std::unique_ptr<CertificateProvider> certificate_provider;
if (from.contains("server_certificate_path")) { if (from.contains("server_certificate_path")) {
const value &path_str = from.at("server_certificate_path"); const value &path_str = from.at("server_certificate_path");
...@@ -168,8 +192,7 @@ auto ConnectionConfigurationHelper::CreateCertificateProvider(const object &from ...@@ -168,8 +192,7 @@ auto ConnectionConfigurationHelper::CreateCertificateProvider(const object &from
return certificate_provider; return certificate_provider;
} }
auto ConnectionConfigurationHelper::CreateAuthenticator(const object &from) const auto CreateAuthenticator(const object &from) -> std::unique_ptr<Authenticator> {
-> std::unique_ptr<Authenticator> {
std::unique_ptr<Authenticator> authenticator; std::unique_ptr<Authenticator> authenticator;
if (from.contains("authentication")) { if (from.contains("authentication")) {
assert(from.at("authentication").is_object()); assert(from.at("authentication").is_object());
...@@ -197,9 +220,9 @@ auto ConnectionConfigurationHelper::CreateAuthenticator(const object &from) cons ...@@ -197,9 +220,9 @@ auto ConnectionConfigurationHelper::CreateAuthenticator(const object &from) cons
return authenticator; return authenticator;
} }
auto ConnectionConfigurationHelper::CreateConnectionConfiguration( auto CreateConnectionConfiguration(const bool tls, const std::string &host, const int port,
const bool tls, const std::string &host, const int port, const CertificateProvider *certificate_provider,
const CertificateProvider *certificate_provider, const Authenticator *authenticator) const const Authenticator *authenticator)
-> std::unique_ptr<ConnectionConfiguration> { -> std::unique_ptr<ConnectionConfiguration> {
if (tls) { if (tls) {
if (certificate_provider != nullptr && authenticator != nullptr) { if (certificate_provider != nullptr && authenticator != nullptr) {
...@@ -220,7 +243,7 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration( ...@@ -220,7 +243,7 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration(
} }
} }
auto ConnectionConfigurationHelper::IsTls(const object &from) const -> bool { auto IsTls(const object &from) -> bool {
bool tls = true; bool tls = true;
if (from.contains("tls")) { if (from.contains("tls")) {
auto tls_switch = from.at("tls"); auto tls_switch = from.at("tls");
...@@ -230,8 +253,7 @@ auto ConnectionConfigurationHelper::IsTls(const object &from) const -> bool { ...@@ -230,8 +253,7 @@ auto ConnectionConfigurationHelper::IsTls(const object &from) const -> bool {
return tls; return tls;
} }
auto ConnectionConfigurationHelper::CreateConnectionConfiguration(const object &from) const auto CreateConnectionConfiguration(const object &from) -> std::unique_ptr<ConnectionConfiguration> {
-> std::unique_ptr<ConnectionConfiguration> {
assert(from.contains("host")); assert(from.contains("host"));
const auto &host = from.at("host"); const auto &host = from.at("host");
assert(host.is_string()); assert(host.is_string());
...@@ -251,25 +273,19 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration(const object & ...@@ -251,25 +273,19 @@ auto ConnectionConfigurationHelper::CreateConnectionConfiguration(const object &
certificate_provider.get(), authenticator.get()); certificate_provider.get(), authenticator.get());
} }
auto LoggingConfigurationHelper::CreateConsoleSinkConfiguration(const object & /*from*/, auto CreateConsoleSinkConfiguration(const object & /*from*/, const std::string &name, int level)
const std::string &name,
int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration> { -> std::shared_ptr<caosdb::logging::SinkConfiguration> {
auto result = std::make_shared<ConsoleSinkConfiguration>(name, level); auto result = std::make_shared<ConsoleSinkConfiguration>(name, level);
return result; return result;
} }
auto LoggingConfigurationHelper::CreateSyslogSinkConfiguration(const object & /*from*/, auto CreateSyslogSinkConfiguration(const object & /*from*/, const std::string &name, int level)
const std::string &name,
int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration> { -> std::shared_ptr<caosdb::logging::SinkConfiguration> {
auto result = std::make_shared<SyslogSinkConfiguration>(name, level); auto result = std::make_shared<SyslogSinkConfiguration>(name, level);
return result; return result;
} }
auto LoggingConfigurationHelper::CreateFileSinkConfiguration(const object &from, auto CreateFileSinkConfiguration(const object &from, const std::string &name, int level)
const std::string &name,
int level) const
-> std::shared_ptr<caosdb::logging::SinkConfiguration> { -> std::shared_ptr<caosdb::logging::SinkConfiguration> {
auto result = std::make_shared<FileSinkConfiguration>(name, level); auto result = std::make_shared<FileSinkConfiguration>(name, level);
if (from.contains("directory")) { if (from.contains("directory")) {
...@@ -278,9 +294,21 @@ auto LoggingConfigurationHelper::CreateFileSinkConfiguration(const object &from, ...@@ -278,9 +294,21 @@ auto LoggingConfigurationHelper::CreateFileSinkConfiguration(const object &from,
return result; return result;
} }
auto LoggingConfigurationHelper::CreateSinkConfiguration(const object &from, auto ConvertLogLevel(const std::string &string_level) -> int {
const std::string &name, static std::map<std::string, int> log_level_names = {
int default_level) const {"", CAOSDB_DEFAULT_LOG_LEVEL}, {"off", CAOSDB_LOG_LEVEL_OFF},
{"fatal", CAOSDB_LOG_LEVEL_FATAL}, {"error", CAOSDB_LOG_LEVEL_ERROR},
{"warn", CAOSDB_LOG_LEVEL_WARN}, {"info", CAOSDB_LOG_LEVEL_INFO},
{"debug", CAOSDB_LOG_LEVEL_DEBUG}, {"trace", CAOSDB_LOG_LEVEL_TRACE},
{"all", CAOSDB_LOG_LEVEL_ALL}};
try {
return log_level_names.at(string_level);
} catch (const std::out_of_range &exc) {
throw ConfigurationError("Unknown log level: " + string_level);
}
}
auto CreateSinkConfiguration(const object &from, const std::string &name, int default_level)
-> std::shared_ptr<caosdb::logging::SinkConfiguration> { -> std::shared_ptr<caosdb::logging::SinkConfiguration> {
assert(from.contains("destination")); assert(from.contains("destination"));
const auto &destination = std::string(from.at("destination").as_string().c_str()); const auto &destination = std::string(from.at("destination").as_string().c_str());
...@@ -299,22 +327,7 @@ auto LoggingConfigurationHelper::CreateSinkConfiguration(const object &from, ...@@ -299,22 +327,7 @@ auto LoggingConfigurationHelper::CreateSinkConfiguration(const object &from,
} }
} }
auto LoggingConfigurationHelper::ConvertLogLevel(const std::string &string_level) const -> int { auto CreateLoggingConfiguration(const object &from) -> LoggingConfiguration {
static std::map<std::string, int> log_level_names = {
{"", CAOSDB_DEFAULT_LOG_LEVEL}, {"off", CAOSDB_LOG_LEVEL_OFF},
{"fatal", CAOSDB_LOG_LEVEL_FATAL}, {"error", CAOSDB_LOG_LEVEL_ERROR},
{"warn", CAOSDB_LOG_LEVEL_WARN}, {"info", CAOSDB_LOG_LEVEL_INFO},
{"debug", CAOSDB_LOG_LEVEL_DEBUG}, {"trace", CAOSDB_LOG_LEVEL_TRACE},
{"all", CAOSDB_LOG_LEVEL_ALL}};
try {
return log_level_names.at(string_level);
} catch (const std::out_of_range &exc) {
throw ConfigurationError("Unknown log level: " + string_level);
}
}
auto LoggingConfigurationHelper::CreateLoggingConfiguration(const object &from) const
-> LoggingConfiguration {
auto default_level_str = auto default_level_str =
from.contains("level") ? std::string(from.at("level").as_string().c_str()) : ""; from.contains("level") ? std::string(from.at("level").as_string().c_str()) : "";
int default_level = ConvertLogLevel(default_level_str); int default_level = ConvertLogLevel(default_level_str);
...@@ -356,7 +369,7 @@ auto ConfigurationManager::mReset() noexcept -> int { ...@@ -356,7 +369,7 @@ auto ConfigurationManager::mReset() noexcept -> int {
auto ConfigurationManager::mClear() noexcept -> int { auto ConfigurationManager::mClear() noexcept -> int {
try { try {
json_configuration = value(nullptr); json_configuration.Reset();
ConnectionManager::Reset(); ConnectionManager::Reset();
return StatusCode::SUCCESS; return StatusCode::SUCCESS;
} catch (const caosdb::exceptions::Exception &exc) { } catch (const caosdb::exceptions::Exception &exc) {
...@@ -369,7 +382,7 @@ auto ConfigurationManager::mClear() noexcept -> int { ...@@ -369,7 +382,7 @@ auto ConfigurationManager::mClear() noexcept -> int {
} }
auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) -> void { auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) -> void {
if (!json_configuration.is_null()) { if (json_configuration.wrapped) {
throw ConfigurationError("This CaosDB client has already been configured."); throw ConfigurationError("This CaosDB client has already been configured.");
} }
if (!exists(json_file)) { if (!exists(json_file)) {
...@@ -381,12 +394,17 @@ auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) - ...@@ -381,12 +394,17 @@ auto ConfigurationManager::mLoadSingleJSONConfiguration(const path &json_file) -
auto ConfigurationManager::mGetConnectionConfiguration(const std::string &name) const auto ConfigurationManager::mGetConnectionConfiguration(const std::string &name) const
-> std::unique_ptr<ConnectionConfiguration> { -> std::unique_ptr<ConnectionConfiguration> {
auto connection_json = GetConnection(name); GET_CONNECTIONS
return connection_configuration_helper.CreateConnectionConfiguration(connection_json); if (connections.contains(name)) {
const auto &result_connection = connections.at(name);
assert(result_connection.is_object());
return CreateConnectionConfiguration(result_connection.as_object());
}
throw ConfigurationError("The connection '" + name + "' has not been defined.");
} }
auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string { auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string {
auto connections = GetConnections(); GET_CONNECTIONS
if (connections.contains("default")) { if (connections.contains("default")) {
auto default_connection = connections.at("default"); auto default_connection = connections.at("default");
if (default_connection.is_object()) { if (default_connection.is_object()) {
...@@ -406,41 +424,6 @@ auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string { ...@@ -406,41 +424,6 @@ auto ConfigurationManager::mGetDefaultConnectionName() const -> std::string {
throw ConfigurationError("Could not determine the default connection."); throw ConfigurationError("Could not determine the default connection.");
} }
auto ConfigurationManager::GetConfiguration() const -> const object & {
if (json_configuration.is_null()) {
throw ConfigurationError("This CaosDB client has not been configured.");
}
assert(json_configuration.is_object());
return json_configuration.as_object();
}
auto ConfigurationManager::GetConnections() const -> const object & {
const auto &configuration = GetConfiguration();
if (!configuration.contains("connections")) {
throw ConfigurationError("This CaosDB client hasn't any configured connections.");
}
const auto &connections_value = configuration.at("connections");
if (connections_value.is_null()) {
throw ConfigurationError("This CaosDB client hasn't any configured connections.");
}
assert(connections_value.is_object());
const auto &connections_object = connections_value.as_object();
if (connections_object.empty()) {
throw ConfigurationError("This CaosDB client hasn't any configured connections.");
}
return connections_object;
}
auto ConfigurationManager::GetConnection(const std::string &name) const -> const object & {
const auto &connections = GetConnections();
if (connections.contains(name)) {
const auto &result_connection = connections.at(name);
assert(result_connection.is_object());
return result_connection.as_object();
}
throw ConfigurationError("The connection '" + name + "' has not been defined.");
}
// TODO(tf) This has apparently a cognitive complexity of 34>25 (threshold). // TODO(tf) This has apparently a cognitive complexity of 34>25 (threshold).
auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT
...@@ -488,11 +471,10 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT ...@@ -488,11 +471,10 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT
} }
// Logging in the configuration leads to additional content. // Logging in the configuration leads to additional content.
if (this->json_configuration.is_object() && if (this->json_configuration.wrapped && WRAPPED_JSON_CONFIGURATION(this)->is_object() &&
this->json_configuration.as_object().contains("logging")) { WRAPPED_JSON_CONFIGURATION(this)->as_object().contains("logging")) {
LoggingConfiguration logging_configuration = LoggingConfiguration logging_configuration =
logging_configuration_helper.CreateLoggingConfiguration( CreateLoggingConfiguration(WRAPPED_JSON_CONFIGURATION(this)->at("logging").as_object());
json_configuration.at("logging").as_object());
logging::initialize_logging(logging_configuration); logging::initialize_logging(logging_configuration);
} else { } else {
logging::initialize_logging_defaults(); logging::initialize_logging_defaults();
...@@ -500,7 +482,8 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT ...@@ -500,7 +482,8 @@ auto ConfigurationManager::InitializeDefaults() -> int { // NOLINT
"We are using the default configuration"; "We are using the default configuration";
} }
if (configuration_file_path != nullptr && this->json_configuration.is_object()) { if (configuration_file_path != nullptr && this->json_configuration.wrapped &&
WRAPPED_JSON_CONFIGURATION(this)->is_object()) {
CAOSDB_LOG_INFO(logger_name) << "Loaded configuration from " << *(configuration_file_path) CAOSDB_LOG_INFO(logger_name) << "Loaded configuration from " << *(configuration_file_path)
<< "."; << ".";
} }
......
...@@ -21,16 +21,33 @@ ...@@ -21,16 +21,33 @@
#include "caosdb/utility.h" #include "caosdb/utility.h"
#include "caosdb/data_type.h" // for AtomicDataType, atomicdatatype_names #include "caosdb/data_type.h" // for AtomicDataType, atomicdatatype_names
#include "caosdb/entity.h" // for Importance, Role, importance_names #include "caosdb/entity.h" // for Importance, Role, importance_names
#include <boost/beast/core/detail/base64.hpp> // for encoded_size
#include <boost/beast/core/detail/base64.ipp> // for encode
#include <boost/filesystem/string_file.hpp> // for load_string_file
#include <boost/json/stream_parser.hpp> // for stream_parser
#include <boost/json/value.hpp> // for value
#include <cassert> // for assert
#include <map> // for map, operator!=, _Rb_tree_const_iterator #include <map> // for map, operator!=, _Rb_tree_const_iterator
#include <memory> // for allocator, unique_ptr
#include <stdexcept> // for logic_error
#include <type_traits> // for underlying_type_t
#include <typeinfo> // for type_info
#include <utility> // for pair #include <utility> // for pair
namespace caosdb::utility { namespace caosdb::utility {
using boost::json::stream_parser;
using boost::json::value;
using caosdb::entity::AtomicDataType; using caosdb::entity::AtomicDataType;
using caosdb::entity::Importance; using caosdb::entity::Importance;
using caosdb::entity::Role; using caosdb::entity::Role;
// using emap = std::map<int, std::string>; // enum mapping template <typename Enum> auto getEnumNameFromValue(Enum v) -> std::string {
if (std::is_same_v<std::underlying_type_t<Enum>, int>) {
return std::to_string(static_cast<int>(v));
}
throw std::logic_error(std::string("Enum type ") + typeid(v).name() + " not implemented.");
}
// Enum helper template specializations ////////////////////////////////////// // Enum helper template specializations //////////////////////////////////////
template <> auto getEnumNameFromValue<Importance>(Importance v) -> std::string { template <> auto getEnumNameFromValue<Importance>(Importance v) -> std::string {
...@@ -87,4 +104,82 @@ template <> auto getEnumValueFromName<Role>(const std::string &name) -> Role { ...@@ -87,4 +104,82 @@ template <> auto getEnumValueFromName<Role>(const std::string &name) -> Role {
// End of template specialization ///////////////////////////////////////////// // End of template specialization /////////////////////////////////////////////
auto load_string_file(const path &file_path) -> std::string {
std::string result;
boost::filesystem::load_string_file(file_path.string(), result);
return result;
}
auto base64_encode(const std::string &plain) -> std::string {
auto size_plain = plain.size();
auto size_encoded = boost::beast::detail::base64::encoded_size(size_plain);
std::string result = std::string(size_encoded, '\0');
boost::beast::detail::base64::encode(&result[0], plain.c_str(), size_plain);
return result;
}
auto _load_json_file(const path &json_file) -> value {
assert(exists(json_file));
constexpr auto buffer_size = std::size_t(4096);
auto stream = ifstream(json_file);
stream.exceptions(std::ios_base::badbit);
stream_parser parser;
auto result = std::string();
auto buffer = std::string(buffer_size, '\0');
while (stream.read(&buffer[0], buffer_size)) {
parser.write(buffer.c_str(), stream.gcount());
}
parser.write(buffer.c_str(), stream.gcount());
assert(parser.done());
return parser.release();
}
auto load_json_file(const path &json_file) -> JsonValue {
return {new value(_load_json_file(json_file))};
}
JsonValue::JsonValue(void *wrapped) { this->wrapped.reset(static_cast<value *>(wrapped)); }
JsonValue::~JsonValue() = default;
auto JsonValue::Reset() -> void {
if (this->wrapped) {
this->wrapped.reset();
}
}
JsonValue::JsonValue(const JsonValue &other) {
if (other.wrapped) {
this->wrapped.reset(static_cast<value *>(other.wrapped.get()));
}
}
auto JsonValue::operator=(const JsonValue &other) -> JsonValue & {
if (this != &other) {
if (other.wrapped) {
this->wrapped = std::make_shared<value>(*(static_cast<value *>(other.wrapped.get())));
}
}
return *this;
}
JsonValue::JsonValue(JsonValue &&other) noexcept {
if (other.wrapped) {
this->wrapped = std::move(other.wrapped);
}
}
auto JsonValue::operator=(JsonValue &&other) noexcept -> JsonValue & {
if (this != &other) {
Reset();
this->wrapped = std::move(other.wrapped);
}
return *this;
}
} // namespace caosdb::utility } // namespace caosdb::utility
...@@ -20,10 +20,7 @@ ...@@ -20,10 +20,7 @@
* *
*/ */
#include "gmock/gmock-matchers.h" // for ElementsAre, EXPECT_THAT
#include "boost/beast/core/detail/base64.hpp" // for encoded_size #include "boost/beast/core/detail/base64.hpp" // for encoded_size
#include "boost/json/object.hpp" // for object
#include "boost/json/value.hpp" // for value
#include "caosdb/data_type.h" // for atomicdatatype_names #include "caosdb/data_type.h" // for atomicdatatype_names
#include "caosdb/entity.h" // for importance_names, role... #include "caosdb/entity.h" // for importance_names, role...
#include "caosdb/status_code.h" // for get_status_description #include "caosdb/status_code.h" // for get_status_description
...@@ -38,7 +35,6 @@ ...@@ -38,7 +35,6 @@
#include <utility> // for pair #include <utility> // for pair
namespace caosdb::utility { namespace caosdb::utility {
using ::testing::ElementsAre;
TEST(test_utility, base64_encode) { TEST(test_utility, base64_encode) {
auto test_plain = std::string("admin:caosdb"); auto test_plain = std::string("admin:caosdb");
...@@ -48,17 +44,6 @@ TEST(test_utility, base64_encode) { ...@@ -48,17 +44,6 @@ TEST(test_utility, base64_encode) {
EXPECT_EQ(test_encoded, base64_encode(test_plain)); EXPECT_EQ(test_encoded, base64_encode(test_plain));
} }
TEST(test_utility, test_load_json_file) {
auto json = load_json_file(TEST_DATA_DIR + "/test.json").as_object();
EXPECT_EQ(json["it"], "tests");
EXPECT_EQ(json["null values"], nullptr);
EXPECT_THAT(json["this"].as_array(), ElementsAre("is", "a", "test"));
EXPECT_THAT(json["numbers"].as_array(), ElementsAre(1, 2, 3.3));
auto sub = json["arrays and objects"].as_object();
EXPECT_THAT(sub["see?"].as_array(), ElementsAre(true, false));
}
TEST(test_utility, enum_names) { TEST(test_utility, enum_names) {
// All working enums // All working enums
for (const auto &entry : caosdb::entity::importance_names) { for (const auto &entry : caosdb::entity::importance_names) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment