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_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_CXX_STANDARD_REQUIRED ON)
|
||||||
# set(CMAKE_BUILD_TYPE Release)
|
# 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
|
set(ADC_COMMON_HEADERS
|
||||||
common/adc_traits.h
|
common/adc_traits.h
|
||||||
@ -29,7 +50,7 @@ set(ADC_NETWORK_HEADERS
|
|||||||
# net/adc_netmsg.h
|
# net/adc_netmsg.h
|
||||||
# net/adc_netmessage.h
|
# net/adc_netmessage.h
|
||||||
net/adc_netproto.h
|
net/adc_netproto.h
|
||||||
net/adc_netservice.h
|
# net/adc_netservice.h
|
||||||
net/adc_endpoint.h
|
net/adc_endpoint.h
|
||||||
net/adc_netserver.h
|
net/adc_netserver.h
|
||||||
net/adc_net_concepts.h
|
net/adc_net_concepts.h
|
||||||
|
|||||||
@ -246,9 +246,11 @@ public:
|
|||||||
_netService.asyncReceive(
|
_netService.asyncReceive(
|
||||||
[self, this](netservice_t::async_callback_err_t ec, message_t msg) {
|
[self, this](netservice_t::async_callback_err_t ec, message_t msg) {
|
||||||
if (ec) {
|
if (ec) {
|
||||||
std::string str("asyncReceive operation completed with error: ");
|
// std::string str("asyncReceive operation completed with error: ");
|
||||||
netservice_t::formatError(ec, str);
|
// netservice_t::formatError(ec, str);
|
||||||
_serverPtr->errorMessage(str);
|
// _serverPtr->errorMessage(str);
|
||||||
|
_serverPtr->logError("asyncReceive operation completed with error: {}",
|
||||||
|
netservice_t::formattableError(ec));
|
||||||
stop();
|
stop();
|
||||||
} else {
|
} else {
|
||||||
auto msg_sptr = std::make_shared<message_t>(std::move(msg));
|
auto msg_sptr = std::make_shared<message_t>(std::move(msg));
|
||||||
@ -261,9 +263,11 @@ public:
|
|||||||
*msg_sptr,
|
*msg_sptr,
|
||||||
[self, msg_sptr, this](netservice_t::async_callback_err_t ec) {
|
[self, msg_sptr, this](netservice_t::async_callback_err_t ec) {
|
||||||
if (ec) {
|
if (ec) {
|
||||||
std::string str("asyncSend operation completed with error: ");
|
// std::string str("asyncSend operation completed with error: ");
|
||||||
netservice_t::formatError(ec, str);
|
// netservice_t::formatError(ec, str);
|
||||||
_serverPtr->errorMessage(str);
|
// _serverPtr->errorMessage(str);
|
||||||
|
_serverPtr->logError("asyncSend operation completed with error: {}",
|
||||||
|
netservice_t::formattableError(ec));
|
||||||
stop();
|
stop();
|
||||||
} else {
|
} else {
|
||||||
start();
|
start();
|
||||||
|
|||||||
@ -160,8 +160,11 @@ concept adc_netservice_c = requires(SRVT srv, const SRVT srv_const) {
|
|||||||
|
|
||||||
srv.close();
|
srv.close();
|
||||||
|
|
||||||
// static method
|
// // static method
|
||||||
SRVT::formatError(std::declval<typename SRVT::async_callback_err_t>(), std::declval<std::string&>());
|
// 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 <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -28,7 +29,87 @@ namespace adc
|
|||||||
|
|
||||||
/* SOME USEFULL PRIVITIVES */
|
/* 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
|
class AdcPosixGenericDaemon
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -224,12 +305,15 @@ protected:
|
|||||||
/* very generic network server */
|
/* very generic network server */
|
||||||
|
|
||||||
template <typename IdentT = std::string>
|
template <typename IdentT = std::string>
|
||||||
class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager
|
class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager, public AdcTrivialLogger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef IdentT server_ident_t;
|
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;
|
AdcGenericNetServer(const AdcGenericNetServer&) = delete;
|
||||||
@ -353,16 +437,18 @@ protected:
|
|||||||
_isListening<SessionT>[this][id] = true;
|
_isListening<SessionT>[this][id] = true;
|
||||||
doAccept<SessionT>(acceptor, std::move(id), std::move(sess_ctx));
|
doAccept<SessionT>(acceptor, std::move(id), std::move(sess_ctx));
|
||||||
} else {
|
} else {
|
||||||
std::string str{"Cannot start accepting connection: "};
|
// std::string str{"Cannot start accepting connection: "};
|
||||||
SessionT::netservice_t::formatError(ec, str);
|
// SessionT::netservice_t::formatError(ec, str);
|
||||||
errorMessage(str);
|
// errorMessage(str);
|
||||||
|
|
||||||
|
this->logError("Cannot start accepting connection: {}", SessionT::netservice_t::formattableError(ec));
|
||||||
|
|
||||||
_isListening<SessionT>[this][id] = false;
|
_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(),
|
std::string s;
|
||||||
err.category().name(), err.message());
|
std::format_to(std::back_inserter(s), "{} (Err category: {}) (Err msg: {})", ec.value(), ec.category().name(),
|
||||||
|
ec.message());
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user