...
This commit is contained in:
parent
1caf4223d2
commit
06959e8746
@ -27,7 +27,7 @@ set(ADC_NETWORK_HEADERS
|
||||
# net/adc_netmessage.h
|
||||
net/adc_netproto.h
|
||||
net/adc_netservice.h
|
||||
net/adc_url.h
|
||||
net/adc_endpoint.h
|
||||
)
|
||||
|
||||
option(BUILD_TESTS "Build tests" ON)
|
||||
|
||||
359
net/adc_endpoint.h
Normal file
359
net/adc_endpoint.h
Normal file
@ -0,0 +1,359 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../common/adc_traits.h"
|
||||
|
||||
namespace adc
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
* Very simple various protocols endpoint parser and holder class
|
||||
*
|
||||
* endpoint: proto_mark://host_name:port_num/path
|
||||
* where "part" is optional for all protocol kinds;
|
||||
*
|
||||
* for "local" kind protocol the endpoint string must consists of
|
||||
* only "proto_mark" and "host_name" fields
|
||||
* (e.g.: local://APP_UNIX_SOCKET)
|
||||
*
|
||||
*/
|
||||
|
||||
class AdcEndpoint
|
||||
{
|
||||
protected:
|
||||
static constexpr std::string_view protoHostDelim = "://";
|
||||
static constexpr std::string_view hostPortDelim = ":";
|
||||
static constexpr std::string_view portPathDelim = "/";
|
||||
|
||||
public:
|
||||
enum proto_id_t : uint8_t {
|
||||
PROTO_ID_LOCAL,
|
||||
PROTO_ID_TCP,
|
||||
PROTO_ID_TLS,
|
||||
PROTO_ID_UDP,
|
||||
PROTO_ID_WS,
|
||||
PROTO_ID_WSS,
|
||||
PROTO_ID_UNKNOWN
|
||||
};
|
||||
|
||||
static constexpr std::string_view protoMarkLocal{"local"}; // UNIX domain
|
||||
static constexpr std::string_view protoMarkTCP{"tcp"}; // TCP
|
||||
static constexpr std::string_view protoMarkTLS{"tls"}; // TLS
|
||||
static constexpr std::string_view protoMarkUDP{"udp"}; // UDP
|
||||
static constexpr std::string_view protoMarkWS{"ws"}; // Websocket
|
||||
static constexpr std::string_view protoMarkWSS{"wss"}; // Secure Websocket
|
||||
|
||||
static constexpr std::array validProtoMarks = {protoMarkLocal, protoMarkTCP, protoMarkTLS,
|
||||
protoMarkUDP, protoMarkWS, protoMarkWSS};
|
||||
|
||||
/* Constructors and destructor */
|
||||
|
||||
AdcEndpoint() = default;
|
||||
|
||||
// full-feature constructor
|
||||
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT = std::string_view>
|
||||
AdcEndpoint(proto_id_t proto_id, HT&& host, int port = -1, PTT&& path = PTT()) : AdcEndpoint()
|
||||
{
|
||||
setEndpoint(proto_id, std::forward<HT>(host), port, std::forward<PTT>(path));
|
||||
}
|
||||
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
//
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R endpoint() const
|
||||
{
|
||||
R r;
|
||||
if (!_isValid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (_protoID == PROTO_ID_LOCAL) { // only proto mark, host and its delimiter
|
||||
std::ranges::copy(endpointView | std::views::take(3) | std::views::join, std::back_inserter(r));
|
||||
} else {
|
||||
std::ranges::copy(endpointView | std::views::join, std::back_inserter(r));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string endpoint() const
|
||||
{
|
||||
//
|
||||
return endpoint<std::string>();
|
||||
}
|
||||
|
||||
|
||||
template <traits::adc_char_view R>
|
||||
R proto() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return R();
|
||||
}
|
||||
|
||||
const auto& proto = validProtoMarks[_protoID];
|
||||
return R{proto.begin(), proto.end()};
|
||||
}
|
||||
|
||||
|
||||
std::string_view proto() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
return validProtoMarks[_protoID];
|
||||
}
|
||||
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R host() const
|
||||
{
|
||||
R r;
|
||||
if (!_isValid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ranges::copy(_host, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template <traits::adc_char_view R>
|
||||
R hostView() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return R();
|
||||
}
|
||||
|
||||
return R{_host.begin(), _host.end()};
|
||||
}
|
||||
|
||||
std::string host() const
|
||||
{
|
||||
//
|
||||
return _host;
|
||||
}
|
||||
|
||||
std::string_view hostView() const
|
||||
{
|
||||
//
|
||||
return std::string_view{_host.begin(), _host.end()};
|
||||
}
|
||||
|
||||
|
||||
int port() const
|
||||
{
|
||||
//
|
||||
return _isValid ? _port : -1;
|
||||
}
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R path() const
|
||||
{
|
||||
R r;
|
||||
if (!_isValid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ranges::copy(_path, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template <traits::adc_char_view R>
|
||||
R pathView() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return R();
|
||||
}
|
||||
|
||||
return R{_path.begin(), _path.end()};
|
||||
}
|
||||
|
||||
std::string path() const
|
||||
{
|
||||
//
|
||||
return _isValid ? _path : "";
|
||||
}
|
||||
|
||||
std::string_view pathView() const
|
||||
{
|
||||
//
|
||||
return _isValid ? std::string_view{_path.begin(), _path.end()} : std::string_view();
|
||||
}
|
||||
|
||||
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT>
|
||||
bool setEndpoint(proto_id_t proto_id, const HT& host, int port, const PTT& path)
|
||||
{
|
||||
if (!std::distance(std::begin(host), std::end(host))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (proto_id) {
|
||||
case PROTO_ID_LOCAL:
|
||||
// ignore path (always "") and port (just skip)
|
||||
_port = -1;
|
||||
_path.clear();
|
||||
|
||||
break;
|
||||
case PROTO_ID_TCP:
|
||||
case PROTO_ID_TLS:
|
||||
case PROTO_ID_UDP:
|
||||
case PROTO_ID_WS:
|
||||
case PROTO_ID_WSS:
|
||||
if (port <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_port = port;
|
||||
|
||||
_path.clear();
|
||||
std::ranges::copy(path, std::back_inserter(_path));
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_isValid = true;
|
||||
|
||||
_protoID = proto_id;
|
||||
|
||||
_host.clear();
|
||||
std::ranges::copy(host, std::back_inserter(_host));
|
||||
|
||||
updateEndpointView();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
bool setEndpoint(char (&r)[N])
|
||||
{
|
||||
return setEndpoint(std::string_view(r));
|
||||
}
|
||||
|
||||
template <traits::adc_input_char_range R>
|
||||
bool setEndpoint(const R& r)
|
||||
{
|
||||
auto found = std::ranges::search(r, protoHostDelim);
|
||||
|
||||
if (found.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (found.end() == r.end()) { // no host, only delimiter!!!
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sz = std::distance(r.begin(), found.begin());
|
||||
|
||||
std::string proto;
|
||||
std::ranges::copy(r | std::views::take(sz), std::back_inserter(proto));
|
||||
|
||||
std::underlying_type_t<proto_id_t> i = 0;
|
||||
proto_id_t id = PROTO_ID_UNKNOWN;
|
||||
|
||||
for (const auto& el : validProtoMarks) {
|
||||
if (std::ranges::equal(el, proto)) {
|
||||
id = static_cast<proto_id_t>(i);
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if (id == PROTO_ID_UNKNOWN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id == PROTO_ID_LOCAL) { // remaining part is host
|
||||
_protoID = id;
|
||||
_host.clear();
|
||||
std::ranges::copy(r | std::views::drop(sz), std::back_inserter(_host));
|
||||
_path.clear();
|
||||
_port = -1;
|
||||
_isValid = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sz += proto.size();
|
||||
|
||||
found = std::ranges::search(r | std::views::drop(sz), hostPortDelim);
|
||||
|
||||
if (found.empty()) { // no host-to-port delimiter
|
||||
return false;
|
||||
}
|
||||
|
||||
if (found.end() == r.end()) { // the delimiter is at the end!!!
|
||||
return false;
|
||||
}
|
||||
|
||||
auto pos = std::distance(r.begin(), found.begin());
|
||||
if (pos == sz) { // empty host field
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string host;
|
||||
std::ranges::copy(r | std::views::drop(sz) | std::views::take(pos - sz), std::back_inserter(host));
|
||||
sz = pos + hostPortDelim.size();
|
||||
|
||||
found = std::ranges::search(r | std::views::drop(sz), portPathDelim);
|
||||
pos = std::distance(r.begin(), found.begin());
|
||||
|
||||
std::string port_str;
|
||||
std::ranges::copy(r | std::views::drop(sz) | std::views::take(pos - sz), std::back_inserter(port_str));
|
||||
|
||||
int port;
|
||||
auto end_ptr = port_str.data() + port_str.size();
|
||||
|
||||
auto [ptr, ec] = std::from_chars(port_str.data(), end_ptr, port);
|
||||
if (ec != std::errc() || ptr != end_ptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sz = pos + portPathDelim.size();
|
||||
|
||||
_path.clear();
|
||||
std::ranges::copy(r | std::views::drop(sz), std::back_inserter(_path));
|
||||
|
||||
_protoID = id;
|
||||
_host = host;
|
||||
_port = port;
|
||||
|
||||
_isValid = true;
|
||||
|
||||
updateEndpointView();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool _isValid{false};
|
||||
proto_id_t _protoID;
|
||||
std::string _host, _path, _portStr;
|
||||
int _port;
|
||||
|
||||
std::array<std::string_view, 7> endpointView{protoMarkLocal, protoHostDelim, "localhost", hostPortDelim,
|
||||
"7777", portPathDelim, ""};
|
||||
|
||||
void updateEndpointView()
|
||||
{
|
||||
endpointView[0] = validProtoMarks[_protoID];
|
||||
endpointView[2] = _host.c_str();
|
||||
|
||||
_portStr = std::to_string(_port);
|
||||
endpointView[4] = _port == -1 ? "" : _portStr.c_str();
|
||||
|
||||
endpointView[6] = _path.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
256
net/adc_url.h
256
net/adc_url.h
@ -1,256 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../common/adc_traits.h"
|
||||
|
||||
namespace adc
|
||||
{
|
||||
|
||||
|
||||
/*
|
||||
* Very simple URL parser and holder class
|
||||
*
|
||||
* URL: proto_mark://host_name:port_num/path
|
||||
*/
|
||||
|
||||
class AdcURL
|
||||
{
|
||||
protected:
|
||||
static constexpr std::string_view protoHostDelim = "://";
|
||||
static constexpr std::string_view hostPortDelim = ":";
|
||||
static constexpr std::string_view portPathDelim = "/";
|
||||
|
||||
public:
|
||||
enum proto_id_t { PROTO_ID_LOCAL, PROTO_ID_TCP, PROTO_ID_TLS, PROTO_ID_UDP, PROTO_ID_WS, PROTO_ID_WSS };
|
||||
|
||||
static constexpr std::string_view protoMarkLocal{"local"}; // UNIX domain
|
||||
static constexpr std::string_view protoMarkTCP{"tcp"}; // TCP
|
||||
static constexpr std::string_view protoMarkTLS{"tls"}; // TLS
|
||||
static constexpr std::string_view protoMarkUDP{"udp"}; // UDP
|
||||
static constexpr std::string_view protoMarkWS{"ws"}; // Websocket
|
||||
static constexpr std::string_view protoMarkWSS{"wss"}; // Secure Websocket
|
||||
|
||||
static constexpr std::array validProtoMarks = {protoMarkLocal, protoMarkTCP, protoMarkTLS,
|
||||
protoMarkUDP, protoMarkWS, protoMarkWSS};
|
||||
|
||||
/* Constructors and destructor */
|
||||
|
||||
AdcURL() = default;
|
||||
|
||||
// full-feature constructor
|
||||
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT>
|
||||
AdcURL(proto_id_t proto_id, HT&& host, int port, PTT&& path) : AdcURL()
|
||||
{
|
||||
setURL(proto_id, std::forward<HT>(host), port, std::forward<PTT>(path));
|
||||
}
|
||||
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
//
|
||||
return _isValid;
|
||||
}
|
||||
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R url() const
|
||||
{
|
||||
R r;
|
||||
if (!_isValid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (_protoID == PROTO_ID_LOCAL) { // only proto mark, host and its delimiter
|
||||
std::ranges::copy(_urlView | std::views::take(3) | std::views::join, std::back_inserter(r));
|
||||
} else {
|
||||
std::ranges::copy(_urlView | std::views::join, std::back_inserter(r));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string url() const
|
||||
{
|
||||
//
|
||||
return url<std::string>();
|
||||
}
|
||||
|
||||
|
||||
template <traits::adc_char_view R>
|
||||
R proto() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return R();
|
||||
}
|
||||
|
||||
const auto& proto = validProtoMarks[_protoID];
|
||||
return R{proto.begin(), proto.end()};
|
||||
}
|
||||
|
||||
|
||||
std::string_view proto() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
return validProtoMarks[_protoID];
|
||||
}
|
||||
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R host() const
|
||||
{
|
||||
R r;
|
||||
if (!_isValid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ranges::copy(_host, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template <traits::adc_char_view R>
|
||||
R hostView() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return R();
|
||||
}
|
||||
|
||||
return R{_host.begin(), _host.end()};
|
||||
}
|
||||
|
||||
std::string host() const
|
||||
{
|
||||
//
|
||||
return _host;
|
||||
}
|
||||
|
||||
std::string_view hostView() const
|
||||
{
|
||||
//
|
||||
return std::string_view{_host.begin(), _host.end()};
|
||||
}
|
||||
|
||||
|
||||
int port() const
|
||||
{
|
||||
//
|
||||
return _isValid ? _port : -1;
|
||||
}
|
||||
|
||||
template <traits::adc_output_char_range R>
|
||||
R path() const
|
||||
{
|
||||
R r;
|
||||
if (!_isValid) {
|
||||
return r;
|
||||
}
|
||||
|
||||
std::ranges::copy(_path, std::back_inserter(r));
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template <traits::adc_char_view R>
|
||||
R pathView() const
|
||||
{
|
||||
if (!_isValid) {
|
||||
return R();
|
||||
}
|
||||
|
||||
return R{_path.begin(), _path.end()};
|
||||
}
|
||||
|
||||
std::string path() const
|
||||
{
|
||||
//
|
||||
return _isValid ? _path : "";
|
||||
}
|
||||
|
||||
std::string_view pathView() const
|
||||
{
|
||||
//
|
||||
return _isValid ? std::string_view{_path.begin(), _path.end()} : std::string_view();
|
||||
}
|
||||
|
||||
template <traits::adc_input_char_range HT, traits::adc_input_char_range PTT>
|
||||
bool setURL(proto_id_t proto_id, HT&& host, int port, PTT&& path)
|
||||
{
|
||||
if (!std::distance(host.begin(), host.end())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (proto_id) {
|
||||
case PROTO_ID_LOCAL:
|
||||
// ignore path (always "") and port (just skip)
|
||||
_port = -1;
|
||||
_path.clear();
|
||||
|
||||
break;
|
||||
case PROTO_ID_TCP:
|
||||
case PROTO_ID_TLS:
|
||||
case PROTO_ID_UDP:
|
||||
case PROTO_ID_WS:
|
||||
case PROTO_ID_WSS:
|
||||
if (port <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_port = port;
|
||||
|
||||
_path.clear();
|
||||
std::ranges::copy(std::forward<PTT>(path), std::back_inserter(_path));
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_isValid = true;
|
||||
|
||||
_protoID = proto_id;
|
||||
|
||||
_host.clear();
|
||||
std::ranges::copy(std::forward<PTT>(host), std::back_inserter(_host));
|
||||
|
||||
updateURLView();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <traits::adc_input_char_range R>
|
||||
bool setURL(R&& r)
|
||||
{
|
||||
auto found = std::ranges::search(std::forward<R>(r), protoHostDelim);
|
||||
|
||||
if (found.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool _isValid{false};
|
||||
proto_id_t _protoID;
|
||||
std::string _host, _path, _portStr;
|
||||
int _port;
|
||||
|
||||
std::array<std::string_view, 7> _urlView{protoMarkLocal, protoHostDelim, "localhost", hostPortDelim,
|
||||
"7777", portPathDelim, ""};
|
||||
|
||||
void updateURLView()
|
||||
{
|
||||
_urlView[0] = validProtoMarks[_protoID];
|
||||
_urlView[2] = _host.c_str();
|
||||
_portStr = std::to_string(_port);
|
||||
_urlView[4] = _port == -1 ? "" : _portStr.c_str();
|
||||
_urlView[6] = _path.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
@ -6,6 +6,7 @@
|
||||
// #include "../common/adc_utils.h"
|
||||
// #include "../net/adc_netmessage.h"
|
||||
|
||||
#include "../net/adc_endpoint.h"
|
||||
#include "../net/adc_netmsg.h"
|
||||
|
||||
using namespace adc;
|
||||
@ -66,6 +67,19 @@ TEST_CASE("[ADC NET MESSAGE]")
|
||||
std::cout << "[" << el << "]";
|
||||
}
|
||||
std::cout << "\n";
|
||||
|
||||
|
||||
std::cout << "\n\n\n";
|
||||
|
||||
AdcEndpoint ept(AdcEndpoint::PROTO_ID_LOCAL, "SOCK");
|
||||
|
||||
std::cout << "EPT: [" << ept.endpoint() << "]\n";
|
||||
std::cout << "EPT SZ: " << ept.endpoint().size() << "\n";
|
||||
|
||||
char ee[] = "tls://dewlkj.dwed.dwed:8012/dwelk";
|
||||
ept.setEndpoint(ee);
|
||||
|
||||
std::cout << "EPT: [" << ept.endpoint() << "]\n";
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user