diff --git a/net/adc_device_netserver.h b/net/adc_device_netserver.h index deae86c..ab8efd5 100644 --- a/net/adc_device_netserver.h +++ b/net/adc_device_netserver.h @@ -281,6 +281,8 @@ public: void processMessage(auto& msg) { + typedef std::decay_t msg_t; + typedef std::vector attr_vec_t; attr_vec_t attrs; diff --git a/net/adc_endpoint.h b/net/adc_endpoint.h index 0856bdc..bcdfd7c 100644 --- a/net/adc_endpoint.h +++ b/net/adc_endpoint.h @@ -38,7 +38,7 @@ namespace adc */ -class AdcEndpointParser +class AdcEndpoint { public: static constexpr std::string_view protoHostDelim = "://"; @@ -76,13 +76,38 @@ public: template - AdcEndpointParser(const R& ept) + AdcEndpoint(const R& ept) { fromRange(ept); } + AdcEndpoint(const AdcEndpoint& other) + { + copyInst(other); + } - virtual ~AdcEndpointParser() = default; + AdcEndpoint(AdcEndpoint&& other) + { + moveInst(std::move(other)); + } + + virtual ~AdcEndpoint() = default; + + + AdcEndpoint& operator=(const AdcEndpoint& other) + { + copyInst(other); + + return *this; + } + + + AdcEndpoint& operator=(AdcEndpoint&& other) + { + moveInst(std::move(other)); + + return *this; + } template requires std::ranges::contiguous_range @@ -274,7 +299,7 @@ protected: ssize_t idx = 0; // case-insensitive look-up - bool found = std::ranges::any_of(AdcEndpointParser::validProtoMarks, [&idx, &proto_mark, this](const auto& el) { + bool found = std::ranges::any_of(AdcEndpoint::validProtoMarks, [&idx, &proto_mark](const auto& el) { bool ok = utils::AdcCharRangeCompare(proto_mark, el, true); if (!ok) { @@ -322,389 +347,53 @@ protected: return res; } -}; - - -class AdcEndpoint -{ -public: - static constexpr std::string_view protoHostDelim = "://"; - static constexpr std::string_view hostPortDelim = ":"; - static constexpr std::string_view portPathDelim = "/"; - - 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}; - - - // factory methods - - template - AdcEndpoint createLocal(R&& path) + void copyInst(const AdcEndpoint& other) { - return AdcEndpoint(PROTO_ID_LOCAL, std::string_view(""), -1, std::forward(path)); - } + if (&other != this) { + if (other._isValid) { + _isValid = other._isValid; + _endpoint = other._endpoint; + _proto = other._proto; - template - AdcEndpoint createTCP(HT&& host, int port) - { - return AdcEndpoint(PROTO_ID_TCP, std::forward(host), port); - } + auto idx = std::distance(other._endpoint.c_str(), other._host.data()); + _host = std::string_view(_endpoint.c_str() + idx, other._host.size()); -#ifdef USE_OPENSSL_WITH_ASIO - template - AdcEndpoint createTLS(HT&& host, int port) - { - return AdcEndpoint(PROTO_ID_TLS, std::forward(host), port); - } -#endif + idx = std::distance(other._endpoint.c_str(), other._path.data()); + _path = std::string_view(_endpoint.c_str() + idx, other._path.size()); - template - AdcEndpoint createUDP(HT&& host, int port) - { - return AdcEndpoint(PROTO_ID_UDP, std::forward(host), port); - } - - - template - AdcEndpoint createWS(HT&& host, int port, PTT&& path = PTT()) - { - return AdcEndpoint(PROTO_ID_WS, std::forward(host), port, std::forward(path)); - } - - - template - AdcEndpoint createWSS(HT&& host, int port, PTT&& path = PTT()) - { - return AdcEndpoint(PROTO_ID_WSS, std::forward(host), port, std::forward(path)); - } - - - /* Constructors and destructor */ - - AdcEndpoint() = default; - - // full-feature constructor - template - AdcEndpoint(proto_id_t proto_id, HT&& host, int port = -1, PTT&& path = PTT()) : AdcEndpoint() - { - setEndpoint(proto_id, std::forward(host), port, std::forward(path)); - } - - - bool valid() const - { - // - return _isValid; - } - - - template - 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(); - } - - - template - 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 - R host() const - { - R r; - if (!_isValid) { - return r; - } - - std::ranges::copy(_host, std::back_inserter(r)); - - return r; - } - - template - 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 - R path() const - { - R r; - if (!_isValid) { - return r; - } - - std::ranges::copy(_path, std::back_inserter(r)); - - return r; - } - - template - 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 - 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 = other._port; + } else { + _isValid = false; + _endpoint = std::string(); + _proto = std::string_view(); + _host = std::string_view(); + _path = std::string_view(); _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 - bool setEndpoint(char (&r)[N]) - { - return setEndpoint(std::string_view(r)); - } - - template - 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; // case-insensitive! - std::ranges::copy( - r | std::views::take(sz) | std::views::transform([](auto ch) -> char { return std::tolower(ch); }), - std::back_inserter(proto)); - - std::underlying_type_t i = 0; - proto_id_t id = PROTO_ID_UNKNOWN; - - for (const auto& el : validProtoMarks) { - if (std::ranges::equal(el, proto)) { - id = static_cast(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 endpointView{protoMarkLocal, protoHostDelim, "localhost", hostPortDelim, - "7777", portPathDelim, ""}; - - void updateEndpointView() + void moveInst(AdcEndpoint&& other) { - 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(); + if (&other != this) { + if (other._isValid) { + _isValid = std::move(other._isValid); + _endpoint = std::move(other._endpoint); + _proto = other._proto; + _host = std::move(other._host); + _path = std::move(other._path); + _port = std::move(other._port); + } else { + _isValid = false; + _endpoint = std::string(); + _proto = std::string_view(); + _host = std::string_view(); + _path = std::string_view(); + _port = -1; + } + } } }; diff --git a/net/asio/adc_device_netserver_asio.h b/net/asio/adc_device_netserver_asio.h index 386a92f..47e0ea8 100644 --- a/net/asio/adc_device_netserver_asio.h +++ b/net/asio/adc_device_netserver_asio.h @@ -24,7 +24,7 @@ public: } - template EptT> + template EptT> #ifdef USE_OPENSSL_WITH_ASIO void start(const EptT& endpoint, asio::ssl::context tls_context = asio::ssl::context(asio::ssl::context::tlsv13_server), diff --git a/tests/adc_asio_netserver_test.cpp b/tests/adc_asio_netserver_test.cpp index 201243b..355d21e 100644 --- a/tests/adc_asio_netserver_test.cpp +++ b/tests/adc_asio_netserver_test.cpp @@ -108,7 +108,7 @@ int main(int argc, char* argv[]) "endpoints server will be listening for. For 'local' endpoint the '@' symbol at the beginning of the path " "means " "abstract namespace socket.", - cxxopts::value>()->default_value("local://stream/ADC_ASIO_TEST_SERVER")); + cxxopts::value>()->default_value("local://stream/@ADC_ASIO_TEST_SERVER")); options.positional_help("[endpoint0] [enpoint1] ... [endpointN]"); @@ -144,13 +144,13 @@ int main(int argc, char* argv[]) auto epnt = opt_result["endpoints"].as>(); for (auto& ep : epnt) { - adc::AdcEndpointParser epn(ep); + adc::AdcEndpoint epn(ep); if (epn.isValid()) { if (epn.isLocalSeqpacket() || epn.isLocalStream()) { if (epn.path()[0] == '@') { // replace '@' to '\0' (use of UNIX abstract namespace) auto it = std::ranges::find(ep, '@'); *it = '\0'; - epn = adc::AdcEndpointParser(ep); + epn = adc::AdcEndpoint(ep); } } diff --git a/tests/adc_netmsg_test.cpp b/tests/adc_netmsg_test.cpp index 39375a3..c4cde38 100644 --- a/tests/adc_netmsg_test.cpp +++ b/tests/adc_netmsg_test.cpp @@ -85,7 +85,7 @@ TEST_CASE("[ADC NET MESSAGE]") char ee[] = "tLs://dewlkK.dwed.dwed:8012/dwelk"; std::cout << "EPT CHAR RANGE: " << ee << "\n"; - AdcEndpointParser prs(ee); + AdcEndpoint prs(ee); std::cout << std::boolalpha << "IS VALID: " << prs.isValid() << "\n"; std::cout << "PROTO: [" << prs.proto() << "]\n"; @@ -100,7 +100,7 @@ TEST_CASE("[ADC NET MESSAGE]") auto it = std::ranges::find(bs, '@'); *it = '\0'; std::cout << "EPT CHAR RANGE: " << bs << "\n"; - prs = AdcEndpointParser(bs); + prs = AdcEndpoint(bs); std::cout << std::boolalpha << "IS VALID: " << prs.isValid() << "\n"; std::cout << "PROTO: [" << prs.proto() << "]\n"; std::cout << "HOST: [" << prs.host() << "]\n";