From a2093e24a6e5224a8bd70314ca9b3bff7f493a4a Mon Sep 17 00:00:00 2001 From: peri4 Date: Tue, 26 May 2026 21:31:58 +0300 Subject: [PATCH] detach PIHTTPServer::Endpoint to base struct PIHTTP::ServerEndpoint (private header), no functionality changes in HTTP server Ready to implement this private base struct to MQTT client --- libs/http_server/pihttpserver.cpp | 158 ++++-------------------- libs/main/http_common/pihttptypes.h | 5 + libs/main/http_server/pihttpserver.h | 36 +----- main.cpp | 177 +++++++-------------------- 4 files changed, 76 insertions(+), 300 deletions(-) diff --git a/libs/http_server/pihttpserver.cpp b/libs/http_server/pihttpserver.cpp index 796f88c4..eb4d11ec 100644 --- a/libs/http_server/pihttpserver.cpp +++ b/libs/http_server/pihttpserver.cpp @@ -1,14 +1,25 @@ #include "pihttpserver.h" -#include "piliterals_string.h" +#include "piserverendpoint_p.h" + + +struct Endpoint: public PIHTTP::ServerEndpoint { + PIHTTP::Method method = PIHTTP::Method::Unknown; + PIHTTPServer::RequestFunction function; +}; + + +PRIVATE_DEFINITION_START(PIHTTPServer) + PIMap> endpoints; +PRIVATE_DEFINITION_END(PIHTTPServer) PIHTTPServer::PIHTTPServer() { setRequestCallback([this](const PIHTTP::MessageConst & r) -> PIHTTP::MessageMutable { PIHTTP::MessageMutable reply; reply.setCode(PIHTTP::Code::NotFound); - auto in_path = splitPath(r.path()); - auto it = endpoints.makeReverseIterator(); + auto in_path = PIHTTP::ServerEndpoint::splitPath(r.path()); + auto it = PRIVATE->endpoints.makeReverseIterator(); bool found = false; while (it.next()) { for (const auto & ep: it.value()) { @@ -41,159 +52,36 @@ PIHTTPServer::~PIHTTPServer() { } -bool PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, RequestFunction functor) { +bool PIHTTPServer::registerPath(const PIString & path, PIHTTP::Method method, PIHTTP::RequestFunction functor) { Endpoint ep; if (!ep.create(path)) return false; ep.method = method; ep.function = std::move(functor); - endpoints[ep.priority] << ep; + PRIVATE->endpoints[ep.priority] << ep; return true; } -void PIHTTPServer::registerUnhandled(RequestFunction functor) { +void PIHTTPServer::registerUnhandled(PIHTTP::RequestFunction functor) { unhandled = functor; } void PIHTTPServer::unregisterPath(const PIString & path, PIHTTP::Method method) { - auto pl = splitPath(path); - auto it = endpoints.makeIterator(); + auto pl = PIHTTP::ServerEndpoint::splitPath(path); + auto it = PRIVATE->endpoints.makeIterator(); while (it.next()) { it.value().removeWhere([&pl, method](const Endpoint & ep) { return ep.path == pl && ep.method == method; }); } - endpoints.removeWhere([](uint, const PIVector & epl) { return epl.isEmpty(); }); + PRIVATE->endpoints.removeWhere([](uint, const PIVector & epl) { return epl.isEmpty(); }); } void PIHTTPServer::unregisterPath(const PIString & path) { - auto pl = splitPath(path); - auto it = endpoints.makeIterator(); + auto pl = PIHTTP::ServerEndpoint::splitPath(path); + auto it = PRIVATE->endpoints.makeIterator(); while (it.next()) { it.value().removeWhere([&pl](const Endpoint & ep) { return ep.path == pl; }); } - endpoints.removeWhere([](uint, const PIVector & epl) { return epl.isEmpty(); }); -} - - -PIStringList PIHTTPServer::splitPath(const PIString & path) { - auto ret = path.split("/"); - ret.removeAll({}); - return ret; -} - - -PIHTTPServer::PathElement::PathElement(const PIString & reg) { - source = reg; - if (reg == "*"_a) { - type = Type::AnyOne; - } else if (reg == "**"_a) { - type = Type::AnyMany; - } else if (reg.contains('*')) { - type = Type::AnyPart; - parts = reg.split('*'); - } else if (reg.contains('{')) { - type = Type::Arguments; - int ind = 0, eind = 0, pind = 0; - for (;;) { - ind = reg.find('{', ind); - if (ind < 0) break; - eind = reg.find('}', ind + 1); - if (eind < 0) break; - arguments.insert(arguments.size_s(), reg.mid(ind + 1, eind - ind - 1)); - if (ind == 0) - parts << PIString(); - else { - if (ind > pind) - parts << reg.mid(pind, ind - pind); - else if (parts.isNotEmpty()) { - piCout << "[PIHTTPServer] Warning: sequential arguments, ignoring this path!"; - type = Type::Invalid; - return; - } - } - ind = pind = eind + 1; - } - if (eind < reg.size_s() - 1) parts << reg.mid(eind + 1); - } -} - - -bool PIHTTPServer::PathElement::match(const PIString & in, PIMap & ext_args) const { - // piCout << "match" << source << "with" << in; - if (type == Type::AnyOne) return true; - if (type == Type::AnyPart) { - int ind = 0; - for (const auto & m: parts) { - ind = in.find(m, ind); - if (ind < 0) return false; - } - return true; - } - if (type == Type::Arguments) { - int ind = 0, eind = 0; - for (int i = 0; i < parts.size_s(); ++i) { - const auto & m(parts[i]); - if (m.isNotEmpty()) { - ind = in.find(m, eind); - if (ind < 0) return false; - } - if (i > 0) { - ext_args[arguments.value(i - 1)] = in.mid(eind, ind - eind); - } - eind = ind + m.size_s(); - } - if (parts.size() == arguments.size()) { - ext_args[arguments.value(arguments.size_s() - 1)] = in.mid(eind); - } - return true; - } - return source == in; -} - - -uint PIHTTPServer::PathElement::priority() const { - switch (type) { - case Type::Fixed: return 0x10000; break; - case Type::Arguments: return 0x1000; break; - case Type::AnyPart: return 0x100; break; - case Type::AnyOne: return 0x10; break; - case Type::AnyMany: return 0x1; break; - default: break; - } - return 0; -} - - -bool PIHTTPServer::Endpoint::create(const PIString & p) { - path = splitPath(p); - prepared_path.clear(); - priority = 0; - for (const auto & i: path) { - PathElement pe(i); - prepared_path << pe; - path_types |= pe.type; - priority += pe.priority(); - } - return !path_types[PathElement::Type::Invalid]; -} - - -bool PIHTTPServer::Endpoint::match(const PIStringList & in_path, PIMap & ext_args) const { - if (path_types[PathElement::Type::AnyMany]) { - int any_ind = path.indexOf("**"_a); - for (int i = 0; i < any_ind; ++i) { - if (!prepared_path[i].match(in_path[i], ext_args)) return false; - } - int si = prepared_path.size_s() - 1, ii = in_path.size_s() - 1; - for (; si > any_ind && ii >= 0; --si, --ii) { - if (!prepared_path[si].match(in_path[ii], ext_args)) return false; - } - } else { - if (in_path.size() != prepared_path.size()) return false; - for (int i = 0; i < prepared_path.size_s(); ++i) { - if (!prepared_path[i].match(in_path[i], ext_args)) return false; - } - } - return true; + PRIVATE->endpoints.removeWhere([](uint, const PIVector & epl) { return epl.isEmpty(); }); } diff --git a/libs/main/http_common/pihttptypes.h b/libs/main/http_common/pihttptypes.h index cb8cf15e..a105ecf0 100644 --- a/libs/main/http_common/pihttptypes.h +++ b/libs/main/http_common/pihttptypes.h @@ -210,6 +210,11 @@ public: PIP_EXPORT const char * methodName(Method m); +//! \~english Request handler used by registered routes and fallback processing. +//! \~russian Обработчик запроса, используемый зарегистрированными маршрутами и fallback-обработкой. +using RequestFunction = std::function; + + }; // namespace PIHTTP diff --git a/libs/main/http_server/pihttpserver.h b/libs/main/http_server/pihttpserver.h index 68fa2fe4..ca3abea1 100644 --- a/libs/main/http_server/pihttpserver.h +++ b/libs/main/http_server/pihttpserver.h @@ -102,43 +102,9 @@ public: void clearReplyHeaders() { reply_headers.clear(); } private: - struct PathElement { - enum class Type { - Invalid = 0x01, - Fixed = 0x02, - Arguments = 0x04, - AnyOne = 0x08, - AnyPart = 0x10, - AnyMany = 0x20 - }; - - Type type = Type::Fixed; - PIString source; - PIStringList parts; - PIMap arguments; - - PathElement(const PIString & reg = {}); - - bool match(const PIString & in, PIMap & ext_args) const; - uint priority() const; - }; - - struct Endpoint { - PIStringList path; - PIHTTP::Method method = PIHTTP::Method::Unknown; - RequestFunction function; - PIFlags path_types; - PIVector prepared_path; - uint priority = 0; - - bool create(const PIString & p); - bool match(const PIStringList & in_path, PIMap & ext_args) const; - }; - - static PIStringList splitPath(const PIString & path); + PRIVATE_DECLARATION(PIP_HTTP_SERVER_EXPORT) PIMap reply_headers; - PIMap> endpoints; RequestFunction unhandled; }; diff --git a/main.cpp b/main.cpp index fa83d4df..f92b7159 100644 --- a/main.cpp +++ b/main.cpp @@ -10,18 +10,57 @@ using namespace PICoutManipulators; using namespace PIHTTP; -using namespace PIUnits::Class; -int rcnt = 0, scnt = 0; - -inline PIByteArray SMBusTypeInfo_genHash(PIString n) { - PICrypt c; - return piSerialize(c.shorthash(n.removeAll(" "), PIString("SMBusDataHashKey").toByteArray())); -} PIKbdListener kbd; +MessageMutable createMessage(Code c, const char * path, const MessageConst & msg) { + piCout << "path" << path << "args" << msg.pathArguments(); + return MessageMutable().setCode(c); +}; int main(int argc, char * argv[]) { + piCout << "start ..."; + PIHTTPServer server; + server.registerUnhandled([](const MessageConst & msg) { return createMessage(Code::BadRequest, "unhadled", msg); }); + server.registerPath("api/v1/status", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/status", msg); + }); + server.registerPath("api/v1/plugins", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/plugins", msg); + }); + server.registerPath("api/v1/task-status", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/task-status", msg); + }); + server.registerPath("api/v1/task/{taskID}/status", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/task/{taskID}/status", msg); + }); + server.registerPath("api/v1/bort/list", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/bort/list", msg); + }); + server.registerPath("api/v1/all", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/all", msg); + }); + server.registerPath("api/v1/all/bort{A}/f", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/all/*/f", msg); + }); + server.registerPath("api/v1/all2/**", Method::Get, [](const MessageConst & msg) { + return createMessage(Code::Accepted, "api/v1/all2/**", msg); + }); + server.listenAll(12345); + + kbd.enableExitCapture('Q'); + WAIT_FOR_EXIT + piCout << "exiting ..."; + server.stop(); + + return 0; + + PISystemMonitor mon; + mon.startOnSelf(); + PISystemMonitor::totalRAM(); + 2_s .sleep(); + + return 0; PIMQTT::Client cl; cl.setConnectTimeout(2_s); CONNECTL(&cl, connected, [&cl] { @@ -36,7 +75,7 @@ int main(int argc, char * argv[]) { cl.connect("localhost", "PIP"); }); CONNECTL(&cl, received, [](const PIMQTT::MessageConst & message) { - piCout << "received" << message.topic() << message.payload().size(); + piCout << "received" << message.topic() << message.pathArguments() << message.payload().size(); }); cl.connect("localhost", "PIP"); @@ -45,126 +84,4 @@ int main(int argc, char * argv[]) { WAIT_FOR_EXIT piCout << "exiting ..."; - return 0; - - PICrypt _crypt; - // auto ba = PIFile::readAll("logo.png"); - PIString str = "hello!"_a; - PIByteArray ba = str.toAscii(); - PIByteArray key = PIString("SMBusDataHashKey").toByteArray(); - - const int times = 1000000; - PITimeMeasurer tm; - PISystemTime el; - - tm.reset(); - piForTimes(times) { - PIDigest::calculateWithKey(ba, key, PIDigest::Type::SipHash_2_4_128); - } - el = tm.elapsed(); - piCout << "PIDigest" << el.toString(); - - tm.reset(); - piForTimes(times) { - _crypt.shorthash(str, key); - } - el = tm.elapsed(); - piCout << " sodium" << el.toString(); - - tm.reset(); - piForTimes(times) { - PIDigest::calculateWithKey(ba, key, PIDigest::Type::BLAKE2b_128); - } - el = tm.elapsed(); - piCout << " blake" << el.toString(); - - return 0; - - - PIEthernet *eth_r, *eth_s; - eth_r = PIIODevice::createFromFullPath("eth://udp: 192.168.1.25 :10000")->cast(); - eth_s = PIIODevice::createFromFullPath("eth://udp: : : 192.168.1.25:10000")->cast(); - - eth_r->setReadBufferSize(1_MiB); - CONNECTL(eth_r, threadedReadEvent, [](const uchar * readed, ssize_t size) { - // piCout << "rec"; - piMSleep(1); - ++rcnt; - }); - eth_r->startThreadedRead(); - - PIByteArray _ba(1400); - for (int i = 0; i < 100; ++i) { - eth_s->write(_ba); - ++scnt; - } - - 0.2_s .sleep(); - - piCout << "snd" << scnt; - piCout << "rec" << rcnt; - - piDeleteSafety(eth_r); - piDeleteSafety(eth_s); - return 0; - - PITranslator::loadLang("ru"); - /*auto ucl = PIUnits::allClasses(); - for (auto c: ucl) { - piCout << (c->className() + ":"); - for (auto t: c->allTypes()) { - piCout << " " << c->name(t) << "->" << c->unit(t); - } - }*/ - - // PIUnits::Value(1); - // piCout << PIUnits::name(PIUnits::Class::Information::Bit); - // piCout << PIUnits::name(PIUnits::Class::Information::Byte); - // piCout << PIUnits::name(PIUnits::Class::Information::_LastType); - // piCout << PIUnits::name((int)PIUnits::Class::Angle::Degree); - - // piCout << PIUnits::unit(PIUnits::Class::Information::Bit); - // piCout << PIUnits::unit(PIUnits::Class::Information::Byte); - // piCout << PIUnits::unit(PIUnits::Class::Information::_LastType); - // piCout << PIUnits::unit((int)PIUnits::Class::Angle::Degree); - - // for (int i = -10; i < 10; ++i) - // piCout << PIUnits::Value(pow10(i * 0.99), PIUnits::Class::Distance::Meter).toString(); - - auto v = PIUnits::Value(M_PI, Angle::Radian); - piCout << v << "=" << v.converted(Angle::Degree); - - v = PIUnits::Value(45, Angle::Degree); - piCout << v << "=" << v.converted(Angle::Radian); - - piCout << PIUnits::Value(5E-5, Time::Second); - piCout << PIUnits::Value(3E-3, Time::Second); - piCout << PIUnits::Value(0.8, Time::Second); - piCout << PIUnits::Value(1.2, Time::Second); - piCout << PIUnits::Value(1001, Time::Second); - piCout << PIUnits::Value(1000001, Time::Second); - - piCout << PIUnits::Value(1_KB, Information::Byte); - piCout << PIUnits::Value(1_MB, Information::Byte); - piCout << PIUnits::Value(1_MiB, Information::Byte); - piCout << PIUnits::Value(1_MB, Information::Byte).converted(Information::Bit); - piCout << PIUnits::Value(1_MiB, Information::Byte).converted(Information::Bit); - - piCout << PIUnits::Value(0., Temperature::Celsius).converted(Temperature::Kelvin); - piCout << PIUnits::Value(0., Temperature::Celsius).converted(Temperature::Fahrenheit); - piCout << PIUnits::Value(100., Temperature::Celsius).converted(Temperature::Fahrenheit); - - piCout << PIUnits::Value(1., Pressure::Atmosphere).converted(Pressure::Pascal); - piCout << PIUnits::Value(1., Pressure::Atmosphere).converted(Pressure::MillimetreOfMercury); - piCout << PIUnits::Value(766., Pressure::MillimetreOfMercury).converted(Pressure::Atmosphere); - - piCout << PIUnits::Value(5E-5, Time::Second).converted(Time::Hertz); - piCout << PIUnits::Value(3E-3, Time::Second).converted(Time::Hertz); - piCout << PIUnits::Value(0.8, Time::Second).converted(Time::Hertz); - piCout << PIUnits::Value(1.2, Time::Second).converted(Time::Hertz); - piCout << PIUnits::Value(1001, Time::Second).converted(Time::Hertz); - piCout << PIUnits::Value(1000001, Time::Second).converted(Time::Hertz); - // piCout << PIUnits::Value(0.2, Time::Second).converted(Time::Hertz); - // piCout << PIUnits::Value(5E-5, Time::Second).converted(Time::Hertz); - return 0; }