CMakeLists.txt: requires C++23 standard
CMakeLists.txt: add compiler version checks adc_netserver.h: add AdcTrivialLogger class (use of 'deduced this' feature of C++23 standard); AdcGenericNetServer class now has basic based on std::basic_ostream logging capability
This commit is contained in:
parent
afa8d09ade
commit
6acc1f94ba
@ -4,10 +4,31 @@ project(ADC LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
# set(CMAKE_BUILD_TYPE Release)
|
||||
|
||||
#
|
||||
# check compiler version to ensure supporting of
|
||||
# 'deducing this' C++23 feature
|
||||
#
|
||||
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0)
|
||||
message(FATAL_ERROR "GCC version must be at least 14.0!")
|
||||
endif()
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0)
|
||||
message(FATAL_ERROR "Clang version must be at least 18.0!")
|
||||
endif()
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.32")
|
||||
message(FATAL_ERROR "MSVC version must be at least 19.32")
|
||||
endif()
|
||||
else()
|
||||
message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang and GCC.")
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
set(ADC_COMMON_HEADERS
|
||||
common/adc_traits.h
|
||||
@ -29,7 +50,7 @@ set(ADC_NETWORK_HEADERS
|
||||
# net/adc_netmsg.h
|
||||
# net/adc_netmessage.h
|
||||
net/adc_netproto.h
|
||||
net/adc_netservice.h
|
||||
# net/adc_netservice.h
|
||||
net/adc_endpoint.h
|
||||
net/adc_netserver.h
|
||||
net/adc_net_concepts.h
|
||||
|
||||
@ -246,9 +246,11 @@ public:
|
||||
_netService.asyncReceive(
|
||||
[self, this](netservice_t::async_callback_err_t ec, message_t msg) {
|
||||
if (ec) {
|
||||
std::string str("asyncReceive operation completed with error: ");
|
||||
netservice_t::formatError(ec, str);
|
||||
_serverPtr->errorMessage(str);
|
||||
// std::string str("asyncReceive operation completed with error: ");
|
||||
// netservice_t::formatError(ec, str);
|
||||
// _serverPtr->errorMessage(str);
|
||||
_serverPtr->logError("asyncReceive operation completed with error: {}",
|
||||
netservice_t::formattableError(ec));
|
||||
stop();
|
||||
} else {
|
||||
auto msg_sptr = std::make_shared<message_t>(std::move(msg));
|
||||
@ -261,9 +263,11 @@ public:
|
||||
*msg_sptr,
|
||||
[self, msg_sptr, this](netservice_t::async_callback_err_t ec) {
|
||||
if (ec) {
|
||||
std::string str("asyncSend operation completed with error: ");
|
||||
netservice_t::formatError(ec, str);
|
||||
_serverPtr->errorMessage(str);
|
||||
// std::string str("asyncSend operation completed with error: ");
|
||||
// netservice_t::formatError(ec, str);
|
||||
// _serverPtr->errorMessage(str);
|
||||
_serverPtr->logError("asyncSend operation completed with error: {}",
|
||||
netservice_t::formattableError(ec));
|
||||
stop();
|
||||
} else {
|
||||
start();
|
||||
|
||||
@ -160,8 +160,11 @@ concept adc_netservice_c = requires(SRVT srv, const SRVT srv_const) {
|
||||
|
||||
srv.close();
|
||||
|
||||
// static method
|
||||
SRVT::formatError(std::declval<typename SRVT::async_callback_err_t>(), std::declval<std::string&>());
|
||||
// // static method
|
||||
// SRVT::formatError(std::declval<typename SRVT::async_callback_err_t>(), std::declval<std::string&>());
|
||||
|
||||
// convert given error to formattable (valid input to std::format) representation
|
||||
{ SRVT::formattableError(std::declval<typename SRVT::async_callback_err_t>()) } -> traits::formattable;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
@ -28,7 +29,87 @@ namespace adc
|
||||
|
||||
/* SOME USEFULL PRIVITIVES */
|
||||
|
||||
// Ageneric implementation pf POSIX OS daemon
|
||||
|
||||
// A simple std::ostream logger
|
||||
class AdcTrivialLogger
|
||||
{
|
||||
public:
|
||||
virtual ~AdcTrivialLogger() = default;
|
||||
|
||||
protected:
|
||||
static constexpr std::string_view errorLevelMark{"error"};
|
||||
static constexpr std::string_view warnLevelMark{"warning"};
|
||||
static constexpr std::string_view infoLevelMark{"info"};
|
||||
|
||||
std::basic_ostream<char>& _stream;
|
||||
|
||||
AdcTrivialLogger(std::basic_ostream<char>& stream = std::cout) : _stream(stream) {}
|
||||
|
||||
template <traits::formattable... ArgTs>
|
||||
std::string logMsgFormat(std::string_view level_mark, std::string_view fmt, ArgTs&&... args)
|
||||
{
|
||||
std::string s;
|
||||
std::format_to(std::back_inserter(s), fmt, std::forward<ArgTs>(args)...);
|
||||
|
||||
std::stringstream st;
|
||||
|
||||
const std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
|
||||
// format log-message in form:
|
||||
// [YYYY-MM-DD HH:MM:SS][level] log-message
|
||||
//
|
||||
st << std::put_time(std::localtime(&now), "[%F %T]") << "[" << level_mark << "] " << s;
|
||||
|
||||
return st.str();
|
||||
}
|
||||
|
||||
|
||||
// define default logging function of ERROR, WARNING and INFO levels
|
||||
template <traits::formattable... ArgTs>
|
||||
void logError(this auto&& self, std::string_view fmt, ArgTs&&... args)
|
||||
{
|
||||
using obj_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<std::remove_cvref_t<obj_t>, AdcTrivialLogger>) {
|
||||
std::forward<obj_t>(self)._stream
|
||||
<< std::forward<obj_t>(self).logMsgFormat(errorLevelMark, fmt, std::forward<ArgTs>(args)...) << "\n"
|
||||
<< std::flush;
|
||||
} else {
|
||||
std::forward<obj_t>(self).logError(fmt, std::forward<ArgTs>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::formattable... ArgTs>
|
||||
void logWarn(this auto&& self, std::string_view fmt, ArgTs&&... args)
|
||||
{
|
||||
using obj_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<obj_t, AdcTrivialLogger>) {
|
||||
std::forward<obj_t>(self)._stream
|
||||
<< std::forward<obj_t>(self).logMsgFormat(warnLevelMark, fmt, std::forward<ArgTs>(args)...) << "\n"
|
||||
<< std::flush;
|
||||
} else {
|
||||
std::forward<obj_t>(self).logWarn(fmt, std::forward<ArgTs>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <traits::formattable... ArgTs>
|
||||
void logInfo(this auto&& self, std::string_view fmt, ArgTs&&... args)
|
||||
{
|
||||
using obj_t = decltype(self);
|
||||
|
||||
if constexpr (std::same_as<obj_t, AdcTrivialLogger>) {
|
||||
std::forward<obj_t>(self)._stream
|
||||
<< std::forward<obj_t>(self).logMsgFormat(infoLevelMark, fmt, std::forward<ArgTs>(args)...) << "\n"
|
||||
<< std::flush;
|
||||
} else {
|
||||
std::forward<obj_t>(self).logInfo(fmt, std::forward<ArgTs>(args)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A generic implementation of POSIX OS daemon
|
||||
class AdcPosixGenericDaemon
|
||||
{
|
||||
public:
|
||||
@ -224,12 +305,15 @@ protected:
|
||||
/* very generic network server */
|
||||
|
||||
template <typename IdentT = std::string>
|
||||
class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager
|
||||
class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager, public AdcTrivialLogger
|
||||
{
|
||||
public:
|
||||
typedef IdentT server_ident_t;
|
||||
|
||||
AdcGenericNetServer(const server_ident_t& id) : _serverIdent(id) {}
|
||||
AdcGenericNetServer(const server_ident_t& id, std::basic_ostream<char>& log_stream = std::cout)
|
||||
: AdcTrivialLogger(log_stream), _serverIdent(id)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AdcGenericNetServer(const AdcGenericNetServer&) = delete;
|
||||
@ -353,16 +437,18 @@ protected:
|
||||
_isListening<SessionT>[this][id] = true;
|
||||
doAccept<SessionT>(acceptor, std::move(id), std::move(sess_ctx));
|
||||
} else {
|
||||
std::string str{"Cannot start accepting connection: "};
|
||||
SessionT::netservice_t::formatError(ec, str);
|
||||
errorMessage(str);
|
||||
// std::string str{"Cannot start accepting connection: "};
|
||||
// SessionT::netservice_t::formatError(ec, str);
|
||||
// errorMessage(str);
|
||||
|
||||
this->logError("Cannot start accepting connection: {}", SessionT::netservice_t::formattableError(ec));
|
||||
|
||||
_isListening<SessionT>[this][id] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
virtual void errorMessage(const std::string&) {};
|
||||
// virtual void errorMessage(const std::string&) {};
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -758,10 +758,19 @@ public:
|
||||
}
|
||||
|
||||
|
||||
static void formatError(std::error_code err, std::string& result_str)
|
||||
// static void formatError(std::error_code err, std::string& result_str)
|
||||
// {
|
||||
// std::format_to(std::back_inserter(result_str), "{} (Err category: {}) (Err msg: {})", err.value(),
|
||||
// err.category().name(), err.message());
|
||||
// }
|
||||
|
||||
static std::string formattableError(std::error_code ec)
|
||||
{
|
||||
std::format_to(std::back_inserter(result_str), "{} (Err category: {}) (Err msg: {})", err.value(),
|
||||
err.category().name(), err.message());
|
||||
std::string s;
|
||||
std::format_to(std::back_inserter(s), "{} (Err category: {}) (Err msg: {})", ec.value(), ec.category().name(),
|
||||
ec.message());
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user