From 41ecf9c222e523b67324d0a8aaf981439922e71c Mon Sep 17 00:00:00 2001 From: stephb9959 Date: Tue, 30 Nov 2021 23:39:33 -0800 Subject: [PATCH] Initial commit Signed-off-by: stephb9959 --- microservice_sample/CMakeLists.txt | 77 +- microservice_sample/README.md | 24 +- microservice_sample/build | 2 +- microservice_sample/src/APIServers.cpp | 24 - microservice_sample/src/Daemon.cpp | 7 +- microservice_sample/src/Daemon.h | 5 +- .../src/RESTAPI/RESTAPI_helloWorld_handler.h | 9 +- .../src/RESTAPI/RESTAPI_routers.cpp | 27 + .../RESTObjects/RESTAPI_AnalyticsObjects.cpp | 624 +++ .../RESTObjects/RESTAPI_AnalyticsObjects.h | 422 ++ .../src/RESTObjects/RESTAPI_CertObjects.cpp | 208 + .../src/RESTObjects/RESTAPI_CertObjects.h | 122 + .../src/RESTObjects/RESTAPI_FMSObjects.cpp | 65 +- .../src/RESTObjects/RESTAPI_FMSObjects.h | 38 +- .../src/RESTObjects/RESTAPI_GWobjects.cpp | 143 +- .../src/RESTObjects/RESTAPI_GWobjects.h | 123 +- .../src/RESTObjects/RESTAPI_ProvObjects.cpp | 732 ++- .../src/RESTObjects/RESTAPI_ProvObjects.h | 345 +- .../RESTObjects/RESTAPI_SecurityObjects.cpp | 166 +- .../src/RESTObjects/RESTAPI_SecurityObjects.h | 490 +- .../src/RESTObjects/RESTAPI_SubObjects.cpp | 603 ++ .../src/RESTObjects/RESTAPI_SubObjects.h | 322 ++ microservice_sample/src/StorageService.cpp | 3 +- microservice_sample/src/StorageService.h | 18 +- microservice_sample/src/framework/API_Proxy.h | 93 + .../src/framework/ConfigurationValidator.cpp | 4976 +++++++++-------- .../src/framework/ConfigurationValidator.h | 10 +- .../src/framework/KafkaTopics.h | 2 + .../src/framework/MicroService.h | 2945 +++++++--- .../src/framework/OpenWifiTypes.h | 46 +- .../src/framework/RESTAPI_errors.h | 63 - .../src/framework/RESTAPI_protocol.h | 137 - .../src/framework/StorageClass.h | 72 +- .../framework/WebSocketClientNotifications.h | 193 + microservice_sample/src/framework/orm.h | 519 +- .../src/framework/ow_constants.h | 515 ++ .../src/framework/uCentral_Protocol.h | 130 - microservice_sample/src/ow_version.h.in | 13 + 38 files changed, 10217 insertions(+), 4096 deletions(-) delete mode 100644 microservice_sample/src/APIServers.cpp create mode 100644 microservice_sample/src/RESTAPI/RESTAPI_routers.cpp create mode 100644 microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp create mode 100644 microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.h create mode 100644 microservice_sample/src/RESTObjects/RESTAPI_CertObjects.cpp create mode 100644 microservice_sample/src/RESTObjects/RESTAPI_CertObjects.h create mode 100644 microservice_sample/src/RESTObjects/RESTAPI_SubObjects.cpp create mode 100644 microservice_sample/src/RESTObjects/RESTAPI_SubObjects.h create mode 100644 microservice_sample/src/framework/API_Proxy.h delete mode 100644 microservice_sample/src/framework/RESTAPI_errors.h delete mode 100644 microservice_sample/src/framework/RESTAPI_protocol.h create mode 100644 microservice_sample/src/framework/WebSocketClientNotifications.h create mode 100644 microservice_sample/src/framework/ow_constants.h delete mode 100644 microservice_sample/src/framework/uCentral_Protocol.h create mode 100644 microservice_sample/src/ow_version.h.in diff --git a/microservice_sample/CMakeLists.txt b/microservice_sample/CMakeLists.txt index 9a9c399..c9bacb7 100644 --- a/microservice_sample/CMakeLists.txt +++ b/microservice_sample/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.13) -project(ow_helloworld VERSION 1.0.0) +project(ow_helloworld VERSION 2.7.0) set(CMAKE_CXX_STANDARD 17) @@ -20,24 +20,38 @@ endif() # Auto build increment. You must define BUILD_INCREMENT with cmake -DBUILD_INCREMENT=1 if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/build) - file(READ build BUILD_NUM) + file(READ ${CMAKE_CURRENT_SOURCE_DIR}/build BUILD_NUM) if(BUILD_INCREMENT) MATH(EXPR BUILD_NUM "${BUILD_NUM}+1") - file(WRITE build ${BUILD_NUM}) + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM}) endif() else() set(BUILD_NUM 1) - file(WRITE build ${BUILD_NUM}) + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/build ${BUILD_NUM}) +endif() + +if(ASAN) + add_compile_options(-fsanitize=address) + add_link_options(-fsanitize=address) + add_compile_options(-fsanitize=undefined) + add_link_options(-fsanitize=undefined) +endif() + +find_package(Git QUIET) +if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_RESULT + OUTPUT_VARIABLE GIT_HASH) + if(NOT GIT_RESULT EQUAL "0") + message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}") + endif() + string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}") endif() -add_definitions(-DAPP_VERSION="${CMAKE_PROJECT_VERSION}" -DBUILD_NUMBER="${BUILD_NUM}") -add_definitions(-DTIP_GATEWAY_SERVICE="1") -set(Boost_USE_STATIC_LIBS OFF) -set(Boost_USE_MULTITHREADED ON) -set(Boost_USE_STATIC_RUNTIME OFF) -find_package(Boost REQUIRED system) find_package(OpenSSL REQUIRED) find_package(ZLIB REQUIRED) +find_package(fmt REQUIRED) find_package(nlohmann_json REQUIRED) find_package(nlohmann_json_schema_validator REQUIRED) @@ -51,24 +65,27 @@ else() endif() include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include) +configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY) +add_compile_options(-Wall -Wextra) -add_executable(ow_helloworld - build - src/framework/CountryCodes.h - src/framework/KafkaTopics.h - src/framework/MicroService.h - src/framework/OpenWifiTypes.h - src/framework/orm.h - src/framework/RESTAPI_errors.h - src/framework/RESTAPI_protocol.h - src/framework/StorageClass.h - src/framework/uCentral_Protocol.h - src/APIServers.cpp - src/RESTObjects/RESTAPI_SecurityObjects.cpp src/RESTObjects/RESTAPI_SecurityObjects.h - src/StorageService.cpp src/StorageService.h - src/RESTAPI/RESTAPI_helloWorld_handler.cpp src/RESTAPI/RESTAPI_helloWorld_handler.h - src/Daemon.cpp src/Daemon.h - src/framework/ConfigurationValidator.cpp src/framework/ConfigurationValidator.h +add_executable( ow_helloworld + build + src/ow_version.h.in + src/framework/CountryCodes.h + src/framework/KafkaTopics.h + src/framework/MicroService.h + src/framework/OpenWifiTypes.h + src/framework/orm.h + src/framework/StorageClass.h + src/framework/ConfigurationValidator.cpp + src/framework/ConfigurationValidator.h + src/framework/ow_constants.h + src/RESTAPI/RESTAPI_routers.cpp + src/RESTObjects/RESTAPI_SecurityObjects.cpp src/RESTObjects/RESTAPI_SecurityObjects.h + src/RESTAPI/RESTAPI_helloWorld_handler.cpp src/RESTAPI/RESTAPI_helloWorld_handler.h + src/StorageService.cpp src/StorageService.h + src/Daemon.cpp src/Daemon.h + src/framework/ConfigurationValidator.cpp src/framework/ConfigurationValidator.h ) if(NOT SMALL_BUILD) @@ -80,12 +97,16 @@ INSTALL(TARGETS ow_helloworld ) target_link_libraries(ow_helloworld PUBLIC - ${Poco_LIBRARIES} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES}) + ${Poco_LIBRARIES} + ${Boost_LIBRARIES} + ${ZLIB_LIBRARIES} ) + if(NOT SMALL_BUILD) target_link_libraries(ow_helloworld PUBLIC ${MySQL_LIBRARIES} ${ZLIB_LIBRARIES} CppKafka::cppkafka nlohmann_json_schema_validator + fmt::fmt ) if(UNIX AND NOT APPLE) target_link_libraries(ow_helloworld PUBLIC PocoJSON) diff --git a/microservice_sample/README.md b/microservice_sample/README.md index 34c60db..c0777d9 100644 --- a/microservice_sample/README.md +++ b/microservice_sample/README.md @@ -6,10 +6,8 @@ This is a skeleton Micro Service that shows off all the basic facilities of the ## Building In order to build the uCentralGW, you will need to install its dependencies, which includes the following: - cmake -- boost -- POCO 1.11.1 or later (special build) +- POCO 1.12 or later (special build) - a C++17 compiler -- libyaml - openssl - libpq-dev (PortgreSQL development libraries) - mysql-client (MySQL client) @@ -28,6 +26,7 @@ sudo apt install git cmake g++ libssl-dev libmariadb-dev sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev sudo apt install librdkafka-dev libmysqlclient-dev default-libmysqlclient-dev +cd ~ git clone https://github.com/stephb9959/poco cd poco mkdir cmake-build @@ -36,6 +35,7 @@ cmake .. cmake --build . --config Release sudo cmake --build . --target install +cd ~ git clone https://github.com/stephb9959/cppkafka cd cppkafka mkdir cmake-build @@ -44,6 +44,24 @@ cmake .. cmake --build . --config Release sudo cmake --build . --target install +cd ~ +git clone https://github.com/nlohmann/json.git +cd json +mkdir cmake-build +cd cmake-build +cmake .. +make -j +sudo make install + +cd ~ +git clone https://github.com/pboettch/json-schema-validator.git +cd json-schema-validator +mkdir cmake-build +cd cmake-build +cmake .. +make -j +sudo make install + cd ~ git clone https://github.com/Telecominfraproject/wlan-cloud-tools cd wlan-cloud-tools diff --git a/microservice_sample/build b/microservice_sample/build index 56a6051..e440e5c 100644 --- a/microservice_sample/build +++ b/microservice_sample/build @@ -1 +1 @@ -1 \ No newline at end of file +3 \ No newline at end of file diff --git a/microservice_sample/src/APIServers.cpp b/microservice_sample/src/APIServers.cpp deleted file mode 100644 index 70cd19d..0000000 --- a/microservice_sample/src/APIServers.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by stephane bourque on 2021-10-23. -// - -#include "framework/MicroService.h" - -#include "RESTAPI/RESTAPI_helloWorld_handler.h" - -namespace OpenWifi { - - Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, - Poco::Logger & L, RESTAPI_GenericServer & S) { - return RESTAPI_Router< - RESTAPI_helloWorld_handler - >(Path,Bindings,L, S); - } - - Poco::Net::HTTPRequestHandler * RESTAPI_internal_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, - Poco::Logger & L, RESTAPI_GenericServer & S) { - return RESTAPI_Router_I< - RESTAPI_helloWorld_handler - >(Path,Bindings,L, S); - } -} \ No newline at end of file diff --git a/microservice_sample/src/Daemon.cpp b/microservice_sample/src/Daemon.cpp index b06f8f9..af7836b 100644 --- a/microservice_sample/src/Daemon.cpp +++ b/microservice_sample/src/Daemon.cpp @@ -29,14 +29,9 @@ namespace OpenWifi { return &instance; } - void Daemon::initialize() { - + void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) { } - void MicroServicePostInitialization() { - Daemon()->initialize(); - } - } int main(int argc, char **argv) { diff --git a/microservice_sample/src/Daemon.h b/microservice_sample/src/Daemon.h index bce889d..4c99274 100644 --- a/microservice_sample/src/Daemon.h +++ b/microservice_sample/src/Daemon.h @@ -45,7 +45,7 @@ namespace OpenWifi { const SubSystemVec & SubSystems) : MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {}; - void initialize(); + void PostInitialization(Poco::Util::Application &self); static Daemon *instance(); Poco::Logger & Log() { return Poco::Logger::get(AppName()); } private: @@ -53,5 +53,8 @@ namespace OpenWifi { }; inline Daemon * Daemon() { return Daemon::instance(); } + inline void DaemonPostInitialization(Poco::Util::Application &self) { + Daemon()->PostInitialization(self); + } } diff --git a/microservice_sample/src/RESTAPI/RESTAPI_helloWorld_handler.h b/microservice_sample/src/RESTAPI/RESTAPI_helloWorld_handler.h index 8ade9de..9278504 100644 --- a/microservice_sample/src/RESTAPI/RESTAPI_helloWorld_handler.h +++ b/microservice_sample/src/RESTAPI/RESTAPI_helloWorld_handler.h @@ -9,14 +9,17 @@ namespace OpenWifi { class RESTAPI_helloWorld_handler : public RESTAPIHandler { public: - RESTAPI_helloWorld_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal) + RESTAPI_helloWorld_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) : RESTAPIHandler(bindings, L, std::vector{ Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_OPTIONS}, Server, - Internal) {} - static const std::list PathName() { return std::list{"/api/v1/hello"}; }; + TransactionId, + Internal, + false) {} + + static auto PathName() { return std::list{"/api/v1/hello"}; }; void DoGet() final; void DoPost() final {}; diff --git a/microservice_sample/src/RESTAPI/RESTAPI_routers.cpp b/microservice_sample/src/RESTAPI/RESTAPI_routers.cpp new file mode 100644 index 0000000..f6a7f41 --- /dev/null +++ b/microservice_sample/src/RESTAPI/RESTAPI_routers.cpp @@ -0,0 +1,27 @@ +// +// Created by stephane bourque on 2021-10-23. +// + +#include "framework/MicroService.h" +#include "RESTAPI_helloWorld_handler.h" + +namespace OpenWifi { + + Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, + Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { + + return RESTAPI_Router< + RESTAPI_system_command, + RESTAPI_helloWorld_handler + >(Path,Bindings,L, S, TransactionId); + } + + Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, + Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { + + return RESTAPI_Router_I< + RESTAPI_system_command, + RESTAPI_helloWorld_handler + >(Path,Bindings,L, S, TransactionId); + } +} \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp new file mode 100644 index 0000000..e7738ba --- /dev/null +++ b/microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp @@ -0,0 +1,624 @@ +// +// Created by stephane bourque on 2022-01-10. +// + +#include "RESTAPI_AnalyticsObjects.h" +#include "RESTAPI_ProvObjects.h" +#include "framework/MicroService.h" + +using OpenWifi::RESTAPI_utils::field_to_json; +using OpenWifi::RESTAPI_utils::field_from_json; + +namespace OpenWifi::AnalyticsObjects { + + void Report::reset() { + } + + void Report::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const { + } + + void VenueInfo::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id",id); + field_to_json(Obj,"name",name); + field_to_json(Obj,"description",description); + field_to_json(Obj,"retention",retention); + field_to_json(Obj,"interval",interval); + field_to_json(Obj,"monitorSubVenues",monitorSubVenues); + } + + bool VenueInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id",id); + field_from_json(Obj,"name",name); + field_from_json(Obj,"description",description); + field_from_json(Obj,"retention",retention); + field_from_json(Obj,"interval",interval); + field_from_json(Obj,"monitorSubVenues",monitorSubVenues); + return true; + } catch(...) { + + } + return false; + } + + void BoardInfo::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json(Obj,"venueList",venueList); + } + + bool BoardInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json(Obj,"venueList",venueList); + return true; + } catch(...) { + + } + return false; + } + + void DeviceInfo::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"boardId",boardId); + field_to_json(Obj,"type",type); + field_to_json(Obj,"serialNumber",serialNumber); + field_to_json(Obj,"deviceType",deviceType); + field_to_json(Obj,"lastContact",lastContact); + field_to_json(Obj,"lastPing",lastPing); + field_to_json(Obj,"lastState",lastState); + field_to_json(Obj,"lastFirmware",lastFirmware); + field_to_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate); + field_to_json(Obj,"lastConnection",lastConnection); + field_to_json(Obj,"lastDisconnection",lastDisconnection); + field_to_json(Obj,"pings",pings); + field_to_json(Obj,"states",states); + field_to_json(Obj,"connected",connected); + field_to_json(Obj,"connectionIp",connectionIp); + field_to_json(Obj,"associations_2g",associations_2g); + field_to_json(Obj,"associations_5g",associations_5g); + field_to_json(Obj,"associations_6g",associations_6g); + field_to_json(Obj,"health",health); + field_to_json(Obj,"lastHealth",lastHealth); + field_to_json(Obj,"locale",locale); + field_to_json(Obj,"uptime",uptime); + field_to_json(Obj,"memory",memory); + } + + bool DeviceInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"boardId",boardId); + field_from_json(Obj,"type",type); + field_from_json(Obj,"serialNumber",serialNumber); + field_from_json(Obj,"deviceType",deviceType); + field_from_json(Obj,"lastContact",lastContact); + field_from_json(Obj,"lastPing",lastPing); + field_from_json(Obj,"lastState",lastState); + field_from_json(Obj,"lastFirmware",lastFirmware); + field_from_json(Obj,"lastFirmwareUpdate",lastFirmwareUpdate); + field_from_json(Obj,"lastConnection",lastConnection); + field_from_json(Obj,"lastDisconnection",lastDisconnection); + field_from_json(Obj,"pings",pings); + field_from_json(Obj,"states",states); + field_from_json(Obj,"connected",connected); + field_from_json(Obj,"connectionIp",connectionIp); + field_from_json(Obj,"associations_2g",associations_2g); + field_from_json(Obj,"associations_5g",associations_5g); + field_from_json(Obj,"associations_6g",associations_6g); + field_from_json(Obj,"health",health); + field_from_json(Obj,"lastHealth",lastHealth); + field_from_json(Obj,"locale",locale); + field_from_json(Obj,"uptime",uptime); + field_from_json(Obj,"memory",memory); + return true; + } catch(...) { + + } + return false; + } + + void DeviceInfoList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"devices",devices); + } + + bool DeviceInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"devices",devices); + return true; + } catch(...) { + + } + return false; + } + + void UE_rate::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"bitrate",bitrate); + field_to_json(Obj,"mcs",mcs); + field_to_json(Obj,"nss",nss); + field_to_json(Obj,"ht",ht); + field_to_json(Obj,"sgi",sgi); + field_to_json(Obj,"chwidth",chwidth); + } + + bool UE_rate::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"bitrate",bitrate); + field_from_json(Obj,"mcs",mcs); + field_from_json(Obj,"nss",nss); + field_from_json(Obj,"ht",ht); + field_from_json(Obj,"sgi",sgi); + field_from_json(Obj,"chwidth",chwidth); + return true; + } catch(...) { + + } + return false; + } + + void UETimePoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"station",station); + field_to_json(Obj,"rssi",rssi); + field_to_json(Obj,"tx_bytes",tx_bytes); + field_to_json(Obj,"rx_bytes",rx_bytes); + field_to_json(Obj,"tx_duration",tx_duration); + field_to_json(Obj,"rx_packets",rx_packets); + field_to_json(Obj,"tx_packets",tx_packets); + field_to_json(Obj,"tx_retries",tx_retries); + field_to_json(Obj,"tx_failed",tx_failed); + field_to_json(Obj,"connected",connected); + field_to_json(Obj,"inactive",inactive); + field_to_json(Obj,"tx_rate",tx_rate); + field_to_json(Obj,"rx_rate",rx_rate); +// field_to_json(Obj, "tidstats", tidstats); + + field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_to_json(Obj,"tx_packets_bw",tx_packets_bw); + field_to_json(Obj,"rx_packets_bw",rx_packets_bw); + field_to_json(Obj,"tx_failed_pct",tx_failed_pct); + field_to_json(Obj,"tx_retries_pct",tx_retries_pct); + field_to_json(Obj,"tx_duration_pct",tx_duration_pct); + + field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta); + field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta); + field_to_json(Obj,"tx_packets_delta",tx_packets_delta); + field_to_json(Obj,"rx_packets_delta",rx_packets_delta); + field_to_json(Obj,"tx_failed_delta",tx_failed_delta); + field_to_json(Obj,"tx_retries_delta",tx_retries_delta); + field_to_json(Obj,"tx_duration_delta",tx_duration_delta); + } + + bool UETimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"station",station); + field_from_json(Obj,"rssi",rssi); + field_from_json(Obj,"tx_bytes",tx_bytes); + field_from_json(Obj,"rx_bytes",rx_bytes); + field_from_json(Obj,"tx_duration",tx_duration); + field_from_json(Obj,"rx_packets",rx_packets); + field_from_json(Obj,"tx_packets",tx_packets); + field_from_json(Obj,"tx_retries",tx_retries); + field_from_json(Obj,"tx_failed",tx_failed); + field_from_json(Obj,"connected",connected); + field_from_json(Obj,"inactive",inactive); + field_from_json(Obj,"tx_rate",tx_rate); + field_from_json(Obj,"rx_rate",rx_rate); +// field_from_json(Obj,"tidstats",tidstats); + field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_from_json(Obj,"tx_packets_bw",tx_packets_bw); + field_from_json(Obj,"rx_packets_bw",rx_packets_bw); + field_from_json(Obj,"tx_failed_pct",tx_failed_pct); + field_from_json(Obj,"tx_retries_pct",tx_retries_pct); + field_from_json(Obj,"tx_duration_pct",tx_duration_pct); + field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta); + field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta); + field_from_json(Obj,"tx_packets_delta",tx_packets_delta); + field_from_json(Obj,"rx_packets_delta",rx_packets_delta); + field_from_json(Obj,"tx_failed_delta",tx_failed_delta); + field_from_json(Obj,"tx_retries_delta",tx_retries_delta); + field_from_json(Obj,"tx_duration_delta",tx_duration_delta); + return true; + } catch(...) { + + } + return false; + } + + void APTimePoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"collisions",collisions); + field_to_json(Obj,"multicast",multicast); + field_to_json(Obj,"rx_bytes",rx_bytes); + field_to_json(Obj,"rx_dropped",rx_dropped); + field_to_json(Obj,"rx_errors",rx_errors); + field_to_json(Obj,"rx_packets",rx_packets); + field_to_json(Obj,"tx_bytes",tx_bytes); + field_to_json(Obj,"tx_packets",tx_packets); + field_to_json(Obj,"tx_dropped",tx_dropped); + field_to_json(Obj,"tx_errors",tx_errors); + field_to_json(Obj,"tx_packets",tx_packets); + + field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct); + field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct); + field_to_json(Obj,"rx_packets_bw",rx_packets_bw); + field_to_json(Obj,"tx_packets_bw",tx_packets_bw); + field_to_json(Obj,"rx_errors_pct",rx_errors_pct); + field_to_json(Obj,"tx_errors_pct",tx_errors_pct); + + field_to_json(Obj,"tx_bytes_delta",tx_bytes_delta); + field_to_json(Obj,"rx_bytes_delta",rx_bytes_delta); + field_to_json(Obj,"rx_dropped_delta",rx_dropped_delta); + field_to_json(Obj,"tx_dropped_delta",tx_dropped_delta); + field_to_json(Obj,"rx_packets_delta",rx_packets_delta); + field_to_json(Obj,"tx_packets_delta",tx_packets_delta); + field_to_json(Obj,"rx_errors_delta",rx_errors_delta); + field_to_json(Obj,"tx_errors_delta",tx_errors_delta); + } + + bool APTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"collisions",collisions); + field_from_json(Obj,"multicast",multicast); + field_from_json(Obj,"rx_bytes",rx_bytes); + field_from_json(Obj,"rx_dropped",rx_dropped); + field_from_json(Obj,"rx_errors",rx_errors); + field_from_json(Obj,"rx_packets",rx_packets); + field_from_json(Obj,"tx_bytes",tx_bytes); + field_from_json(Obj,"tx_packets",tx_packets); + field_from_json(Obj,"tx_dropped",tx_dropped); + field_from_json(Obj,"tx_errors",tx_errors); + field_from_json(Obj,"tx_packets",tx_packets); + + field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct); + field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct); + field_from_json(Obj,"rx_packets_bw",rx_packets_bw); + field_from_json(Obj,"tx_packets_bw",tx_packets_bw); + field_from_json(Obj,"rx_errors_pct",rx_errors_pct); + field_from_json(Obj,"tx_errors_pct",tx_errors_pct); + + field_from_json(Obj,"tx_bytes_delta",tx_bytes_delta); + field_from_json(Obj,"rx_bytes_delta",rx_bytes_delta); + field_from_json(Obj,"rx_dropped_delta",rx_dropped_delta); + field_from_json(Obj,"tx_dropped_delta",tx_dropped_delta); + field_from_json(Obj,"rx_packets_delta",rx_packets_delta); + field_from_json(Obj,"tx_packets_delta",tx_packets_delta); + field_from_json(Obj,"rx_errors_delta",rx_errors_delta); + field_from_json(Obj,"tx_errors_delta",tx_errors_delta); + + return true; + } catch(...) { + + } + return false; + } + + void TIDstat_entry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"rx_msdu",rx_msdu); + field_to_json(Obj,"tx_msdu",tx_msdu); + field_to_json(Obj,"tx_msdu_failed",tx_msdu_failed); + field_to_json(Obj,"tx_msdu_retries",tx_msdu_retries); + } + + bool TIDstat_entry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"rx_msdu",rx_msdu); + field_from_json(Obj,"tx_msdu",tx_msdu); + field_from_json(Obj,"tx_msdu_failed",tx_msdu_failed); + field_from_json(Obj,"tx_msdu_retries",tx_msdu_retries); + return true; + } catch(...) { + + } + return false; + } + + void RadioTimePoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"band",band); + field_to_json(Obj,"channel_width",channel_width); + field_to_json(Obj,"active_ms",active_ms); + field_to_json(Obj,"busy_ms",busy_ms); + field_to_json(Obj,"receive_ms",receive_ms); + field_to_json(Obj,"transmit_ms",transmit_ms); + field_to_json(Obj,"tx_power",tx_power); + field_to_json(Obj,"channel",channel); + field_to_json(Obj,"temperature",temperature); + field_to_json(Obj,"noise",noise); + field_to_json(Obj,"active_pct",active_pct); + field_to_json(Obj,"busy_pct",busy_pct); + field_to_json(Obj,"receive_pct",receive_pct); + field_to_json(Obj,"transmit_pct",transmit_pct); + } + + bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"band",band); + field_from_json(Obj,"channel_width",channel_width); + field_from_json(Obj,"active_ms",active_ms); + field_from_json(Obj,"busy_ms",busy_ms); + field_from_json(Obj,"receive_ms",receive_ms); + field_from_json(Obj,"transmit_ms",transmit_ms); + field_from_json(Obj,"tx_power",tx_power); + field_from_json(Obj,"channel",channel); + field_from_json(Obj,"temperature",temperature); + field_from_json(Obj,"noise",noise); + field_from_json(Obj,"active_pct",active_pct); + field_from_json(Obj,"busy_pct",busy_pct); + field_from_json(Obj,"receive_pct",receive_pct); + field_from_json(Obj,"transmit_pct",transmit_pct); + return true; + } catch(...) { + + } + return false; + } + + void AveragePoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"min",min); + field_to_json(Obj,"max",max); + field_to_json(Obj,"avg",avg); + } + + bool AveragePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"min",min); + field_from_json(Obj,"max",max); + field_from_json(Obj,"avg",avg); + return true; + } catch(...) { + + } + return false; + } + + void SSIDTimePoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"bssid",bssid); + field_to_json(Obj,"mode",mode); + field_to_json(Obj,"ssid",ssid); + field_to_json(Obj,"band",band); + field_to_json(Obj,"channel",channel); + field_to_json(Obj,"associations",associations); + field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_to_json(Obj,"tx_packets_bw",tx_packets_bw); + field_to_json(Obj,"rx_packets_bw",rx_packets_bw); + field_to_json(Obj,"tx_failed_pct",tx_failed_pct); + field_to_json(Obj,"tx_retries_pct",tx_retries_pct); + field_to_json(Obj,"tx_duration_pct",tx_duration_pct); + } + + bool SSIDTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"bssid",bssid); + field_from_json(Obj,"mode",mode); + field_from_json(Obj,"ssid",ssid); + field_from_json(Obj,"band",band); + field_from_json(Obj,"channel",channel); + field_from_json(Obj,"associations",associations); + field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_from_json(Obj,"tx_packets_bw",tx_packets_bw); + field_from_json(Obj,"rx_packets_bw",rx_packets_bw); + field_from_json(Obj,"tx_failed_pct",tx_failed_pct); + field_from_json(Obj,"tx_retries_pct",tx_retries_pct); + field_from_json(Obj,"tx_duration_pct",tx_duration_pct); + return true; + } catch(...) { + + } + return false; + } + + void DeviceTimePoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id",id); + field_to_json(Obj,"boardId",boardId); + field_to_json(Obj,"timestamp",timestamp); + field_to_json(Obj,"ap_data",ap_data); + field_to_json(Obj,"ssid_data",ssid_data); + field_to_json(Obj,"radio_data",radio_data); + field_to_json(Obj,"device_info",device_info); + field_to_json(Obj,"serialNumber",serialNumber); + } + + bool DeviceTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id",id); + field_from_json(Obj,"boardId",boardId); + field_from_json(Obj,"timestamp",timestamp); + field_from_json(Obj,"ap_data",ap_data); + field_from_json(Obj,"ssid_data",ssid_data); + field_from_json(Obj,"radio_data",radio_data); + field_from_json(Obj,"device_info",device_info); + field_from_json(Obj,"serialNumber",serialNumber); + return true; + } catch(...) { + + } + return false; + } + + void DeviceTimePointAnalysis::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"noise",noise); + field_to_json(Obj,"temperature",temperature); + field_to_json(Obj,"active_pct",active_pct); + field_to_json(Obj,"busy_pct",busy_pct); + field_to_json(Obj,"receive_pct",receive_pct); + field_to_json(Obj,"transmit_pct",transmit_pct); + field_to_json(Obj,"tx_power",tx_power); + field_to_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_to_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_to_json(Obj,"rx_dropped_pct",rx_dropped_pct); + field_to_json(Obj,"tx_dropped_pct",tx_dropped_pct); + field_to_json(Obj,"rx_packets_bw",rx_packets_bw); + field_to_json(Obj,"tx_packets_bw",tx_packets_bw); + field_to_json(Obj,"rx_errors_pct",rx_errors_pct); + field_to_json(Obj,"tx_errors_pct",tx_errors_pct); + } + + bool DeviceTimePointAnalysis::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"noise",noise); + field_from_json(Obj,"temperature",temperature); + field_from_json(Obj,"active_pct",active_pct); + field_from_json(Obj,"busy_pct",busy_pct); + field_from_json(Obj,"receive_pct",receive_pct); + field_from_json(Obj,"transmit_pct",transmit_pct); + field_from_json(Obj,"tx_power",tx_power); + field_from_json(Obj,"tx_bytes_bw",tx_bytes_bw); + field_from_json(Obj,"rx_bytes_bw",rx_bytes_bw); + field_from_json(Obj,"rx_dropped_pct",rx_dropped_pct); + field_from_json(Obj,"tx_dropped_pct",tx_dropped_pct); + field_from_json(Obj,"rx_packets_bw",rx_packets_bw); + field_from_json(Obj,"tx_packets_bw",tx_packets_bw); + field_from_json(Obj,"rx_errors_pct",rx_errors_pct); + field_from_json(Obj,"tx_errors_pct",tx_errors_pct); + return true; + } catch(...) { + + } + return false; + } + + void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"points",points); + field_to_json(Obj,"stats",stats); + } + + bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"points",points); + field_from_json(Obj,"stats",stats); + return true; + } catch(...) { + + } + return false; + } + + void DeviceTimePointStats::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"firstPoint",firstPoint); + field_to_json(Obj,"lastPoint",lastPoint); + field_to_json(Obj,"count",count); + } + + bool DeviceTimePointStats::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"firstPoint",firstPoint); + field_from_json(Obj,"lastPoint",lastPoint); + field_from_json(Obj,"count",count); + return true; + } catch(...) { + + } + return false; + } + + void WifiClientRate::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"bitrate",bitrate); + field_to_json(Obj,"chwidth",chwidth); + field_to_json(Obj,"mcs",mcs); + field_to_json(Obj,"nss",nss); + field_to_json(Obj,"vht",vht); + } + + bool WifiClientRate::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"bitrate",bitrate); + field_from_json(Obj,"chwidth",chwidth); + field_from_json(Obj,"mcs",mcs); + field_from_json(Obj,"nss",nss); + field_from_json(Obj,"vht",vht); + return true; + } catch(...) { + + } + return false; + } + + void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"timestamp",timestamp); + field_to_json(Obj,"station_id",station_id); + field_to_json(Obj,"bssid",bssid); + field_to_json(Obj,"ssid",ssid); + field_to_json(Obj,"rssi",rssi); + field_to_json(Obj,"rx_bitrate",rx_bitrate); + field_to_json(Obj,"rx_chwidth",rx_chwidth); + field_to_json(Obj,"rx_mcs",rx_mcs); + field_to_json(Obj,"rx_nss",rx_nss); + field_to_json(Obj,"rx_vht",rx_vht); + field_to_json(Obj,"tx_bitrate",tx_bitrate); + field_to_json(Obj,"tx_chwidth",tx_chwidth); + field_to_json(Obj,"tx_mcs",tx_mcs); + field_to_json(Obj,"tx_nss",tx_nss); + field_to_json(Obj,"tx_vht",tx_vht); + field_to_json(Obj,"rx_bytes",rx_bytes); + field_to_json(Obj,"tx_bytes",tx_bytes); + field_to_json(Obj,"rx_duration",rx_duration); + field_to_json(Obj,"tx_duration",tx_duration); + field_to_json(Obj,"rx_packets",rx_packets); + field_to_json(Obj,"tx_packets",tx_packets); + field_to_json(Obj,"ipv4",ipv4); + field_to_json(Obj,"ipv6",ipv6); + field_to_json(Obj,"channel_width",channel_width); + field_to_json(Obj,"noise",noise); + field_to_json(Obj,"tx_power",tx_power); + field_to_json(Obj,"channel",channel); + field_to_json(Obj,"active_ms",active_ms); + field_to_json(Obj,"busy_ms",busy_ms); + field_to_json(Obj,"receive_ms",receive_ms); + field_to_json(Obj,"mode",mode); + field_to_json(Obj,"ack_signal",ack_signal); + field_to_json(Obj,"ack_signal_avg",ack_signal_avg); + field_to_json(Obj,"connected",connected); + field_to_json(Obj,"inactive",inactive); + field_to_json(Obj,"tx_retries",tx_retries); + field_to_json(Obj,"venue_id",venue_id); + } + + bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"timestamp",timestamp); + field_from_json(Obj,"station_id",station_id); + field_from_json(Obj,"bssid",bssid); + field_from_json(Obj,"ssid",ssid); + field_from_json(Obj,"rssi",rssi); + field_from_json(Obj,"rx_bitrate",rx_bitrate); + field_from_json(Obj,"rx_chwidth",rx_chwidth); + field_from_json(Obj,"rx_mcs",rx_mcs); + field_from_json(Obj,"rx_nss",rx_nss); + field_from_json(Obj,"rx_vht",rx_vht); + field_from_json(Obj,"tx_bitrate",tx_bitrate); + field_from_json(Obj,"tx_chwidth",tx_chwidth); + field_from_json(Obj,"tx_mcs",tx_mcs); + field_from_json(Obj,"tx_nss",tx_nss); + field_from_json(Obj,"tx_vht",tx_vht); + field_from_json(Obj,"rx_bytes",rx_bytes); + field_from_json(Obj,"tx_bytes",tx_bytes); + field_from_json(Obj,"rx_duration",rx_duration); + field_from_json(Obj,"tx_duration",tx_duration); + field_from_json(Obj,"rx_packets",rx_packets); + field_from_json(Obj,"tx_packets",tx_packets); + field_from_json(Obj,"ipv4",ipv4); + field_from_json(Obj,"ipv6",ipv6); + field_from_json(Obj,"channel_width",channel_width); + field_from_json(Obj,"noise",noise); + field_from_json(Obj,"tx_power",tx_power); + field_from_json(Obj,"channel",channel); + field_from_json(Obj,"active_ms",active_ms); + field_from_json(Obj,"busy_ms",busy_ms); + field_from_json(Obj,"receive_ms",receive_ms); + field_from_json(Obj,"mode",mode); + field_from_json(Obj,"ack_signal",ack_signal); + field_from_json(Obj,"ack_signal_avg",ack_signal_avg); + field_from_json(Obj,"connected",connected); + field_from_json(Obj,"inactive",inactive); + field_from_json(Obj,"tx_retries",tx_retries); + field_from_json(Obj,"venue_id",venue_id); + return true; + } catch(...) { + + } + return false; + } +} \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.h b/microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.h new file mode 100644 index 0000000..c1328f4 --- /dev/null +++ b/microservice_sample/src/RESTObjects/RESTAPI_AnalyticsObjects.h @@ -0,0 +1,422 @@ +// +// Created by stephane bourque on 2022-01-10. +// + +#pragma once + +#include "RESTAPI_ProvObjects.h" +#include + +namespace OpenWifi { + + namespace AnalyticsObjects { + + struct Report { + uint64_t snapShot = 0; + + void reset(); + + void to_json(Poco::JSON::Object &Obj) const; + }; + + struct VenueInfo { + OpenWifi::Types::UUID_t id; + std::string name; + std::string description; + uint64_t retention = 0; + uint64_t interval = 0; + bool monitorSubVenues = false; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct BoardInfo { + ProvObjects::ObjectInfo info; + std::vector venueList; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + + inline bool operator<(const BoardInfo &bb) const { + return info.id < bb.info.id; + } + + inline bool operator==(const BoardInfo &bb) const { + return info.id == bb.info.id; + } + }; + + struct DeviceInfo { + std::string boardId; + std::string type; + std::string serialNumber; + std::string deviceType; + uint64_t lastContact = 0 ; + uint64_t lastPing = 0; + uint64_t lastState = 0; + std::string lastFirmware; + uint64_t lastFirmwareUpdate = 0; + uint64_t lastConnection = 0; + uint64_t lastDisconnection = 0; + uint64_t pings = 0; + uint64_t states = 0; + bool connected = false; + std::string connectionIp; + uint64_t associations_2g = 0; + uint64_t associations_5g = 0; + uint64_t associations_6g = 0; + uint64_t health = 0; + uint64_t lastHealth = 0; + std::string locale; + uint64_t uptime = 0; + double memory = 0.0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct DeviceInfoList { + std::vector devices; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + enum wifi_band { + band_2g = 0, band_5g = 1, band_6g = 2 + }; + + struct TIDstat_entry { + uint64_t rx_msdu = 0, + tx_msdu = 0, + tx_msdu_failed = 0, + tx_msdu_retries = 0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct UE_rate { + uint64_t bitrate=0; + uint64_t mcs=0; + uint64_t nss=0; + bool ht=false; + bool sgi=false; + uint64_t chwidth=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct AveragePoint { + double min = 0.0, + max = 0.0, + avg = 0.0; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct UETimePoint { + std::string station; + int64_t rssi = 0; + uint64_t tx_bytes = 0, + rx_bytes = 0, + tx_duration = 0, + rx_packets = 0, + tx_packets = 0, + tx_retries = 0, + tx_failed = 0, + connected = 0, + inactive = 0; + + double tx_bytes_bw = 0.0 , + rx_bytes_bw = 0.0 , + tx_packets_bw = 0.0 , + rx_packets_bw = 0.0 , + tx_failed_pct = 0.0 , + tx_retries_pct = 0.0 , + tx_duration_pct = 0.0; + + uint64_t tx_bytes_delta = 0, + rx_bytes_delta = 0, + tx_duration_delta = 0, + rx_packets_delta = 0, + tx_packets_delta = 0, + tx_retries_delta = 0, + tx_failed_delta = 0; + + UE_rate tx_rate, + rx_rate; + std::vector tidstats; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + enum SSID_MODES { + unknown = 0, + ap, + mesh, + sta, + wds_ap, + wds_sta, + wds_repeater + }; + + inline SSID_MODES SSID_Mode(const std::string &m) { + if (m == "ap") + return ap; + if (m == "sta") + return sta; + if (m == "mesh") + return mesh; + if (m == "wds-ap") + return wds_ap; + if (m == "wds-sta") + return wds_sta; + if (m == "wds-repeater") + return wds_repeater; + return unknown; + } + + struct SSIDTimePoint { + std::string bssid, + mode, + ssid; + uint64_t band=0, + channel=0; + std::vector associations; + + AveragePoint tx_bytes_bw, + rx_bytes_bw, + tx_packets_bw, + rx_packets_bw, + tx_failed_pct, + tx_retries_pct, + tx_duration_pct; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + + struct APTimePoint { + uint64_t collisions = 0, + multicast = 0, + rx_bytes = 0, + rx_dropped = 0, + rx_errors = 0, + rx_packets = 0, + tx_bytes = 0, + tx_dropped = 0, + tx_errors = 0, + tx_packets = 0; + + double tx_bytes_bw = 0.0 , + rx_bytes_bw = 0.0 , + rx_dropped_pct = 0.0, + tx_dropped_pct = 0.0, + rx_packets_bw = 0.0, + tx_packets_bw = 0.0, + rx_errors_pct = 0.0 , + tx_errors_pct = 0.0; + + uint64_t tx_bytes_delta = 0, + rx_bytes_delta = 0 , + rx_dropped_delta = 0, + tx_dropped_delta = 0, + rx_packets_delta = 0, + tx_packets_delta = 0, + rx_errors_delta = 0, + tx_errors_delta = 0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadioTimePoint { + uint64_t band = 0, + channel_width = 0; + uint64_t active_ms = 0, + busy_ms = 0, + receive_ms = 0, + transmit_ms = 0, + tx_power = 0, + channel = 0; + int64_t temperature = 0, + noise = 0; + + double active_pct = 0.0 , + busy_pct = 0.0, + receive_pct = 0.0, + transmit_pct = 0.0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + + struct DeviceTimePoint { + std::string id; + std::string boardId; + uint64_t timestamp = 0; + APTimePoint ap_data; + std::vector ssid_data; + std::vector radio_data; + AnalyticsObjects::DeviceInfo device_info; + std::string serialNumber; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + + inline bool operator<(const DeviceTimePoint &rhs) const { + if(timestamp < rhs.timestamp) + return true; + if(timestamp > rhs.timestamp) + return false; + if(device_info.serialNumber < rhs.device_info.serialNumber) + return true; + return false; + } + + inline bool operator==(const DeviceTimePoint &rhs) const { + return timestamp==rhs.timestamp && device_info.serialNumber==rhs.device_info.serialNumber; + } + + inline bool operator>(const DeviceTimePoint &rhs) const { + if(timestamp > rhs.timestamp) + return true; + if(timestamp < rhs.timestamp) + return false; + if(device_info.serialNumber > rhs.device_info.serialNumber) + return true; + return false; + } + + }; + + struct DeviceTimePointAnalysis { + uint64_t timestamp; + + AveragePoint noise; + AveragePoint temperature; + AveragePoint active_pct; + AveragePoint busy_pct; + AveragePoint receive_pct; + AveragePoint transmit_pct; + AveragePoint tx_power; + + AveragePoint tx_bytes_bw; + AveragePoint rx_bytes_bw; + AveragePoint rx_dropped_pct; + AveragePoint tx_dropped_pct; + AveragePoint rx_packets_bw; + AveragePoint tx_packets_bw; + AveragePoint rx_errors_pct; + AveragePoint tx_errors_pct; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + + }; + + struct DeviceTimePointList { + std::vector points; + std::vector stats; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct BandwidthAnalysisEntry { + uint64_t timestamp = 0; + + }; + + struct BandwidthAnalysis { + + }; + + struct AverageValueSigned { + int64_t peak=0, avg=0, low=0; + }; + + struct AverageValueUnsigned { + uint64_t peak=0, avg=0, low=0; + }; + + struct RadioAnalysis { + uint64_t timestamp=0; + AverageValueSigned noise, temperature; + AverageValueUnsigned active_ms, + busy_ms, + transmit_ms, + receive_ms; + }; + + struct DeviceTimePointStats { + uint64_t firstPoint=0; + uint64_t lastPoint=0; + uint64_t count=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct WifiClientRate { + uint32_t bitrate=0; + uint32_t chwidth=0; + uint16_t mcs=0; + uint16_t nss=0; + bool vht=false; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct WifiClientHistory { + uint64_t timestamp=OpenWifi::Now(); + std::string station_id; + std::string bssid; + std::string ssid; + int64_t rssi=0; + uint32_t rx_bitrate=0; + uint32_t rx_chwidth=0; + uint16_t rx_mcs=0; + uint16_t rx_nss=0; + bool rx_vht=false; + uint32_t tx_bitrate=0; + uint32_t tx_chwidth=0; + uint16_t tx_mcs=0; + uint16_t tx_nss=0; + bool tx_vht=false; + uint64_t rx_bytes=0; + uint64_t tx_bytes=0; + uint64_t rx_duration=0; + uint64_t tx_duration=0; + uint64_t rx_packets=0; + uint64_t tx_packets=0; + std::string ipv4; + std::string ipv6; + uint64_t channel_width=0; + int64_t noise=0; + uint64_t tx_power=0; + uint64_t channel=0; + uint64_t active_ms=0; + uint64_t busy_ms=0; + uint64_t receive_ms=0; + std::string mode; + int64_t ack_signal=0; + int64_t ack_signal_avg=0; + uint64_t connected=0; + uint64_t inactive=0; + uint64_t tx_retries=0; + std::string venue_id; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + } + +} \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_CertObjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_CertObjects.cpp new file mode 100644 index 0000000..ea55bd4 --- /dev/null +++ b/microservice_sample/src/RESTObjects/RESTAPI_CertObjects.cpp @@ -0,0 +1,208 @@ +// +// Created by stephane bourque on 2021-12-07. +// + +#include "RESTAPI_CertObjects.h" +#include "framework/MicroService.h" + +using OpenWifi::RESTAPI_utils::field_to_json; +using OpenWifi::RESTAPI_utils::field_from_json; + +namespace OpenWifi::CertObjects { + void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id", id); + field_to_json(Obj,"entity", entity); + field_to_json(Obj,"creator", creator); + field_to_json(Obj,"type", type); + field_to_json(Obj,"status", status); + field_to_json(Obj,"certificate", certificate); + field_to_json(Obj,"key", key); + field_to_json(Obj,"devid", devid); + field_to_json(Obj,"cas", cas); + field_to_json(Obj,"manufacturer", manufacturer); + field_to_json(Obj,"model", model); + field_to_json(Obj,"redirector", redirector); + field_to_json(Obj,"commonName", commonName); + field_to_json(Obj,"certificateId", certificateId); + field_to_json(Obj,"batch", batch); + field_to_json(Obj,"created", created); + field_to_json(Obj,"modified", modified); + field_to_json(Obj,"revoked", revoked); + field_to_json(Obj,"revokeCount", revokeCount); + field_to_json(Obj,"synched", synched); + } + + bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id", id); + field_from_json(Obj,"entity", entity); + field_from_json(Obj,"creator", creator); + field_from_json(Obj,"type", type); + field_from_json(Obj,"status", status); + field_from_json(Obj,"certificate", certificate); + field_from_json(Obj,"key", key); + field_from_json(Obj,"devid", devid); + field_from_json(Obj,"cas", cas); + field_from_json(Obj,"manufacturer", manufacturer); + field_from_json(Obj,"model", model); + field_from_json(Obj,"redirector", redirector); + field_from_json(Obj,"commonName", commonName); + field_from_json(Obj,"certificateId", certificateId); + field_from_json(Obj,"batch", batch); + field_from_json(Obj,"created", created); + field_from_json(Obj,"modified", modified); + field_from_json(Obj,"revoked", revoked); + field_from_json(Obj,"revokeCount", revokeCount); + field_from_json(Obj,"synched", synched); + return true; + } catch (...) { + } + return false; + } + + void EntityEntry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id", id); + field_to_json(Obj,"creator", creator); + field_to_json(Obj,"name", name); + field_to_json(Obj,"description", description); + field_to_json(Obj,"defaultRedirector", defaultRedirector); + field_to_json(Obj,"apiKey", apiKey); + field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); + field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); + field_to_json(Obj,"organization", organization); + field_to_json(Obj,"created", created); + field_to_json(Obj,"modified", modified); + field_to_json(Obj,"suspended", suspended); + field_to_json(Obj,"deleted", deleted); + field_to_json(Obj,"notes", notes); + } + + bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id", id); + field_from_json(Obj,"creator", creator); + field_from_json(Obj,"name", name); + field_from_json(Obj,"description", description); + field_from_json(Obj,"defaultRedirector", defaultRedirector); + field_from_json(Obj,"apiKey", apiKey); + field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); + field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); + field_from_json(Obj,"organization", organization); + field_from_json(Obj,"created", created); + field_from_json(Obj,"modified", modified); + field_from_json(Obj,"suspended", suspended); + field_from_json(Obj,"deleted", deleted); + field_from_json(Obj,"notes", notes); + return true; + } catch (...) { + } + return false; + } + + void BatchEntry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id", id); + field_to_json(Obj,"entity", entity); + field_to_json(Obj,"creator", creator); + field_to_json(Obj,"name", name); + field_to_json(Obj,"description", description); + field_to_json(Obj,"manufacturer", manufacturer); + field_to_json(Obj,"model", model); + field_to_json(Obj,"redirector", redirector); + field_to_json(Obj,"commonNames", commonNames); + field_to_json(Obj,"jobHistory", jobHistory); + field_to_json(Obj,"notes", notes); + field_to_json(Obj,"submitted", submitted); + field_to_json(Obj,"started", started); + field_to_json(Obj,"completed", completed); + field_to_json(Obj,"modified", modified); + } + + bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id", id); + field_from_json(Obj,"entity", entity); + field_from_json(Obj,"creator", creator); + field_from_json(Obj,"name", name); + field_from_json(Obj,"description", description); + field_from_json(Obj,"manufacturer", manufacturer); + field_from_json(Obj,"model", model); + field_from_json(Obj,"redirector", redirector); + field_from_json(Obj,"commonNames", commonNames); + field_from_json(Obj,"jobHistory", jobHistory); + field_from_json(Obj,"notes", notes); + field_from_json(Obj,"submitted", submitted); + field_from_json(Obj,"started", started); + field_from_json(Obj,"completed", completed); + field_from_json(Obj,"modified", modified); + return true; + } catch (...) { + } + return false; + } + + void JobEntry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id", id); + field_to_json(Obj,"entity", entity); + field_to_json(Obj,"creator", creator); + field_to_json(Obj,"batch", batch); + field_to_json(Obj,"commonNames", commonNames); + field_to_json(Obj,"completedNames", completedNames); + field_to_json(Obj,"errorNames", errorNames); + field_to_json(Obj,"status", status); + field_to_json(Obj,"command", command); + field_to_json(Obj,"parameters", parameters); + field_to_json(Obj,"submitted", submitted); + field_to_json(Obj,"started", started); + field_to_json(Obj,"completed", completed); + } + + bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id", id); + field_from_json(Obj,"entity", entity); + field_from_json(Obj,"creator", creator); + field_from_json(Obj,"batch", batch); + field_from_json(Obj,"commonNames", commonNames); + field_from_json(Obj,"completedNames", completedNames); + field_from_json(Obj,"errorNames", errorNames); + field_from_json(Obj,"status", status); + field_from_json(Obj,"command", command); + field_from_json(Obj,"parameters", parameters); + field_from_json(Obj,"submitted", submitted); + field_from_json(Obj,"started", started); + field_from_json(Obj,"completed", completed); + return true; + } catch (...) { + } + return false; + } + + void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "year", year); + field_to_json(Obj, "activeCerts", activeCerts); + field_to_json(Obj, "revokedCerts", revokedCerts); + } + + void Dashboard::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"snapshot", snapshot); + field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts); + field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts); + field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization); + field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization); + field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors); + field_to_json(Obj,"deviceTypes", deviceTypes); + field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts); + field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear); + } + + void Dashboard::reset() { + snapshot=0; + numberOfRevokedCerts = numberOfIssuedCerts = 0; + activeCertsPerOrganization.clear(); + revokedCertsPerOrganization.clear(); + numberOfRedirectors.clear(); + deviceTypes.clear(); + monthlyNumberOfCerts.clear(); + monthlyNumberOfCertsPerOrgPerYear.clear(); + } +} \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_CertObjects.h b/microservice_sample/src/RESTObjects/RESTAPI_CertObjects.h new file mode 100644 index 0000000..40b75a0 --- /dev/null +++ b/microservice_sample/src/RESTObjects/RESTAPI_CertObjects.h @@ -0,0 +1,122 @@ +// +// Created by stephane bourque on 2021-12-07. +// + +#pragma once + +#include +#include "framework/OpenWifiTypes.h" +#include "RESTObjects/RESTAPI_SecurityObjects.h" + +namespace OpenWifi::CertObjects { + + struct CertificateEntry { + OpenWifi::Types::UUID_t id; + OpenWifi::Types::UUID_t entity; + OpenWifi::Types::UUID_t creator; + std::string type; + std::string status; + std::string certificate; + std::string key; + std::string devid; + std::string cas; + std::string manufacturer; + std::string model; + std::string redirector; + std::string commonName; + std::string certificateId; + OpenWifi::Types::UUID_t batch; + uint64_t created = 0; + uint64_t modified = 0; + uint64_t revoked = 0; + uint64_t revokeCount = 0; + uint64_t synched = 0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct EntityEntry { + OpenWifi::Types::UUID_t id; + OpenWifi::Types::UUID_t creator; + std::string name; + std::string description; + std::string defaultRedirector; + std::string apiKey; + std::string serverEnrollmentProfile; + std::string clientEnrollmentProfile; + std::string organization; + SecurityObjects::NoteInfoVec notes; + bool suspended=false; + bool deleted=false; + uint64_t created = 0 ; + uint64_t modified = 0 ; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct BatchEntry { + OpenWifi::Types::UUID_t id; + OpenWifi::Types::UUID_t entity; + OpenWifi::Types::UUID_t creator; + std::string name; + std::string description; + std::string manufacturer; + std::string model; + std::string redirector; + std::vector commonNames; + std::vector jobHistory; + SecurityObjects::NoteInfoVec notes; + uint64_t submitted = 0 ; + uint64_t started = 0 ; + uint64_t completed = 0 ; + uint64_t modified = 0 ; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct JobEntry { + OpenWifi::Types::UUID_t id; + OpenWifi::Types::UUID_t entity; + OpenWifi::Types::UUID_t creator; + OpenWifi::Types::UUID_t batch; + std::string command; + OpenWifi::Types::StringVec commonNames; + OpenWifi::Types::StringVec completedNames; + OpenWifi::Types::StringVec errorNames; + Types::StringPairVec parameters; + std::string status; + uint64_t submitted=0; + uint64_t started=0; + uint64_t completed=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct DashBoardYearlyStats { + uint64_t year=0; + OpenWifi::Types::Counted3DMapSII activeCerts; + OpenWifi::Types::Counted3DMapSII revokedCerts; + + void to_json(Poco::JSON::Object &Obj) const; + }; + + struct Dashboard { + uint64_t snapshot=0; + uint64_t numberOfIssuedCerts=0; + uint64_t numberOfRevokedCerts=0; + OpenWifi::Types::CountedMap activeCertsPerOrganization; + OpenWifi::Types::CountedMap revokedCertsPerOrganization; + OpenWifi::Types::CountedMap numberOfRedirectors; + OpenWifi::Types::CountedMap deviceTypes; + OpenWifi::Types::CountedMap monthlyNumberOfCerts; + std::vector monthlyNumberOfCertsPerOrgPerYear; + + void to_json(Poco::JSON::Object &Obj) const; + void reset(); + }; + +} \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.cpp index 78d0062..ceb3619 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.cpp +++ b/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.cpp @@ -233,10 +233,10 @@ namespace OpenWifi::FMSObjects { UnknownFirmwares_.clear(); totalSecondsOld_.clear(); numberOfDevices = 0 ; - snapshot = std::time(nullptr); + snapshot = OpenWifi::Now(); } - bool DeviceReport::from_json(const Poco::JSON::Object::Ptr &Obj) { + bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { try { return true; @@ -245,4 +245,65 @@ namespace OpenWifi::FMSObjects { } return false; } + + void DeviceInformation::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "serialNumber",serialNumber); + field_to_json(Obj, "history", history); + field_to_json(Obj, "currentFirmware", currentFirmware); + field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate); + field_to_json(Obj, "latestFirmware", latestFirmware); + field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate); + field_to_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable); + field_to_json(Obj, "latestFirmwareURI",latestFirmwareURI); + } + + bool DeviceInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "serialNumber",serialNumber); + field_from_json(Obj, "history", history); + field_from_json(Obj, "currentFirmware", currentFirmware); + field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate); + field_from_json(Obj, "latestFirmware", latestFirmware); + field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate); + field_from_json(Obj, "latestFirmwareAvailable",latestFirmwareAvailable); + field_from_json(Obj, "latestFirmwareURI",latestFirmwareURI); + return true; + } catch(...) { + + } + return false; + } + + void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "serialNumber",serialNumber); + field_to_json(Obj, "revision", revision); + field_to_json(Obj, "upgraded", upgraded); + } + + bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "serialNumber",serialNumber); + field_from_json(Obj, "revision", revision); + field_from_json(Obj, "upgraded", upgraded); + return true; + } catch(...) { + + } + return false; + } + + void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "devices",devices); + } + + bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "devices",devices); + return true; + } catch(...) { + + } + return false; + } + } diff --git a/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.h b/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.h index 86dfb70..60aea5f 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.h +++ b/microservice_sample/src/RESTObjects/RESTAPI_FMSObjects.h @@ -4,9 +4,7 @@ #include -#ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H -#define UCENTRALFMS_RESTAPI_FMSOBJECTS_H - +#pragma once #include "RESTAPI_SecurityObjects.h" #include "framework/OpenWifiTypes.h" @@ -127,7 +125,35 @@ namespace OpenWifi::FMSObjects { void reset(); bool from_json(const Poco::JSON::Object::Ptr &Obj); }; + + struct DeviceInformation { + std::string serialNumber; + RevisionHistoryEntryList history; + std::string currentFirmware; + uint64_t currentFirmwareDate=0; + std::string latestFirmware; + uint64_t latestFirmwareDate=0; + bool latestFirmwareAvailable; + std::string latestFirmwareURI; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct DeviceCurrentInfo { + std::string serialNumber; + std::string revision; + uint64_t upgraded=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct DeviceCurrentInfoList { + std::vector devices; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + } - - -#endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H diff --git a/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.cpp index 24dd4ef..d293b88 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.cpp +++ b/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.cpp @@ -27,7 +27,7 @@ namespace OpenWifi::GWObjects { void Device::to_json(Poco::JSON::Object &Obj) const { field_to_json(Obj,"serialNumber", SerialNumber); #ifdef TIP_GATEWAY_SERVICE - field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible)); + field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->GetPlatform(Compatible)); #endif field_to_json(Obj,"macAddress", MACAddress); field_to_json(Obj,"manufacturer", Manufacturer); @@ -45,6 +45,10 @@ namespace OpenWifi::GWObjects { field_to_json(Obj,"compatible", Compatible); field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy); field_to_json(Obj,"devicePassword", DevicePassword); + field_to_json(Obj,"subscriber", subscriber); + field_to_json(Obj,"entity", entity); + field_to_json(Obj,"modified", modified); + field_to_json(Obj,"locale", locale); } void Device::to_json_with_status(Poco::JSON::Object &Obj) const { @@ -69,7 +73,7 @@ namespace OpenWifi::GWObjects { #endif } - bool Device::from_json(Poco::JSON::Object::Ptr &Obj) { + bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"serialNumber",SerialNumber); field_from_json(Obj,"deviceType",DeviceType); @@ -81,6 +85,9 @@ namespace OpenWifi::GWObjects { field_from_json(Obj,"location",Location); field_from_json(Obj,"venue",Venue); field_from_json(Obj,"compatible",Compatible); + field_from_json(Obj,"subscriber", subscriber); + field_from_json(Obj,"entity", entity); + field_from_json(Obj,"locale", locale); return true; } catch (const Poco::Exception &E) { } @@ -146,9 +153,10 @@ namespace OpenWifi::GWObjects { field_to_json(Obj,"custom", Custom); field_to_json(Obj,"waitingForFile", WaitingForFile); field_to_json(Obj,"attachFile", AttachDate); + field_to_json(Obj,"executionTime", executionTime); } - bool DefaultConfiguration::from_json(Poco::JSON::Object::Ptr &Obj) { + bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"name",Name); field_from_json(Obj,"configuration",Configuration); @@ -167,7 +175,7 @@ namespace OpenWifi::GWObjects { field_to_json(Obj,"created", created); } - bool BlackListedDevice::from_json(Poco::JSON::Object::Ptr &Obj) { + bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"serialNumber",serialNumber); field_from_json(Obj,"author",author); @@ -180,7 +188,6 @@ namespace OpenWifi::GWObjects { } void ConnectionState::to_json(Poco::JSON::Object &Obj) const { - field_to_json(Obj,"serialNumber", SerialNumber); field_to_json(Obj,"ipAddress", Address); field_to_json(Obj,"txBytes", TX); field_to_json(Obj,"rxBytes", RX); @@ -191,6 +198,11 @@ namespace OpenWifi::GWObjects { field_to_json(Obj,"lastContact", LastContact); field_to_json(Obj,"associations_2G", Associations_2G); field_to_json(Obj,"associations_5G", Associations_5G); + field_to_json(Obj,"webSocketClients", webSocketClients); + field_to_json(Obj,"websocketPackets", websocketPackets); + field_to_json(Obj,"kafkaClients", kafkaClients); + field_to_json(Obj,"kafkaPackets", kafkaPackets); + field_to_json(Obj,"locale", locale); switch(VerifiedCertificate) { case NO_CERTIFICATE: @@ -252,7 +264,7 @@ namespace OpenWifi::GWObjects { lastContact.clear(); associations.clear(); numberOfDevices = 0 ; - snapshot = std::time(nullptr); + snapshot = OpenWifi::Now(); } void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{ @@ -260,5 +272,124 @@ namespace OpenWifi::GWObjects { field_to_json(Obj,"capabilities", capabilities); }; + void ScriptRequest::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"serialNumber",serialNumber); + field_to_json(Obj,"timeout",timeout); + field_to_json(Obj,"type",type); + field_to_json(Obj,"script",script); + field_to_json(Obj,"scriptId",scriptId); + field_to_json(Obj,"when",when); + } + + bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"serialNumber",serialNumber); + field_from_json(Obj,"timeout",timeout); + field_from_json(Obj,"type",type); + field_from_json(Obj,"script",script); + field_from_json(Obj,"scriptId",scriptId); + field_from_json(Obj,"when",when); + return true; + } catch (const Poco::Exception &E) { + } + return false; + + } + + void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"pools",pools); + } + + bool RadiusProxyPoolList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"pools",pools); + return true; + } catch (const Poco::Exception &E) { + } + return false; + } + + void RadiusProxyPool::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"name",name); + field_to_json(Obj,"description",description); + field_to_json(Obj,"authConfig",authConfig); + field_to_json(Obj,"acctConfig",acctConfig); + field_to_json(Obj,"coaConfig",coaConfig); + field_to_json(Obj,"useByDefault",useByDefault); + } + + bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"name",name); + field_from_json(Obj,"description",description); + field_from_json(Obj,"authConfig",authConfig); + field_from_json(Obj,"acctConfig",acctConfig); + field_from_json(Obj,"coaConfig",coaConfig); + field_from_json(Obj,"useByDefault",useByDefault); + return true; + } catch (const Poco::Exception &E) { + } + return false; + } + + void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"strategy",strategy); + field_to_json(Obj,"monitor",monitor); + field_to_json(Obj,"monitorMethod",monitorMethod); + field_to_json(Obj,"methodParameters",methodParameters); + field_to_json(Obj,"servers",servers); + } + + bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"strategy",strategy); + field_from_json(Obj,"monitor",monitor); + field_from_json(Obj,"monitorMethod",monitorMethod); + field_from_json(Obj,"methodParameters",methodParameters); + field_from_json(Obj,"servers",servers); + return true; + } catch (const Poco::Exception &E) { + } + return false; + } + + void RadiusProxyServerEntry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"name",name); + field_to_json(Obj,"ip",ip); + field_to_json(Obj,"port",port); + field_to_json(Obj,"weight",weight); + field_to_json(Obj,"secret",secret); + field_to_json(Obj,"certificate",certificate); + field_to_json(Obj,"radsec",radsec); + field_to_json(Obj,"radsecPort",radsecPort); + field_to_json(Obj,"radsecSecret",radsecSecret); + field_to_json(Obj,"radsecCacerts",radsecCacerts); + field_to_json(Obj,"radsecCert",radsecCert); + field_to_json(Obj,"radsecKey",radsecKey); + field_to_json(Obj,"radsecRealms",radsecRealms); + field_to_json(Obj,"ignore",ignore); + } + + bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"name",name); + field_from_json(Obj,"ip",ip); + field_from_json(Obj,"port",port); + field_from_json(Obj,"weight",weight); + field_from_json(Obj,"secret",secret); + field_from_json(Obj,"certificate",certificate); + field_from_json(Obj,"radsec",radsec); + field_from_json(Obj,"radsecSecret",radsecSecret); + field_from_json(Obj,"radsecPort",radsecPort); + field_from_json(Obj,"radsecCacerts",radsecCacerts); + field_from_json(Obj,"radsecCert",radsecCert); + field_from_json(Obj,"radsecKey",radsecKey); + field_from_json(Obj,"radsecRealms",radsecRealms); + field_from_json(Obj,"ignore",ignore); + return true; + } catch (const Poco::Exception &E) { + } + return false; + } } diff --git a/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.h b/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.h index 5485357..3f893b7 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.h +++ b/microservice_sample/src/RESTObjects/RESTAPI_GWobjects.h @@ -22,7 +22,6 @@ namespace OpenWifi::GWObjects { struct ConnectionState { uint64_t MessageCount = 0 ; - std::string SerialNumber; std::string Address; uint64_t UUID = 0 ; uint64_t PendingUUID = 0 ; @@ -34,6 +33,11 @@ namespace OpenWifi::GWObjects { std::string Firmware; CertificateValidation VerifiedCertificate = NO_CERTIFICATE; std::string Compatible; + uint64_t kafkaClients=0; + uint64_t webSocketClients=0; + uint64_t kafkaPackets=0; + uint64_t websocketPackets=0; + std::string locale; void to_json(Poco::JSON::Object &Obj) const; }; @@ -49,40 +53,45 @@ namespace OpenWifi::GWObjects { std::string Firmware; std::string Compatible; std::string FWUpdatePolicy; - uint64_t UUID; - uint64_t CreationTimestamp; - uint64_t LastConfigurationChange; - uint64_t LastConfigurationDownload; - uint64_t LastFWUpdate; + uint64_t UUID = 0 ; + uint64_t CreationTimestamp = 0 ; + uint64_t LastConfigurationChange = 0 ; + uint64_t LastConfigurationDownload = 0 ; + uint64_t LastFWUpdate = 0 ; std::string Venue; std::string DevicePassword; + std::string subscriber; + std::string entity; + uint64_t modified=0; + std::string locale; + void to_json(Poco::JSON::Object &Obj) const; void to_json_with_status(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); + bool from_json(const Poco::JSON::Object::Ptr &Obj); void Print() const; }; struct Statistics { std::string SerialNumber; - uint64_t UUID; + uint64_t UUID = 0 ; std::string Data; - uint64_t Recorded; + uint64_t Recorded = 0; void to_json(Poco::JSON::Object &Obj) const; }; struct HealthCheck { std::string SerialNumber; - uint64_t UUID; + uint64_t UUID = 0 ; std::string Data; - uint64_t Recorded; - uint64_t Sanity; + uint64_t Recorded = 0 ; + uint64_t Sanity = 0 ; void to_json(Poco::JSON::Object &Obj) const; }; struct Capabilities { std::string Capabilities; - uint64_t FirstUpdate; - uint64_t LastUpdate; + uint64_t FirstUpdate = 0 ; + uint64_t LastUpdate = 0 ; void to_json(Poco::JSON::Object &Obj) const; }; @@ -100,10 +109,10 @@ namespace OpenWifi::GWObjects { std::string SerialNumber; std::string Log; std::string Data; - uint64_t Severity; - uint64_t Recorded; - uint64_t LogType; - uint64_t UUID; + uint64_t Severity = 0 ; + uint64_t Recorded = 0 ; + uint64_t LogType = 0 ; + uint64_t UUID = 0 ; void to_json(Poco::JSON::Object &Obj) const; }; @@ -115,7 +124,7 @@ namespace OpenWifi::GWObjects { uint64_t Created; uint64_t LastModified; void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; struct CommandDetails { @@ -137,6 +146,7 @@ namespace OpenWifi::GWObjects { uint64_t AttachDate = 0 ; uint64_t AttachSize = 0 ; std::string AttachType; + double executionTime = 0.0; void to_json(Poco::JSON::Object &Obj) const; }; @@ -146,26 +156,26 @@ namespace OpenWifi::GWObjects { std::string author; uint64_t created; void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; struct RttySessionDetails { std::string SerialNumber; std::string Server; - uint64_t Port; + uint64_t Port = 0 ; std::string Token; - uint64_t TimeOut; + uint64_t TimeOut = 0 ; std::string ConnectionId; - uint64_t Started; + uint64_t Started = 0 ; std::string CommandUUID; - uint64_t ViewPort; + uint64_t ViewPort = 0 ; std::string DevicePassword; void to_json(Poco::JSON::Object &Obj) const; }; struct Dashboard { - uint64_t snapshot; - uint64_t numberOfDevices; + uint64_t snapshot = 0 ; + uint64_t numberOfDevices = 0 ; Types::CountedMap commands; Types::CountedMap upTimes; Types::CountedMap memoryUsed; @@ -189,4 +199,65 @@ namespace OpenWifi::GWObjects { void to_json(Poco::JSON::Object &Obj) const; }; + + struct ScriptRequest { + uint64_t timeout=30; + std::string serialNumber; + std::string type; + std::string script; + std::string scriptId; + uint64_t when=0; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadiusProxyServerEntry { + std::string name; + std::string ip; + uint16_t port=0; + uint64_t weight=0; + std::string secret; + std::string certificate; + bool radsec=false; + uint16_t radsecPort=2083; + std::string radsecSecret; + std::string radsecKey; + std::string radsecCert; + std::vector radsecCacerts; + std::vector radsecRealms; + bool ignore=false; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadiusProxyServerConfig { + std::string strategy; + bool monitor=false; + std::string monitorMethod; + std::vector methodParameters; + std::vector servers; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadiusProxyPool { + std::string name; + std::string description; + RadiusProxyServerConfig authConfig; + RadiusProxyServerConfig acctConfig; + RadiusProxyServerConfig coaConfig; + bool useByDefault=false; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadiusProxyPoolList { + std::vector pools; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; } diff --git a/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.cpp index 3f76c8f..948c787 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.cpp +++ b/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.cpp @@ -91,8 +91,13 @@ namespace OpenWifi::ProvObjects { field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"deviceConfiguration",deviceConfiguration); field_to_json( Obj,"devices",devices); - field_to_json( Obj,"rrm",rrm); + field_to_json( Obj,"deviceRules",deviceRules); field_to_json( Obj,"sourceIP",sourceIP); + field_to_json( Obj,"variables", variables); + field_to_json( Obj,"managementPolicies", managementPolicies); + field_to_json( Obj,"managementRoles", managementRoles); + field_to_json( Obj,"maps", maps); + field_to_json( Obj,"configurations", configurations); } bool Entity::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -106,8 +111,13 @@ namespace OpenWifi::ProvObjects { field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"deviceConfiguration",deviceConfiguration); field_from_json( Obj,"devices",devices); - field_from_json( Obj,"rrm",rrm); + field_from_json( Obj,"deviceRules",deviceRules); field_from_json( Obj,"sourceIP",sourceIP); + field_from_json( Obj,"variables", variables); + field_from_json( Obj,"managementPolicies", managementPolicies); + field_from_json( Obj,"managementRoles", managementRoles); + field_from_json( Obj,"maps", maps); + field_from_json( Obj,"configurations", configurations); return true; } catch(...) { @@ -142,10 +152,16 @@ namespace OpenWifi::ProvObjects { field_to_json( Obj,"design",design); field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"deviceConfiguration",deviceConfiguration); - field_to_json( Obj,"contact",contact); + field_to_json( Obj,"contacts",contacts); field_to_json( Obj,"location",location); - field_to_json( Obj,"rrm",rrm); + field_to_json( Obj,"deviceRules",deviceRules); field_to_json( Obj,"sourceIP",sourceIP); + field_to_json( Obj,"variables", variables); + field_to_json( Obj,"managementPolicies", managementPolicies); + field_to_json( Obj,"managementRoles", managementRoles); + field_to_json( Obj,"maps", maps); + field_to_json( Obj,"configurations", configurations); + field_to_json( Obj,"boards", boards); } bool Venue::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -160,10 +176,16 @@ namespace OpenWifi::ProvObjects { field_from_json( Obj,"design",design); field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"deviceConfiguration",deviceConfiguration); - field_from_json( Obj,"contact",contact); + field_from_json( Obj,"contacts",contacts); field_from_json( Obj,"location",location); - field_from_json( Obj,"rrm",rrm); + field_from_json( Obj,"deviceRules",deviceRules); field_from_json( Obj,"sourceIP",sourceIP); + field_from_json( Obj,"variables", variables); + field_from_json( Obj,"managementPolicies", managementPolicies); + field_from_json( Obj,"managementRoles", managementRoles); + field_from_json( Obj,"maps", maps); + field_from_json( Obj,"configurations", configurations); + field_from_json( Obj,"boards", boards); return true; } catch (...) { @@ -171,6 +193,89 @@ namespace OpenWifi::ProvObjects { return false; } + void Operator::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"managementPolicy",managementPolicy); + field_to_json( Obj,"managementRoles",managementRoles); + field_to_json( Obj,"deviceRules",deviceRules); + field_to_json( Obj,"variables",variables); + field_to_json( Obj,"defaultOperator",defaultOperator); + field_to_json( Obj,"sourceIP",sourceIP); + field_to_json( Obj,"registrationId",registrationId); + } + + bool Operator::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"managementPolicy",managementPolicy); + field_from_json( Obj,"managementRoles",managementRoles); + field_from_json( Obj,"deviceRules",deviceRules); + field_from_json( Obj,"variables",variables); + field_from_json( Obj,"defaultOperator",defaultOperator); + field_from_json( Obj,"sourceIP",sourceIP); + field_from_json( Obj,"registrationId",registrationId); + return true; + } catch(...) { + } + return false; + } + + void OperatorList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"operators",operators); + } + + bool OperatorList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"operators",operators); + return true; + } catch(...) { + } + return false; + } + + void ServiceClass::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"operatorId",operatorId); + field_to_json( Obj,"managementPolicy",managementPolicy); + field_to_json( Obj,"cost",cost); + field_to_json( Obj,"currency",currency); + field_to_json( Obj,"period",period); + field_to_json( Obj,"billingCode",billingCode); + field_to_json( Obj,"variables",variables); + field_to_json( Obj,"defaultService",defaultService); + } + + bool ServiceClass::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"operatorId",operatorId); + field_from_json( Obj,"managementPolicy",managementPolicy); + field_from_json( Obj,"cost",cost); + field_from_json( Obj,"currency",currency); + field_from_json( Obj,"period",period); + field_from_json( Obj,"billingCode",billingCode); + field_from_json( Obj,"variables",variables); + field_from_json( Obj,"defaultService",defaultService); + return true; + } catch(...) { + } + return false; + + } + + void ServiceClassList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"serviceClasses",serviceClasses); + } + + bool ServiceClassList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"serviceClasses",serviceClasses); + return true; + } catch(...) { + } + return false; + } + void UserInfoDigest::to_json(Poco::JSON::Object &Obj) const { field_to_json( Obj,"id",id); field_to_json( Obj,"entity",loginId); @@ -193,6 +298,7 @@ namespace OpenWifi::ProvObjects { field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"users",users); field_to_json( Obj,"entity",entity); + field_to_json( Obj,"venue",venue); } bool ManagementRole::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -201,6 +307,7 @@ namespace OpenWifi::ProvObjects { field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"users",users); field_from_json( Obj,"entity",entity); + field_from_json( Obj,"venue",venue); return true; } catch(...) { } @@ -249,6 +356,92 @@ namespace OpenWifi::ProvObjects { return false; } + void OperatorLocation::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"type",type); + field_to_json( Obj,"buildingName",buildingName); + field_to_json( Obj,"addressLines",addressLines); + field_to_json( Obj,"city",city); + field_to_json( Obj,"state",state); + field_to_json( Obj,"postal",postal); + field_to_json( Obj,"country",country); + field_to_json( Obj,"phones",phones); + field_to_json( Obj,"mobiles",mobiles); + field_to_json( Obj,"geoCode",geoCode); + field_to_json( Obj,"operatorId",operatorId); + field_to_json( Obj,"subscriberDeviceId",subscriberDeviceId); + field_to_json( Obj,"managementPolicy",managementPolicy); + } + + bool OperatorLocation::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"type", type); + field_from_json( Obj,"buildingName",buildingName); + field_from_json( Obj,"addressLines",addressLines); + field_from_json( Obj,"city",city); + field_from_json( Obj,"state",state); + field_from_json( Obj,"postal",postal); + field_from_json( Obj,"country",country); + field_from_json( Obj,"phones",phones); + field_from_json( Obj,"mobiles",mobiles); + field_from_json( Obj,"geoCode",geoCode); + field_from_json( Obj,"operatorId",operatorId); + field_from_json( Obj,"subscriberDeviceId",subscriberDeviceId); + field_from_json( Obj,"managementPolicy",managementPolicy); + return true; + } catch (...) { + + } + return false; + } + + void SubLocation::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"type",type); + field_to_json( Obj,"buildingName",buildingName); + field_to_json( Obj,"addressLines",addressLines); + field_to_json( Obj,"city",city); + field_to_json( Obj,"state",state); + field_to_json( Obj,"postal",postal); + field_to_json( Obj,"country",country); + field_to_json( Obj,"phones",phones); + field_to_json( Obj,"mobiles",mobiles); + field_to_json( Obj,"geoCode",geoCode); + } + + bool SubLocation::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"type", type); + field_from_json( Obj,"buildingName",buildingName); + field_from_json( Obj,"addressLines",addressLines); + field_from_json( Obj,"city",city); + field_from_json( Obj,"state",state); + field_from_json( Obj,"postal",postal); + field_from_json( Obj,"country",country); + field_from_json( Obj,"phones",phones); + field_from_json( Obj,"mobiles",mobiles); + field_from_json( Obj,"geoCode",geoCode); + return true; + } catch (...) { + + } + return false; + } + + void OperatorLocationList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj, "locations", locations); + } + + bool OperatorLocationList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj, "locations", locations); + return true; + } catch(...) { + + } + return false; + } + void Contact::to_json(Poco::JSON::Object &Obj) const { info.to_json(Obj); field_to_json( Obj,"type", to_string(type)); @@ -295,20 +488,118 @@ namespace OpenWifi::ProvObjects { return false; } + void OperatorContact::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"type", type); + field_to_json( Obj,"title",title); + field_to_json( Obj,"salutation",salutation); + field_to_json( Obj,"firstname",firstname); + field_to_json( Obj,"lastname",lastname); + field_to_json( Obj,"initials",initials); + field_to_json( Obj,"visual",visual); + field_to_json( Obj,"mobiles",mobiles); + field_to_json( Obj,"phones",phones); + field_to_json( Obj,"primaryEmail",primaryEmail); + field_to_json( Obj,"secondaryEmail",secondaryEmail); + field_to_json( Obj,"accessPIN",accessPIN); + field_to_json( Obj,"operatorId",operatorId); + field_to_json( Obj,"subscriberDeviceId",subscriberDeviceId); + field_to_json( Obj,"managementPolicy",managementPolicy); + } + + bool OperatorContact::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"type", type); + field_from_json( Obj,"title",title); + field_from_json( Obj,"salutation",salutation); + field_from_json( Obj,"firstname",firstname); + field_from_json( Obj,"lastname",lastname); + field_from_json( Obj,"initials",initials); + field_from_json( Obj,"visual",visual); + field_from_json( Obj,"mobiles",mobiles); + field_from_json( Obj,"phones",phones); + field_from_json( Obj,"primaryEmail",primaryEmail); + field_from_json( Obj,"secondaryEmail",secondaryEmail); + field_from_json( Obj,"accessPIN",accessPIN); + field_from_json( Obj,"operatorId",operatorId); + field_from_json( Obj,"subscriberDeviceId",subscriberDeviceId); + field_from_json( Obj,"managementPolicy",managementPolicy); + return true; + } catch (...) { + + } + return false; + } + + void SubContact::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"type", type); + field_to_json( Obj,"title",title); + field_to_json( Obj,"salutation",salutation); + field_to_json( Obj,"firstname",firstname); + field_to_json( Obj,"lastname",lastname); + field_to_json( Obj,"initials",initials); + field_to_json( Obj,"visual",visual); + field_to_json( Obj,"mobiles",mobiles); + field_to_json( Obj,"phones",phones); + field_to_json( Obj,"primaryEmail",primaryEmail); + field_to_json( Obj,"secondaryEmail",secondaryEmail); + field_to_json( Obj,"accessPIN",accessPIN); + } + + bool SubContact::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"type", type); + field_from_json( Obj,"title",title); + field_from_json( Obj,"salutation",salutation); + field_from_json( Obj,"firstname",firstname); + field_from_json( Obj,"lastname",lastname); + field_from_json( Obj,"initials",initials); + field_from_json( Obj,"visual",visual); + field_from_json( Obj,"mobiles",mobiles); + field_from_json( Obj,"phones",phones); + field_from_json( Obj,"primaryEmail",primaryEmail); + field_from_json( Obj,"secondaryEmail",secondaryEmail); + field_from_json( Obj,"accessPIN",accessPIN); + return true; + } catch (...) { + + } + return false; + } + + void OperatorContactList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj, "contacts", contacts); + } + + bool OperatorContactList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj, "contacts", contacts); + return true; + } catch(...) { + + } + return false; + } + void InventoryTag::to_json(Poco::JSON::Object &Obj) const { info.to_json(Obj); - field_to_json(Obj, "serialNumber", serialNumber); - field_to_json(Obj, "venue", venue); - field_to_json(Obj, "entity", entity); - field_to_json(Obj, "subscriber", subscriber); - field_to_json(Obj, "deviceType", deviceType); - field_to_json(Obj, "qrCode", qrCode); - field_to_json(Obj, "geoCode", geoCode); - field_to_json(Obj, "location", location); - field_to_json(Obj, "contact", contact); - field_to_json( Obj,"deviceConfiguration",deviceConfiguration); - field_to_json( Obj,"rrm",rrm); - field_to_json( Obj,"managementPolicy",managementPolicy); + field_to_json( Obj, "serialNumber", serialNumber); + field_to_json( Obj, "venue", venue); + field_to_json( Obj, "entity", entity); + field_to_json( Obj, "subscriber", subscriber); + field_to_json( Obj, "deviceType", deviceType); + field_to_json( Obj, "qrCode", qrCode); + field_to_json( Obj, "geoCode", geoCode); + field_to_json( Obj, "location", location); + field_to_json( Obj, "contact", contact); + field_to_json( Obj, "deviceConfiguration",deviceConfiguration); + field_to_json( Obj,"deviceRules",deviceRules); + field_to_json( Obj, "managementPolicy",managementPolicy); + field_to_json( Obj, "state",state); + field_to_json( Obj, "devClass",devClass); + field_to_json( Obj, "locale",locale); + field_to_json( Obj, "realMacAddress",realMacAddress); } bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -319,13 +610,17 @@ namespace OpenWifi::ProvObjects { field_from_json( Obj,"entity",entity); field_from_json( Obj,"subscriber",subscriber); field_from_json( Obj,"deviceType",deviceType); - field_from_json(Obj, "qrCode", qrCode); + field_from_json( Obj,"qrCode", qrCode); field_from_json( Obj,"geoCode",geoCode); field_from_json( Obj,"location",location); field_from_json( Obj,"contact",contact); field_from_json( Obj,"deviceConfiguration",deviceConfiguration); - field_from_json( Obj,"rrm",rrm); + field_from_json( Obj,"deviceRules",deviceRules); field_from_json( Obj,"managementPolicy",managementPolicy); + field_from_json( Obj,"state",state); + field_from_json( Obj,"devClass",devClass); + field_from_json( Obj,"locale",locale); + field_from_json( Obj,"realMacAddress",realMacAddress); return true; } catch(...) { @@ -333,6 +628,40 @@ namespace OpenWifi::ProvObjects { return false; } + void InventoryConfigApplyResult::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj, "appliedConfiguration", appliedConfiguration); + field_to_json( Obj, "warnings", warnings); + field_to_json( Obj, "errors", errors); + field_to_json( Obj, "errorCode", errorCode); + } + + bool InventoryConfigApplyResult::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj, "appliedConfiguration", appliedConfiguration); + field_from_json( Obj, "warnings", warnings); + field_from_json( Obj, "errors", errors); + field_from_json( Obj, "errorCode", errorCode); + return true; + } catch (...) { + + } + return false; + } + + void InventoryTagList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"taglist",taglist); + } + + bool InventoryTagList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"taglist",taglist); + return true; + } catch (...) { + + } + return false; + }; + void DeviceConfigurationElement::to_json(Poco::JSON::Object &Obj) const { field_to_json( Obj,"name", name); field_to_json( Obj,"description", description); @@ -357,12 +686,14 @@ namespace OpenWifi::ProvObjects { info.to_json(Obj); field_to_json( Obj,"managementPolicy",managementPolicy); field_to_json( Obj,"deviceTypes",deviceTypes); + field_to_json( Obj,"subscriberOnly",subscriberOnly); + field_to_json( Obj,"entity", entity); + field_to_json( Obj,"venue", venue); + field_to_json( Obj,"subscriber", subscriber); field_to_json( Obj,"configuration",configuration); field_to_json( Obj,"inUse",inUse); field_to_json( Obj,"variables",variables); - field_to_json( Obj,"rrm",rrm); - field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade); - field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly); + field_to_json( Obj,"deviceRules",deviceRules); } bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -370,12 +701,14 @@ namespace OpenWifi::ProvObjects { info.from_json(Obj); field_from_json( Obj,"managementPolicy",managementPolicy); field_from_json( Obj,"deviceTypes",deviceTypes); - field_from_json( Obj,"configuration",configuration); field_from_json( Obj,"inUse",inUse); field_from_json( Obj,"variables",variables); - field_from_json( Obj,"rrm",rrm); - field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade); - field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly); + field_from_json( Obj,"subscriberOnly",subscriberOnly); + field_from_json( Obj,"entity", entity); + field_from_json( Obj,"venue", venue); + field_from_json( Obj,"subscriber", subscriber); + field_from_json( Obj,"configuration",configuration); + field_from_json( Obj,"deviceRules",deviceRules); return true; } catch(...) { @@ -454,46 +787,16 @@ namespace OpenWifi::ProvObjects { return false; } - void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, ACLACCESS A) { - switch(A) { - case READ: Obj.set(FieldName,"read"); break; - case MODIFY: Obj.set(FieldName,"modify"); break; - case CREATE: Obj.set(FieldName,"create"); break; - case DELETE: Obj.set(FieldName,"delete"); break; - case NONE: - default: - Obj.set(FieldName,"none"); - } - } - - void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, ACLACCESS &A) { - if(Obj->has(FieldName)) { - auto V = Obj->getValue(FieldName); - if(V=="read") - A = READ; - else if(V=="modify") - A = MODIFY; - else if(V=="create") - A = CREATE; - else if(V=="delete") - A = DELETE; - else if(V=="none") - A = NONE; - else - throw Poco::Exception("invalid JSON"); - } - } - void ObjectACL::to_json(Poco::JSON::Object &Obj) const { - RESTAPI_utils::field_to_json(Obj, "users", users); - RESTAPI_utils::field_to_json(Obj, "roles", roles); + field_to_json(Obj, "users", users); + field_to_json(Obj, "roles", roles); field_to_json(Obj, "access", access); } bool ObjectACL::from_json(const Poco::JSON::Object::Ptr &Obj) { try { - RESTAPI_utils::field_from_json(Obj, "users", users); - RESTAPI_utils::field_from_json(Obj, "roles", roles); + field_from_json(Obj, "users", users); + field_from_json(Obj, "roles", roles); field_from_json(Obj, "access", access); return true; } catch(...) { @@ -503,12 +806,12 @@ namespace OpenWifi::ProvObjects { } void ObjectACLList::to_json(Poco::JSON::Object &Obj) const { - RESTAPI_utils::field_to_json(Obj, "list", list); + field_to_json(Obj, "list", list); } bool ObjectACLList::from_json(const Poco::JSON::Object::Ptr &Obj) { try { - RESTAPI_utils::field_from_json(Obj, "list", list); + field_from_json(Obj, "list", list); return true; } catch(...) { @@ -516,44 +819,15 @@ namespace OpenWifi::ProvObjects { return false; } - std::string to_string(VISIBILITY A) { - switch(A) { - case PUBLIC: return "public"; - case SELECT: return "select"; - case PRIVATE: - default: - return "private"; - } - } - - void field_to_json(Poco::JSON::Object &Obj, const char * FieldName, VISIBILITY A) { - Obj.set(FieldName,to_string(A)); - } - - VISIBILITY visibility_from_string(const std::string &V) { - if(V=="public") - return PUBLIC; - else if(V=="select") - return SELECT; - else if(V=="private") - return PRIVATE; - throw Poco::Exception("invalid json"); - } - - void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char * FieldName, VISIBILITY &A) { - if(Obj->has(FieldName)) { - auto V = Obj->getValue(FieldName); - A = visibility_from_string(V); - } - } - void Map::to_json(Poco::JSON::Object &Obj) const { info.to_json(Obj); - RESTAPI_utils::field_to_json( Obj,"data",data); - RESTAPI_utils::field_to_json( Obj,"entity",entity); - RESTAPI_utils::field_to_json( Obj,"creator",creator); + field_to_json( Obj,"data",data); + field_to_json( Obj,"entity",entity); + field_to_json( Obj,"creator",creator); field_to_json( Obj,"visibility",visibility); - RESTAPI_utils::field_to_json( Obj,"access",access); + field_to_json( Obj,"access",access); + field_to_json( Obj,"managementPolicy", managementPolicy); + field_to_json( Obj,"venue", venue); } bool Map::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -562,8 +836,24 @@ namespace OpenWifi::ProvObjects { RESTAPI_utils::field_from_json( Obj,"data",data); RESTAPI_utils::field_from_json( Obj,"entity",entity); RESTAPI_utils::field_from_json( Obj,"creator",creator); - field_from_json( Obj,"visibility",visibility); + RESTAPI_utils::field_from_json( Obj,"visibility",visibility); RESTAPI_utils::field_from_json( Obj,"access",access); + RESTAPI_utils::field_from_json( Obj,"managementPolicy", managementPolicy); + RESTAPI_utils::field_from_json( Obj,"venue", venue); + return true; + } catch(...) { + + } + return false; + } + + void SerialNumberList::to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json( Obj,"serialNumbers",serialNumbers); + } + + bool SerialNumberList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json( Obj,"serialNumbers",serialNumbers); return true; } catch(...) { @@ -585,8 +875,223 @@ namespace OpenWifi::ProvObjects { return false; } + void SignupEntry::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"email", email); + field_to_json( Obj,"userId", userId); + field_to_json( Obj,"macAddress", macAddress); + field_to_json( Obj,"serialNumber", serialNumber); + field_to_json( Obj,"submitted", submitted); + field_to_json( Obj,"completed", completed); + field_to_json( Obj,"status", status); + field_to_json( Obj,"error", error); + field_to_json( Obj,"statusCode", statusCode); + field_to_json( Obj,"deviceID", deviceID); + field_to_json( Obj,"registrationId",registrationId); + field_to_json( Obj,"operatorId",operatorId); + } + + bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"email", email); + field_from_json( Obj,"userId", userId); + field_from_json( Obj,"macAddress", macAddress); + field_from_json( Obj,"serialNumber", serialNumber); + field_from_json( Obj,"submitted", submitted); + field_from_json( Obj,"completed", completed); + field_from_json( Obj,"status", status); + field_from_json( Obj,"error", error); + field_from_json( Obj,"statusCode", statusCode); + field_from_json( Obj,"deviceID", deviceID); + field_from_json( Obj,"registrationId",registrationId); + field_from_json( Obj,"operatorId",operatorId); + return true; + } catch(...) { + + } + return false; + } + + void Variable::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"type", type); + field_to_json( Obj,"weight", weight); + field_to_json( Obj,"prefix", prefix); + field_to_json( Obj,"value", value); + } + + bool Variable::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"type", type); + field_from_json( Obj,"weight", weight); + field_from_json( Obj,"prefix", prefix); + field_from_json( Obj,"value", value); + return true; + } catch(...) { + + } + return false; + } + + void VariableList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"variables", variables); + } + + bool VariableList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"variables", variables); + return true; + } catch(...) { + + } + return false; + } + + void VariableBlock::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"variables", variables); + field_to_json( Obj,"entity", entity); + field_to_json( Obj,"venue", venue); + field_to_json( Obj,"subscriber", subscriber); + field_to_json( Obj,"inventory", inventory); + field_to_json( Obj,"configurations", configurations); + field_to_json( Obj,"managementPolicy", managementPolicy); + } + + bool VariableBlock::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"variables", variables); + field_from_json( Obj,"entity", entity); + field_from_json( Obj,"venue", venue); + field_from_json( Obj,"subscriber", subscriber); + field_from_json( Obj,"inventory", inventory); + field_from_json( Obj,"configurations", configurations); + field_from_json( Obj,"managementPolicy", managementPolicy); + return true; + } catch(...) { + } + return false; + } + + void VariableBlockList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"variableBlocks", variableBlocks); + } + + bool VariableBlockList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"variableBlocks", variableBlocks); + return true; + } catch(...) { + + } + return false; + } + + void ConfigurationDetails::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"configuration", configuration); + field_to_json( Obj,"rrm", rrm); + field_to_json( Obj,"firmwareRCOnly", firmwareRCOnly); + field_to_json( Obj,"firmwareUpgrade", firmwareUpgrade); + } + + bool ConfigurationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"configuration", configuration); + field_from_json( Obj,"rrm", rrm); + field_from_json( Obj,"firmwareRCOnly", firmwareRCOnly); + field_from_json( Obj,"firmwareUpgrade", firmwareUpgrade); + return true; + } catch(...) { + + } + return false; + } + + void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const { + info.to_json(Obj); + field_to_json( Obj,"serialNumber", serialNumber); + field_to_json( Obj,"deviceType", deviceType); + field_to_json( Obj,"operatorId", operatorId); + field_to_json( Obj,"subscriberId", subscriberId); + field_to_json( Obj,"location", location); + field_to_json( Obj,"contact", contact); + field_to_json( Obj,"managementPolicy", managementPolicy); + field_to_json( Obj,"serviceClass", serviceClass); + field_to_json( Obj,"qrCode", qrCode); + field_to_json( Obj,"geoCode", geoCode); + field_to_json( Obj,"deviceRules",deviceRules); + field_to_json( Obj,"state", state); + field_to_json( Obj,"locale", locale); + field_to_json( Obj,"billingCode", billingCode); + field_to_json( Obj,"configuration", configuration); + field_to_json( Obj,"suspended", suspended); + field_to_json( Obj,"realMacAddress", realMacAddress); + } + + bool SubscriberDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + info.from_json(Obj); + field_from_json( Obj,"serialNumber", serialNumber); + field_from_json( Obj,"deviceType", deviceType); + field_from_json( Obj,"operatorId", operatorId); + field_from_json( Obj,"subscriberId", subscriberId); + field_from_json( Obj,"location", location); + field_from_json( Obj,"contact", contact); + field_from_json( Obj,"managementPolicy", managementPolicy); + field_from_json( Obj,"serviceClass", serviceClass); + field_from_json( Obj,"qrCode", qrCode); + field_from_json( Obj,"geoCode", geoCode); + field_from_json( Obj,"deviceRules",deviceRules); + field_from_json( Obj,"state", state); + field_from_json( Obj,"locale", locale); + field_from_json( Obj,"billingCode", billingCode); + field_from_json( Obj,"configuration", configuration); + field_from_json( Obj,"suspended", suspended); + field_from_json( Obj,"realMacAddress", realMacAddress); + return true; + } catch(...) { + + } + return false; + } + + void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const { + field_to_json( Obj,"subscriberDevices", subscriberDevices); + } + + bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json( Obj,"subscriberDevices", subscriberDevices); + return true; + } catch(...) { + + } + return false; + } + + void VenueDeviceList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id",id); + field_to_json(Obj,"name",name); + field_to_json(Obj,"description",description); + field_to_json(Obj,"devices",devices); + } + + bool VenueDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id",id); + field_from_json(Obj,"name",name); + field_from_json(Obj,"description",description); + field_from_json(Obj,"devices",devices); + return true; + } catch(...) { + + } + return false; + } + bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { - uint64_t Now = std::time(nullptr); + uint64_t Now = OpenWifi::Now(); if(O->has("name")) I.name = O->get("name").toString(); @@ -607,7 +1112,7 @@ namespace OpenWifi::ProvObjects { } bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) { - uint64_t Now = std::time(nullptr); + uint64_t Now = OpenWifi::Now(); if(O->has("name")) I.name = O->get("name").toString(); @@ -629,5 +1134,30 @@ namespace OpenWifi::ProvObjects { return true; } + + bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) { + I.modified = I.created = OpenWifi::Now(); + I.id = MicroService::CreateUUID(); + return true; + } + + void DeviceRules::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"rcOnly",rcOnly); + field_to_json(Obj,"rrm",rrm); + field_to_json(Obj,"firmwareUpgrade",firmwareUpgrade); + } + + bool DeviceRules::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"rcOnly",rcOnly); + field_from_json(Obj,"rrm",rrm); + field_from_json(Obj,"firmwareUpgrade",firmwareUpgrade); + return true; + } catch(...) { + + } + return false; + } + } diff --git a/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.h b/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.h index 6ac9b4f..4452af9 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.h +++ b/microservice_sample/src/RESTObjects/RESTAPI_ProvObjects.h @@ -33,6 +33,13 @@ namespace OpenWifi::ProvObjects { bool from_json(const Poco::JSON::Object::Ptr &Obj); }; + struct SerialNumberList { + Types::UUIDvec_t serialNumbers; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + struct ManagementPolicyEntry { Types::UUIDvec_t users; Types::UUIDvec_t resources; @@ -48,12 +55,22 @@ namespace OpenWifi::ProvObjects { std::vector entries; Types::StringVec inUse; Types::UUID_t entity; + Types::UUID_t venue; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); }; typedef std::vector ManagementPolicyVec; + struct DeviceRules { + std::string rcOnly{"inherit"}; + std::string rrm{"inherit"}; + std::string firmwareUpgrade{"inherit"}; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + struct Entity { ObjectInfo info; Types::UUID_t parent; @@ -64,8 +81,13 @@ namespace OpenWifi::ProvObjects { Types::UUID_t managementPolicy; Types::UUIDvec_t deviceConfiguration; Types::UUIDvec_t devices; - std::string rrm; + DeviceRules deviceRules; Types::StringVec sourceIP; + Types::UUIDvec_t variables; + Types::UUIDvec_t managementPolicies; + Types::UUIDvec_t managementRoles; + Types::UUIDvec_t maps; + Types::UUIDvec_t configurations; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); @@ -92,10 +114,16 @@ namespace OpenWifi::ProvObjects { DiGraph topology; std::string design; Types::UUIDvec_t deviceConfiguration; - std::string contact; + Types::UUIDvec_t contacts; std::string location; - std::string rrm; + DeviceRules deviceRules; Types::StringVec sourceIP; + Types::UUIDvec_t variables; + Types::UUIDvec_t configurations; + Types::UUIDvec_t maps; + Types::UUIDvec_t managementPolicies; + Types::UUIDvec_t managementRoles; + Types::UUIDvec_t boards; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); @@ -117,6 +145,7 @@ namespace OpenWifi::ProvObjects { Types::UUIDvec_t users; Types::StringVec inUse; Types::UUID_t entity; + Types::UUID_t venue; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); @@ -180,6 +209,51 @@ namespace OpenWifi::ProvObjects { }; typedef std::vector LocationVec; + struct OperatorLocation { + ObjectInfo info; + std::string type; + std::string buildingName; + Types::StringVec addressLines; + std::string city; + std::string state; + std::string postal; + std::string country; + Types::StringVec phones; + Types::StringVec mobiles; + std::string geoCode; + Types::UUID_t operatorId; + Types::UUID_t subscriberDeviceId; + Types::UUID_t managementPolicy; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector LocationVec; + + struct SubLocation { + std::string type; + std::string buildingName; + Types::StringVec addressLines; + std::string city; + std::string state; + std::string postal; + std::string country; + Types::StringVec phones; + Types::StringVec mobiles; + std::string geoCode; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct OperatorLocationList { + std::vector locations; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + enum ContactType { CT_SUBSCRIBER, CT_USER, CT_INSTALLER, CT_CSR, CT_MANAGER, CT_BUSINESSOWNER, CT_TECHNICIAN, CT_CORPORATE, CT_UNKNOWN @@ -243,6 +317,55 @@ namespace OpenWifi::ProvObjects { }; typedef std::vector ContactVec; + struct OperatorContact { + ObjectInfo info; + std::string type; + std::string title; + std::string salutation; + std::string firstname; + std::string lastname; + std::string initials; + std::string visual; + Types::StringVec mobiles; + Types::StringVec phones; + std::string primaryEmail; + std::string secondaryEmail; + std::string accessPIN; + Types::UUID_t operatorId; + Types::UUID_t subscriberDeviceId; + Types::UUID_t managementPolicy; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubContact { + std::string type; + std::string title; + std::string salutation; + std::string firstname; + std::string lastname; + std::string initials; + std::string visual; + Types::StringVec mobiles; + Types::StringVec phones; + std::string primaryEmail; + std::string secondaryEmail; + std::string accessPIN; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct OperatorContactList { + std::vector contacts; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + typedef std::vector OperatorContactVec; + struct DeviceConfigurationElement { std::string name; std::string description; @@ -255,21 +378,24 @@ namespace OpenWifi::ProvObjects { typedef std::vector DeviceConfigurationElementVec; struct DeviceConfiguration { - ObjectInfo info; + ObjectInfo info; Types::UUID_t managementPolicy; Types::StringVec deviceTypes; DeviceConfigurationElementVec configuration; Types::StringVec inUse; - Types::StringPairVec variables; - std::string rrm; - std::string firmwareUpgrade; - bool firmwareRCOnly=false; + Types::UUIDvec_t variables; + DeviceRules deviceRules; + bool subscriberOnly=false; + std::string venue; + std::string entity; + std::string subscriber; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); }; typedef std::vector DeviceConfigurationVec; + struct InventoryTag { ObjectInfo info; std::string serialNumber; @@ -282,14 +408,36 @@ namespace OpenWifi::ProvObjects { std::string location; std::string contact; std::string deviceConfiguration; - std::string rrm; + DeviceRules deviceRules; Types::UUID_t managementPolicy; + std::string state; + std::string devClass; + std::string locale; + std::string realMacAddress; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); }; + typedef std::vector InventoryTagVec; + struct InventoryTagList { + InventoryTagVec taglist; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct InventoryConfigApplyResult { + std::string appliedConfiguration; + Types::StringVec errors; + Types::StringVec warnings; + uint64_t errorCode; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + struct Report { uint64_t snapShot=0; Types::CountedMap tenants; @@ -323,20 +471,20 @@ namespace OpenWifi::ProvObjects { }; struct UuidList { - std::vector list; + Types::UUIDvec_t list; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); }; enum ACLACCESS { - NONE, READ, MODIFY, CREATE, DELETE + NONE = 0, READ=1, MODIFY=2, CREATE=3, DELETE=4 }; struct ObjectACL { UuidList users; UuidList roles; - ACLACCESS access = NONE; + uint64_t access = (uint64_t) NONE; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); @@ -349,20 +497,15 @@ namespace OpenWifi::ProvObjects { bool from_json(const Poco::JSON::Object::Ptr &Obj); }; - enum VISIBILITY { - PUBLIC, PRIVATE, SELECT - }; - - std::string to_string(VISIBILITY A); - VISIBILITY visibility_from_string(const std::string &V); - struct Map { ObjectInfo info; std::string data; std::string entity; std::string creator; - VISIBILITY visibility = PRIVATE; + std::string visibility{"private"}; ObjectACLList access; + Types::UUID_t managementPolicy; + std::string venue; void to_json(Poco::JSON::Object &Obj) const; bool from_json(const Poco::JSON::Object::Ptr &Obj); @@ -375,6 +518,168 @@ namespace OpenWifi::ProvObjects { bool from_json(const Poco::JSON::Object::Ptr &Obj); }; + enum SignupStatusCodes { + SignupCreated = 0 , + SignupWaitingForEmail, + SignupWaitingForDevice, + SignupSuccess, + SignupFailure, + SignupCanceled, + SignupTimedOut + }; + + struct SignupEntry { + ObjectInfo info; + std::string email; + std::string userId; + std::string macAddress; + std::string serialNumber; + uint64_t submitted = 0 ; + uint64_t completed = 0 ; + std::string status; + uint64_t error=0; + uint64_t statusCode=0; + std::string deviceID; + std::string registrationId; + std::string operatorId; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Variable { + std::string type; + uint64_t weight=0; + std::string prefix; + std::string value; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct VariableList { + std::vector variables; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct VariableBlock { + ObjectInfo info; + std::vector variables; + std::string entity; + std::string venue; + std::string subscriber; + std::string inventory; + Types::UUIDvec_t configurations; + Types::UUID_t managementPolicy; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct VariableBlockList { + std::vector variableBlocks; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Operator { + ObjectInfo info; + Types::UUID_t managementPolicy; + Types::UUIDvec_t managementRoles; + DeviceRules deviceRules; + std::vector variables; + bool defaultOperator=false; + Types::StringVec sourceIP; + std::string registrationId; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct OperatorList { + std::vector operators; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct VenueDeviceList { + std::string id; + std::string name; + std::string description; + Types::UUIDvec_t devices; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct ServiceClass { + ObjectInfo info; + Types::UUID_t operatorId; + Types::UUID_t managementPolicy; + double cost=0.0; + std::string currency; + std::string period; + std::string billingCode; + std::vector variables; + bool defaultService=false; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct ServiceClassList { + std::vector serviceClasses; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct ConfigurationDetails { + DeviceConfigurationElementVec configuration; + std::string rrm{"inherit"}; + std::string firmwareUpgrade{"inherit"}; + std::string firmwareRCOnly{"inherit"}; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubscriberDevice { + ObjectInfo info; + std::string serialNumber; + std::string deviceType; + Types::UUID_t operatorId; + Types::UUID_t subscriberId; + SubLocation location; + SubContact contact; + Types::UUID_t managementPolicy; + Types::UUID_t serviceClass; + std::string qrCode; + std::string geoCode; + DeviceRules deviceRules; + std::string state; + std::string locale; + std::string billingCode; + DeviceConfigurationElementVec configuration; + bool suspended=false; + std::string realMacAddress; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubscriberDeviceList { + std::vector subscriberDevices; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I); + bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I); }; diff --git a/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.cpp index 3d0c270..a077e40 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.cpp +++ b/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.cpp @@ -54,6 +54,8 @@ namespace OpenWifi::SecurityObjects { return ADMIN; else if (!Poco::icompare(U,"subscriber")) return SUBSCRIBER; + else if (!Poco::icompare(U,"partner")) + return PARTNER; else if (!Poco::icompare(U,"csr")) return CSR; else if (!Poco::icompare(U, "system")) @@ -72,6 +74,7 @@ namespace OpenWifi::SecurityObjects { case ROOT: return "root"; case ADMIN: return "admin"; case SUBSCRIBER: return "subscriber"; + case PARTNER: return "partner"; case CSR: return "csr"; case SYSTEM: return "system"; case INSTALLER: return "installer"; @@ -92,6 +95,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj, "PortalLogin", PortalLogin_); return true; } catch(...) { + std::cout << "Cannot parse: AclTemplate" << std::endl; } return false; } @@ -109,6 +113,8 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"userMustChangePassword",userMustChangePassword); field_to_json(Obj,"errorCode", errorCode); Obj.set("aclTemplate",AclTemplateObj); + field_to_json(Obj,"errorCode", errorCode); + field_to_json(Obj,"lastRefresh", lastRefresh_); } bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) { @@ -125,9 +131,10 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj, "created", created_); field_from_json(Obj, "username", username_); field_from_json(Obj, "userMustChangePassword",userMustChangePassword); + field_from_json(Obj,"lastRefresh", lastRefresh_); return true; } catch (...) { - + std::cout << "Cannot parse: WebToken" << std::endl; } return false; } @@ -138,14 +145,14 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"primary", primary); } - bool MobilePhoneNumber::from_json(Poco::JSON::Object::Ptr &Obj) { + bool MobilePhoneNumber::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"number",number); field_from_json(Obj,"verified",verified); field_from_json(Obj,"primary",primary); return true; } catch (...) { - + std::cout << "Cannot parse: MobilePhoneNumber" << std::endl; } return false; }; @@ -155,13 +162,13 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"method", method); } - bool MfaAuthInfo::from_json(Poco::JSON::Object::Ptr &Obj) { + bool MfaAuthInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"enabled",enabled); field_from_json(Obj,"method",method); return true; } catch (...) { - + std::cout << "Cannot parse: MfaAuthInfo" << std::endl; } return false; } @@ -169,15 +176,17 @@ namespace OpenWifi::SecurityObjects { void UserLoginLoginExtensions::to_json(Poco::JSON::Object &Obj) const { field_to_json(Obj, "mobiles", mobiles); field_to_json(Obj, "mfa", mfa); + field_to_json(Obj, "authenticatorSecret", authenticatorSecret); } - bool UserLoginLoginExtensions::from_json(Poco::JSON::Object::Ptr &Obj) { + bool UserLoginLoginExtensions::from_json(const Poco::JSON::Object::Ptr &Obj) { try { - field_from_json(Obj,"mobiles",mobiles); - field_from_json(Obj,"mfa",mfa); + field_from_json(Obj, "mobiles",mobiles); + field_from_json(Obj, "mfa",mfa); + field_from_json(Obj, "authenticatorSecret", authenticatorSecret); return true; } catch (...) { - + std::cout << "Cannot parse: UserLoginLoginExtensions" << std::endl; } return false; } @@ -189,7 +198,7 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj, "method", method); } - bool MFAChallengeRequest::from_json(Poco::JSON::Object::Ptr &Obj) { + bool MFAChallengeRequest::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"question",question); @@ -197,7 +206,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj,"method",method); return true; } catch (...) { - + std::cout << "Cannot parse: MFAChallengeRequest" << std::endl; } return false; }; @@ -205,23 +214,22 @@ namespace OpenWifi::SecurityObjects { void MFAChallengeResponse::to_json(Poco::JSON::Object &Obj) const { field_to_json(Obj, "uuid", uuid); field_to_json(Obj, "answer", answer); - } - bool MFAChallengeResponse::from_json(Poco::JSON::Object::Ptr &Obj) { + bool MFAChallengeResponse::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"uuid",uuid); field_from_json(Obj,"answer",answer); return true; } catch (...) { - + std::cout << "Cannot parse: MFAChallengeResponse" << std::endl; } return false; } void UserInfo::to_json(Poco::JSON::Object &Obj) const { - field_to_json(Obj,"Id",Id); + field_to_json(Obj,"id",id); field_to_json(Obj,"name",name); field_to_json(Obj,"description", description); field_to_json(Obj,"avatar", avatar); @@ -251,11 +259,13 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"lastPasswords",lastPasswords); field_to_json(Obj,"oauthType",oauthType); field_to_json(Obj,"oauthUserInfo",oauthUserInfo); + field_to_json(Obj,"modified",modified); + field_to_json(Obj,"signingUp",signingUp); }; bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { try { - field_from_json(Obj,"Id",Id); + field_from_json(Obj,"id",id); field_from_json(Obj,"name",name); field_from_json(Obj,"description",description); field_from_json(Obj,"avatar",avatar); @@ -265,6 +275,8 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj,"currentLoginURI",currentLoginURI); field_from_json(Obj,"locale",locale); field_from_json(Obj,"notes",notes); + field_from_json(Obj,"location", location); + field_from_json(Obj,"owner", owner); field_from_json(Obj,"userRole",userRole, UserTypeFromString); field_from_json(Obj,"securityPolicy",securityPolicy); field_from_json(Obj,"userTypeProprietaryInfo",userTypeProprietaryInfo); @@ -283,13 +295,29 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj,"lastPasswords",lastPasswords); field_from_json(Obj,"oauthType",oauthType); field_from_json(Obj,"oauthUserInfo",oauthUserInfo); + field_from_json(Obj,"modified",modified); + field_from_json(Obj,"signingUp",signingUp); return true; } catch (const Poco::Exception &E) { - + std::cout << "Cannot parse: UserInfo" << std::endl; } return false; }; + void UserInfoList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"users",users); + } + + bool UserInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"users",users); + return true; + } catch (...) { + std::cout << "Cannot parse: InternalServiceInfo" << std::endl; + } + return false; + } + void InternalServiceInfo::to_json(Poco::JSON::Object &Obj) const { field_to_json(Obj,"privateURI",privateURI); field_to_json(Obj,"publicURI",publicURI); @@ -303,7 +331,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj,"token",token); return true; } catch (...) { - + std::cout << "Cannot parse: InternalServiceInfo" << std::endl; } return false; }; @@ -321,7 +349,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj, "services", services); return true; } catch(...) { - + std::cout << "Cannot parse: InternalSystemServices" << std::endl; } return false; }; @@ -343,7 +371,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj, "authenticationType", authenticationType); return true; } catch (...) { - + std::cout << "Cannot parse: SystemEndpoint" << std::endl; } return false; }; @@ -357,7 +385,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj, "endpoints", endpoints); return true; } catch (...) { - + std::cout << "Cannot parse: SystemEndpointList" << std::endl; } return false; } @@ -376,7 +404,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj, "userInfo", userinfo); return true; } catch(...) { - + std::cout << "Cannot parse: UserInfoAndPolicy" << std::endl; } return false; } @@ -387,14 +415,14 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"note", note); } - bool NoteInfo::from_json(Poco::JSON::Object::Ptr &Obj) { + bool NoteInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { try { - field_from_json(Obj,"created",created); + field_from_json(Obj,"created",created); field_from_json(Obj,"createdBy",createdBy); - field_from_json(Obj,"note",note); + field_from_json(Obj,"note", note); return true; } catch(...) { - + std::cout << "Cannot parse: NoteInfo" << std::endl; } return false; } @@ -405,20 +433,20 @@ namespace OpenWifi::SecurityObjects { SecurityObjects::NoteInfoVec NIV; NIV = RESTAPI_utils::to_object_array(Obj->get("notes").toString()); for(auto const &i:NIV) { - SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note}; + SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; Notes.push_back(ii); } } return true; } catch(...) { - + std::cout << "Cannot parse: MergeNotes" << std::endl; } return false; } bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) { for(auto const &i:NewNotes) { - SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note}; + SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note}; ExistingNotes.push_back(ii); } return true; @@ -429,13 +457,13 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"access", access, ResourceAccessTypeToString); } - bool ProfileAction::from_json(Poco::JSON::Object::Ptr &Obj) { + bool ProfileAction::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"resource",resource); field_from_json(Obj,"access",access,ResourceAccessTypeFromString ); return true; } catch(...) { - + std::cout << "Cannot parse: ProfileAction" << std::endl; } return false; } @@ -449,7 +477,7 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"notes", notes); } - bool SecurityProfile::from_json(Poco::JSON::Object::Ptr &Obj) { + bool SecurityProfile::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"id",id); field_from_json(Obj,"name",name); @@ -459,7 +487,7 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj,"notes",notes); return true; } catch(...) { - + std::cout << "Cannot parse: SecurityProfile" << std::endl; } return false; } @@ -468,12 +496,12 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj, "profiles", profiles); } - bool SecurityProfileList::from_json(Poco::JSON::Object::Ptr &Obj) { + bool SecurityProfileList::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"profiles",profiles); return true; } catch(...) { - + std::cout << "Cannot parse: SecurityProfileList" << std::endl; } return false; } @@ -491,9 +519,10 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"expires",expires); field_to_json(Obj,"completed",completed); field_to_json(Obj,"canceled",canceled); + field_to_json(Obj,"userAction",userAction); } - bool ActionLink::from_json(Poco::JSON::Object::Ptr &Obj) { + bool ActionLink::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"id",id); field_from_json(Obj,"action",action); @@ -507,9 +536,10 @@ namespace OpenWifi::SecurityObjects { field_from_json(Obj,"expires",expires); field_from_json(Obj,"completed",completed); field_from_json(Obj,"canceled",canceled); + field_from_json(Obj,"userAction",userAction); return true; } catch(...) { - + std::cout << "Cannot parse: ActionLink" << std::endl; } return false; } @@ -520,16 +550,74 @@ namespace OpenWifi::SecurityObjects { field_to_json(Obj,"data",data); } - bool Preferences::from_json(Poco::JSON::Object::Ptr &Obj) { + bool Preferences::from_json(const Poco::JSON::Object::Ptr &Obj) { try { field_from_json(Obj,"id",id); field_from_json(Obj,"modified",modified); field_from_json(Obj,"data",data); return true; } catch(...) { - + std::cout << "Cannot parse: Preferences" << std::endl; } return false; } + + void SubMfaConfig::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"id",id); + field_to_json(Obj,"type",type); + field_to_json(Obj,"sms",sms); + field_to_json(Obj,"email",email); + } + + bool SubMfaConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"id",id); + field_from_json(Obj,"type",type); + field_from_json(Obj,"sms",sms); + field_from_json(Obj,"email",email); + return true; + } catch(...) { + std::cout << "Cannot parse: SubMfaConfig" << std::endl; + } + return false; + } + + void Token::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"token",token); + field_to_json(Obj,"refreshToken",refreshToken); + field_to_json(Obj,"tokenType",tokenType); + field_to_json(Obj,"userName",userName); + field_to_json(Obj,"created",created); + field_to_json(Obj,"expires",expires); + field_to_json(Obj,"idleTimeout",idleTimeout); + field_to_json(Obj,"revocationDate",revocationDate); + field_to_json(Obj,"lastRefresh", lastRefresh); + } + + bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"token",token); + field_from_json(Obj,"refreshToken",refreshToken); + field_from_json(Obj,"tokenType",tokenType); + field_from_json(Obj,"userName",userName); + field_from_json(Obj,"created",created); + field_from_json(Obj,"expires",expires); + field_from_json(Obj,"idleTimeout",idleTimeout); + field_from_json(Obj,"revocationDate",revocationDate); + field_from_json(Obj,"lastRefresh", lastRefresh); + return true; + } catch(...) { + std::cout << "Cannot parse: Token" << std::endl; + } + return false; + } + + void LoginRecordInfo::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"sessionId",sessionId); + field_to_json(Obj,"userId",userId); + field_to_json(Obj,"email",email); + field_to_json(Obj,"login",login); + field_to_json(Obj,"logout",logout); + } } diff --git a/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.h b/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.h index 647eb77..a3f06e8 100644 --- a/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.h +++ b/microservice_sample/src/RESTObjects/RESTAPI_SecurityObjects.h @@ -6,252 +6,322 @@ // Arilia Wireless Inc. // -#ifndef UCENTRAL_RESTAPI_SECURITYOBJECTS_H -#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H +#pragma once +#include +#include #include "framework/OpenWifiTypes.h" #include "Poco/JSON/Object.h" +#include "Poco/Data/LOB.h" +#include "Poco/Data/LOBStream.h" -namespace OpenWifi::SecurityObjects { +namespace OpenWifi { + uint64_t Now(); + namespace SecurityObjects { + + typedef std::string USER_ID_TYPE; - struct AclTemplate { - bool Read_ = true; - bool ReadWrite_ = true; - bool ReadWriteCreate_ = true; - bool Delete_ = true; - bool PortalLogin_ = true; + struct AclTemplate { + bool Read_ = true; + bool ReadWrite_ = true; + bool ReadWriteCreate_ = true; + bool Delete_ = true; + bool PortalLogin_ = true; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); }; + AclTemplate() noexcept = default; - struct WebToken { - std::string access_token_; - std::string refresh_token_; - std::string id_token_; - std::string token_type_; - std::string username_; - bool userMustChangePassword=false; - uint64_t errorCode=0; - uint64_t expires_in_=0; - uint64_t idle_timeout_=0; - AclTemplate acl_template_; - uint64_t created_=0; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; + static_assert( std::is_nothrow_move_constructible_v ); - enum USER_ROLE { - UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING - }; + struct WebToken { + std::string access_token_; + std::string refresh_token_; + std::string id_token_; + std::string token_type_; + std::string username_; + bool userMustChangePassword=false; + uint64_t errorCode=0; + uint64_t expires_in_=0; + uint64_t idle_timeout_=0; + AclTemplate acl_template_; + uint64_t created_=0; + uint64_t lastRefresh_=0; - USER_ROLE UserTypeFromString(const std::string &U); - std::string UserTypeToString(USER_ROLE U); + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - struct NoteInfo { - uint64_t created = std::time(nullptr); - std::string createdBy; - std::string note; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; - typedef std::vector NoteInfoVec; + enum USER_ROLE { + UNKNOWN, ROOT, ADMIN, SUBSCRIBER, CSR, SYSTEM, INSTALLER, NOC, ACCOUNTING, PARTNER + }; - struct MobilePhoneNumber { - std::string number; - bool verified = false; - bool primary = false; + USER_ROLE UserTypeFromString(const std::string &U); + std::string UserTypeToString(USER_ROLE U); - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct NoteInfo { + uint64_t created=0; // = OpenWifi::Now(); + std::string createdBy; + std::string note; - struct MfaAuthInfo { - bool enabled = false; - std::string method; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector NoteInfoVec; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct MobilePhoneNumber { + std::string number; + bool verified = false; + bool primary = false; - struct UserLoginLoginExtensions { - std::vector mobiles; - struct MfaAuthInfo mfa; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct MfaAuthInfo { + bool enabled = false; + std::string method; - struct MFAChallengeRequest { - std::string uuid; - std::string question; - std::string method; - uint64_t created = std::time(nullptr); + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct UserLoginLoginExtensions { + std::vector mobiles; + struct MfaAuthInfo mfa; + std::string authenticatorSecret; - struct MFAChallengeResponse { - std::string uuid; - std::string answer; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct MFAChallengeRequest { + std::string uuid; + std::string question; + std::string method; + uint64_t created = OpenWifi::Now(); - struct UserInfo { - std::string Id; - std::string name; - std::string description; - std::string avatar; - std::string email; - bool validated = false; - std::string validationEmail; - uint64_t validationDate = 0; - uint64_t creationDate = 0; - std::string validationURI; - bool changePassword = false; - uint64_t lastLogin = 0; - std::string currentLoginURI; - uint64_t lastPasswordChange = 0; - uint64_t lastEmailCheck = 0; - bool waitingForEmailCheck = false; - std::string locale; - NoteInfoVec notes; - std::string location; - std::string owner; - bool suspended = false; - bool blackListed = false; - USER_ROLE userRole; - UserLoginLoginExtensions userTypeProprietaryInfo; - std::string securityPolicy; - uint64_t securityPolicyChange = 0 ; - std::string currentPassword; - Types::StringVec lastPasswords; - std::string oauthType; - std::string oauthUserInfo; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; - typedef std::vector UserInfoVec; + struct MFAChallengeResponse { + std::string uuid; + std::string answer; - // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); - bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); - bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - struct InternalServiceInfo { - std::string privateURI; - std::string publicURI; - std::string token; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; - typedef std::vector InternalServiceInfoVec; + struct UserInfo { + std::string id; + std::string name; + std::string description; + std::string avatar; + std::string email; + bool validated = false; + std::string validationEmail; + uint64_t validationDate = 0; + uint64_t creationDate = 0; + std::string validationURI; + bool changePassword = false; + uint64_t lastLogin = 0; + std::string currentLoginURI; + uint64_t lastPasswordChange = 0; + uint64_t lastEmailCheck = 0; + bool waitingForEmailCheck = false; + std::string locale; + NoteInfoVec notes; + std::string location; + std::string owner; + bool suspended = false; + bool blackListed = false; + USER_ROLE userRole; + UserLoginLoginExtensions userTypeProprietaryInfo; + std::string securityPolicy; + uint64_t securityPolicyChange = 0 ; + std::string currentPassword; + OpenWifi::Types::StringVec lastPasswords; + std::string oauthType; + std::string oauthUserInfo; + uint64_t modified; + std::string signingUp; - struct InternalSystemServices { - std::string key; - std::string version; - InternalServiceInfoVec services; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector UserInfoVec; - struct SystemEndpoint { - std::string type; - uint64_t id = 0; - std::string vendor{"OpenWiFi"}; - std::string uri; - std::string authenticationType{"internal_v1"}; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; - typedef std::vector SystemEndpointVec; + struct UserInfoList { + std::vector users; - struct SystemEndpointList { - SystemEndpointVec endpoints; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - struct UserInfoAndPolicy { - WebToken webtoken; - UserInfo userinfo; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); - }; - typedef std::map UserInfoCache; + // bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); + bool MergeNotes(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes); + bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes); - enum ResourceAccessType { - NONE, - READ, - MODIFY, - DELETE, - CREATE, - TEST, - MOVE - }; + struct InternalServiceInfo { + std::string privateURI; + std::string publicURI; + std::string token; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector InternalServiceInfoVec; - ResourceAccessType ResourceAccessTypeFromString(const std::string &s); - std::string ResourceAccessTypeToString(const ResourceAccessType & T); + struct InternalSystemServices { + std::string key; + std::string version; + InternalServiceInfoVec services; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - struct ProfileAction { - std::string resource; - ResourceAccessType access; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; - typedef std::vector ProfileActionVec; + struct SystemEndpoint { + std::string type; + uint64_t id = 0; + std::string vendor{"OpenWiFi"}; + std::string uri; + std::string authenticationType{"internal_v1"}; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector SystemEndpointVec; - struct SecurityProfile { - uint64_t id=0; - std::string name; - std::string description; - ProfileActionVec policy; - std::string role; - NoteInfoVec notes; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; - typedef std::vector SecurityProfileVec; + struct SystemEndpointList { + SystemEndpointVec endpoints; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; - struct SecurityProfileList { - SecurityProfileVec profiles; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct UserInfoAndPolicy { + WebToken webtoken; + UserInfo userinfo; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::map UserInfoCache; - enum LinkActions { - FORGOT_PASSWORD=1, - VERIFY_EMAIL - }; + enum ResourceAccessType { + NONE, + READ, + MODIFY, + DELETE, + CREATE, + TEST, + MOVE + }; - struct ActionLink { - std::string id; - uint64_t action; - std::string userId; - std::string actionTemplate; - Types::StringPairVec variables; - std::string locale; - std::string message; - uint64_t sent=0; - uint64_t created=std::time(nullptr); - uint64_t expires=0; - uint64_t completed=0; - uint64_t canceled=0; + ResourceAccessType ResourceAccessTypeFromString(const std::string &s); + std::string ResourceAccessTypeToString(const ResourceAccessType & T); - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct ProfileAction { + std::string resource; + ResourceAccessType access; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector ProfileActionVec; - struct Preferences { - std::string id; - uint64_t modified; - Types::StringPairVec data; - void to_json(Poco::JSON::Object &Obj) const; - bool from_json(Poco::JSON::Object::Ptr &Obj); - }; + struct SecurityProfile { + uint64_t id=0; + std::string name; + std::string description; + ProfileActionVec policy; + std::string role; + NoteInfoVec notes; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + typedef std::vector SecurityProfileVec; + + struct SecurityProfileList { + SecurityProfileVec profiles; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + enum LinkActions { + FORGOT_PASSWORD=1, + VERIFY_EMAIL, + SUB_FORGOT_PASSWORD, + SUB_VERIFY_EMAIL, + SUB_SIGNUP + }; + + struct ActionLink { + std::string id; + uint64_t action; + std::string userId; + std::string actionTemplate; + Types::StringPairVec variables; + std::string locale; + std::string message; + uint64_t sent=0; + uint64_t created=OpenWifi::Now(); + uint64_t expires=0; + uint64_t completed=0; + uint64_t canceled=0; + bool userAction=true; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Preferences { + std::string id; + uint64_t modified; + Types::StringPairVec data; + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubMfaConfig { + std::string id; + std::string type; + std::string sms; + std::string email; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Token { + std::string token; + std::string refreshToken; + std::string tokenType; + std::string userName; + uint64_t created=0; + uint64_t expires=0; + uint64_t idleTimeout=0; + uint64_t revocationDate=0; + uint64_t lastRefresh=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Avatar { + std::string id; + std::string type; + uint64_t created=0; + std::string name; + Poco::Data::BLOB avatar; + }; + + struct LoginRecordInfo { + std::string sessionId; + std::string userId; + std::string email; + uint64_t login=0; + uint64_t logout=0; + + void to_json(Poco::JSON::Object &Obj) const; + }; + } } - -#endif //UCENTRAL_RESTAPI_SECURITYOBJECTS_H \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_SubObjects.cpp b/microservice_sample/src/RESTObjects/RESTAPI_SubObjects.cpp new file mode 100644 index 0000000..c5b234c --- /dev/null +++ b/microservice_sample/src/RESTObjects/RESTAPI_SubObjects.cpp @@ -0,0 +1,603 @@ +// +// Created by stephane bourque on 2021-10-27. +// + +#include "RESTAPI_SubObjects.h" +#include "framework/MicroService.h" + +using OpenWifi::RESTAPI_utils::field_to_json; +using OpenWifi::RESTAPI_utils::field_from_json; + + +namespace OpenWifi::SubObjects { + + void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "enableLEDS", enableLEDS); + field_to_json(Obj, "type", type); + field_to_json(Obj, "subnet", subnet); + field_to_json(Obj, "subnetMask", subnetMask); + field_to_json(Obj, "startIP", startIP); + field_to_json(Obj, "endIP", endIP); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + field_to_json(Obj, "subnetV6", subnetV6); + field_to_json(Obj, "subnetMaskV6", subnetMaskV6); + field_to_json(Obj, "startIPV6", startIPV6); + field_to_json(Obj, "endIPV6", endIPV6); + } + + bool HomeDeviceMode::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "enableLEDS", enableLEDS); + field_from_json(Obj, "type", type); + field_from_json(Obj, "subnet", subnet); + field_from_json(Obj, "subnetMask", subnetMask); + field_from_json(Obj, "startIP", startIP); + field_from_json(Obj, "endIP", endIP); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + field_from_json(Obj, "subnetV6", subnetV6); + field_from_json(Obj, "subnetMaskV6", subnetMaskV6); + field_from_json(Obj, "startIPV6", startIPV6); + field_from_json(Obj, "endIPV6", endIPV6); + return true; + } catch (...) { + } + return false; + } + + void IPReservation::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "nickname", nickname); + field_to_json(Obj, "ipAddress", ipAddress); + field_to_json(Obj, "macAddress", macAddress); + } + + bool IPReservation::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "nickname", nickname); + field_from_json(Obj, "ipAddress", ipAddress); + field_from_json(Obj, "macAddress", macAddress); + return true; + } catch (...) { + } + return false; + } + + void IPReservationList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "id", id); + field_to_json(Obj, "reservations", reservations); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool IPReservationList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "id", id); + field_from_json(Obj, "reservations", reservations); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void DnsConfiguration::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "ISP", ISP); + field_to_json(Obj, "custom", custom); + field_to_json(Obj, "primary", primary); + field_to_json(Obj, "secondary", secondary); + field_to_json(Obj, "primaryV6", primaryV6); + field_to_json(Obj, "secondaryV6", secondaryV6); + } + + bool DnsConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "ISP", ISP); + field_from_json(Obj, "custom", custom); + field_from_json(Obj, "primary", primary); + field_from_json(Obj, "secondary", secondary); + field_from_json(Obj, "primaryV6", primaryV6); + field_from_json(Obj, "secondaryV6", secondaryV6); + return true; + } catch (...) { + } + return false; + } + + void InternetConnection::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "type", type); + field_to_json(Obj, "username", username); + field_to_json(Obj, "password", password); + field_to_json(Obj, "ipAddress", ipAddress); + field_to_json(Obj, "subnetMask", subnetMask); + field_to_json(Obj, "defaultGateway", defaultGateway); + field_to_json(Obj, "sendHostname", sendHostname); + field_to_json(Obj, "primaryDns", primaryDns); + field_to_json(Obj, "secondaryDns", secondaryDns); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + field_to_json(Obj, "ipV6Support", ipV6Support); + field_to_json(Obj, "ipAddressV6", ipAddressV6); + field_to_json(Obj, "subnetMaskV6", subnetMaskV6); + field_to_json(Obj, "defaultGatewayV6", defaultGatewayV6); + field_to_json(Obj, "primaryDnsV6", primaryDnsV6); + field_to_json(Obj, "secondaryDnsV6", secondaryDnsV6); + } + + bool InternetConnection::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "type", type); + field_from_json(Obj, "username", username); + field_from_json(Obj, "password", password); + field_from_json(Obj, "ipAddress", ipAddress); + field_from_json(Obj, "subnetMask", subnetMask); + field_from_json(Obj, "defaultGateway", defaultGateway); + field_from_json(Obj, "sendHostname", sendHostname); + field_from_json(Obj, "primaryDns", primaryDns); + field_from_json(Obj, "secondaryDns", secondaryDns); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + field_from_json(Obj, "ipV6Support", ipV6Support); + field_from_json(Obj, "ipAddressV6", ipAddressV6); + field_from_json(Obj, "subnetMaskV6", subnetMaskV6); + field_from_json(Obj, "defaultGatewayV6", defaultGatewayV6); + field_from_json(Obj, "primaryDnsV6", primaryDnsV6); + field_from_json(Obj, "secondaryDnsV6", secondaryDnsV6); + return true; + } catch (...) { + } + return false; + } + + void WifiNetwork::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "type", type); + field_to_json(Obj, "name", name); + field_to_json(Obj, "password", password); + field_to_json(Obj, "encryption", encryption); + field_to_json(Obj, "bands", bands); + } + + bool WifiNetwork::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "type", type); + field_from_json(Obj, "name", name); + field_from_json(Obj, "password", password); + field_from_json(Obj, "encryption", encryption); + field_from_json(Obj, "bands", bands); + return true; + } catch (...) { + } + return false; + } + + void WifiNetworkList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "wifiNetworks", wifiNetworks); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool WifiNetworkList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "wifiNetworks", wifiNetworks); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void AccessTime::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "day", day); + field_to_json(Obj, "rangeList", rangeList); + } + + bool AccessTime::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "day", day); + field_from_json(Obj, "rangeList", rangeList); + return true; + } catch (...) { + } + return false; + } + + void AccessTimes::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "schedule", schedule); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool AccessTimes::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "schedule", schedule); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void SubscriberDevice::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "name", name); + field_to_json(Obj, "description", description); + field_to_json(Obj, "macAddress", macAddress); + field_to_json(Obj, "manufacturer", manufacturer); + field_to_json(Obj, "firstContact", firstContact); + field_to_json(Obj, "lastContact", lastContact); + field_to_json(Obj, "group", group); + field_to_json(Obj, "icon", icon); + field_to_json(Obj, "suspended", suspended); + field_to_json(Obj, "ip", ip); + field_to_json(Obj, "schedule", schedule); + } + + bool SubscriberDevice::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "name", name); + field_from_json(Obj, "description", description); + field_from_json(Obj, "macAddress", macAddress); + field_from_json(Obj, "manufacturer", manufacturer); + field_from_json(Obj, "firstContact", firstContact); + field_from_json(Obj, "lastContact", lastContact); + field_from_json(Obj, "group", group); + field_from_json(Obj, "icon", icon); + field_from_json(Obj, "suspended", suspended); + field_from_json(Obj, "ip", ip); + field_from_json(Obj, "schedule", schedule); + return true; + } catch (...) { + } + return false; + } + + void SubscriberDeviceList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "devices", devices); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool SubscriberDeviceList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "devices", devices); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void Association::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "name", name); + field_to_json(Obj, "ssid", ssid); + field_to_json(Obj, "macAddress", macAddress); + field_to_json(Obj, "rssi", rssi); + field_to_json(Obj, "power", power); + field_to_json(Obj, "ipv4", ipv4); + field_to_json(Obj, "ipv6", ipv6); + field_to_json(Obj, "tx", tx); + field_to_json(Obj, "rx", rx); + field_to_json(Obj, "manufacturer", manufacturer); + } + + bool Association::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "name", name); + field_from_json(Obj, "ssid", ssid); + field_from_json(Obj, "macAddress", macAddress); + field_from_json(Obj, "rssi", rssi); + field_from_json(Obj, "power", power); + field_from_json(Obj, "ipv4", ipv4); + field_from_json(Obj, "ipv6", ipv6); + field_from_json(Obj, "tx", tx); + field_from_json(Obj, "rx", rx); + field_from_json(Obj, "manufacturer", manufacturer); + return true; + } catch (...) { + } + return false; + } + + void AssociationList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "associations", associations); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool AssociationList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "associations", associations); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void Client::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "macAddress", macAddress); + field_to_json(Obj, "speed", speed); + field_to_json(Obj, "mode", mode); + field_to_json(Obj, "ipv4", ipv4); + field_to_json(Obj, "ipv6", ipv6); + field_to_json(Obj, "tx", tx); + field_to_json(Obj, "rx", rx); + field_to_json(Obj, "manufacturer", manufacturer); + } + + bool Client::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "macAddress", macAddress); + field_from_json(Obj, "speed", speed); + field_from_json(Obj, "mode", mode); + field_from_json(Obj, "ipv4", ipv4); + field_from_json(Obj, "ipv6", ipv6); + field_from_json(Obj, "tx", tx); + field_from_json(Obj, "rx", rx); + field_from_json(Obj, "manufacturer", manufacturer); + return true; + } catch (...) { + } + return false; + } + + void ClientList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "clients", clients); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool ClientList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "clients", clients); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void Location::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "buildingName", buildingName); + field_to_json(Obj, "addressLines", addressLines); + field_to_json(Obj, "city", city); + field_to_json(Obj, "state", state); + field_to_json(Obj, "postal", postal); + field_to_json(Obj, "country", country); + field_to_json(Obj, "phones", phones); + field_to_json(Obj, "mobiles", mobiles); + } + + bool Location::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "buildingName", buildingName); + field_from_json(Obj, "addressLines", addressLines); + field_from_json(Obj, "city", city); + field_from_json(Obj, "state", state); + field_from_json(Obj, "postal", postal); + field_from_json(Obj, "country", country); + field_from_json(Obj, "phones", phones); + field_from_json(Obj, "mobiles", mobiles); + return true; + } catch (...) { + } + return false; + } + + void RadioHE::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "multipleBSSID", multipleBSSID); + field_to_json(Obj, "ema", ema); + field_to_json(Obj, "bssColor", bssColor); + } + + bool RadioHE::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "multipleBSSID", multipleBSSID); + field_from_json(Obj, "ema", ema); + field_from_json(Obj, "bssColor", bssColor); + return true; + } catch (...) { + } + return false; + } + + void RadioRates::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "beacon", beacon); + field_to_json(Obj, "multicast", multicast); + } + + bool RadioRates::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "beacon", beacon); + field_from_json(Obj, "multicast", multicast); + return true; + } catch (...) { + } + return false; + } + + void RadioInformation::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "band", band); + field_to_json(Obj, "bandwidth", bandwidth); + field_to_json(Obj, "channel", channel); + field_to_json(Obj, "country", country); + field_to_json(Obj, "channelMode", channelMode); + field_to_json(Obj, "channelWidth", channelWidth); + field_to_json(Obj, "requireMode", requireMode); + field_to_json(Obj, "txpower", txpower); + field_to_json(Obj, "legacyRates", legacyRates); + field_to_json(Obj, "beaconInterval", beaconInterval); + field_to_json(Obj, "dtimPeriod", dtimPeriod); + field_to_json(Obj, "maximumClients", maximumClients); + field_to_json(Obj, "rates", rates); + field_to_json(Obj, "he", he); + field_to_json(Obj, "rawInfo", rawInfo); + field_to_json(Obj, "allowDFS", allowDFS); + field_to_json(Obj, "mimo", mimo); + } + + bool RadioInformation::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "band", band); + field_from_json(Obj, "bandwidth", bandwidth); + field_from_json(Obj, "channel", channel); + field_from_json(Obj, "country", country); + field_from_json(Obj, "channelMode", channelMode); + field_from_json(Obj, "channelWidth", channelWidth); + field_from_json(Obj, "requireMode", requireMode); + field_from_json(Obj, "txpower", txpower); + field_from_json(Obj, "legacyRates", legacyRates); + field_from_json(Obj, "beaconInterval", beaconInterval); + field_from_json(Obj, "dtimPeriod", dtimPeriod); + field_from_json(Obj, "maximumClients", maximumClients); + field_from_json(Obj, "rates", rates); + field_from_json(Obj, "he", he); + field_from_json(Obj, "rawInfo", rawInfo); + field_from_json(Obj, "allowDFS", allowDFS); + field_from_json(Obj, "mimo", mimo); + return true; + } catch (...) { + } + return false; + } + + void AccessPoint::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "id", id); + field_to_json(Obj, "macAddress", macAddress); + field_to_json(Obj, "serialNumber", serialNumber); + field_to_json(Obj, "name", name); + field_to_json(Obj, "deviceType", deviceType); + field_to_json(Obj, "subscriberDevices", subscriberDevices); + field_to_json(Obj, "ipReservations", ipReservations); + field_to_json(Obj, "address", address); + field_to_json(Obj, "wifiNetworks", wifiNetworks); + field_to_json(Obj, "internetConnection", internetConnection); + field_to_json(Obj, "deviceMode", deviceMode); + field_to_json(Obj, "dnsConfiguration", dnsConfiguration); + field_to_json(Obj, "radios", radios); + field_to_json(Obj, "automaticUpgrade", automaticUpgrade); + field_to_json(Obj, "configurationUUID", configurationUUID); + field_to_json(Obj, "currentFirmware", currentFirmware); + field_to_json(Obj, "currentFirmwareDate", currentFirmwareDate); + field_to_json(Obj, "latestFirmware", latestFirmware); + field_to_json(Obj, "latestFirmwareDate", latestFirmwareDate); + field_to_json(Obj, "newFirmwareAvailable", newFirmwareAvailable); + field_to_json(Obj, "latestFirmwareURI", latestFirmwareURI); + } + + bool AccessPoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "id", id); + field_from_json(Obj, "macAddress", macAddress); + field_from_json(Obj, "serialNumber", serialNumber); + field_from_json(Obj, "name", name); + field_from_json(Obj, "deviceType", deviceType); + field_from_json(Obj, "subscriberDevices", subscriberDevices); + field_from_json(Obj, "ipReservations", ipReservations); + field_from_json(Obj, "address", address); + field_from_json(Obj, "wifiNetworks", wifiNetworks); + field_from_json(Obj, "internetConnection", internetConnection); + field_from_json(Obj, "deviceMode", deviceMode); + field_from_json(Obj, "dnsConfiguration", dnsConfiguration); + field_from_json(Obj, "radios", radios); + field_from_json(Obj, "automaticUpgrade", automaticUpgrade); + field_from_json(Obj, "configurationUUID", configurationUUID); + field_from_json(Obj, "currentFirmware", currentFirmware); + field_from_json(Obj, "currentFirmwareDate", currentFirmwareDate); + field_from_json(Obj, "latestFirmware", latestFirmware); + field_from_json(Obj, "latestFirmwareDate", latestFirmwareDate); + field_from_json(Obj, "newFirmwareAvailable", newFirmwareAvailable); + field_from_json(Obj, "latestFirmwareURI", latestFirmwareURI); + return true; + } catch (...) { + } + return false; + } + + void AccessPointList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "list", list); + } + + bool AccessPointList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "list", list); + return true; + } catch (...) { + } + return false; + } + + void SubscriberInfo::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "id", id); + field_to_json(Obj, "userId", userId); + field_to_json(Obj, "firstName", firstName); + field_to_json(Obj, "initials", initials); + field_to_json(Obj, "lastName", lastName); + field_to_json(Obj, "phoneNumber", phoneNumber); + field_to_json(Obj, "secondaryEmail", secondaryEmail); + field_to_json(Obj, "accessPoints", accessPoints); + field_to_json(Obj, "serviceAddress", serviceAddress); + field_to_json(Obj, "billingAddress", billingAddress); + field_to_json(Obj, "created", created); + field_to_json(Obj, "modified", modified); + } + + bool SubscriberInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "id", id); + field_from_json(Obj, "userId", userId); + field_from_json(Obj, "firstName", firstName); + field_from_json(Obj, "initials", initials); + field_from_json(Obj, "lastName", lastName); + field_from_json(Obj, "phoneNumber", phoneNumber); + field_from_json(Obj, "secondaryEmail", secondaryEmail); + field_from_json(Obj, "accessPoints", accessPoints); + field_from_json(Obj, "serviceAddress", serviceAddress); + field_from_json(Obj, "billingAddress", billingAddress); + field_from_json(Obj, "created", created); + field_from_json(Obj, "modified", modified); + return true; + } catch (...) { + } + return false; + } + + void StatsEntry::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "timestamp", timestamp); + field_to_json(Obj, "tx", tx); + field_to_json(Obj, "rx", rx); + } + + bool StatsEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "timestamp", timestamp); + field_from_json(Obj, "tx", tx); + field_from_json(Obj, "rx", rx); + return true; + } catch (...) { + } + return false; + } + + void StatsBlock::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj, "modified", modified); + field_to_json(Obj, "external", external); + field_to_json(Obj, "internal", internal); + } + + bool StatsBlock::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "modified", modified); + field_from_json(Obj, "external", external); + field_from_json(Obj, "internal", internal); + return true; + } catch (...) { + } + return false; + } +} \ No newline at end of file diff --git a/microservice_sample/src/RESTObjects/RESTAPI_SubObjects.h b/microservice_sample/src/RESTObjects/RESTAPI_SubObjects.h new file mode 100644 index 0000000..e586af9 --- /dev/null +++ b/microservice_sample/src/RESTObjects/RESTAPI_SubObjects.h @@ -0,0 +1,322 @@ +// +// Created by stephane bourque on 2021-10-27. +// + +#ifndef OWSUB_RESTAPI_SUBOBJECTS_H +#define OWSUB_RESTAPI_SUBOBJECTS_H + +#include + +#include "Poco/JSON/Object.h" + +namespace OpenWifi::SubObjects { + + struct HomeDeviceMode { + bool enableLEDS = true; + std::string type; // bridge, manual, automatic + std::string subnet; + std::string subnetMask; + std::string startIP; + std::string endIP; + uint64_t created = 0 ; + uint64_t modified = 0 ; + std::string subnetV6; + int subnetMaskV6=0; + std::string startIPV6; + std::string endIPV6; + std::string leaseTime; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct IPReservation { + std::string nickname; + std::string ipAddress; + std::string macAddress; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct IPReservationList { + std::string id; + std::vector reservations; + uint64_t created = 0 ; + uint64_t modified = 0 ; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct DnsConfiguration { + bool ISP=false; + bool custom=false; + std::string primary; + std::string secondary; + std::string primaryV6; + std::string secondaryV6; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct InternetConnection { + std::string type; // automatic, pppoe, manual + std::string username; + std::string password; + std::string ipAddress; + std::string subnetMask; + std::string defaultGateway; + bool sendHostname = true; + std::string primaryDns; + std::string secondaryDns; + uint64_t created=0; + uint64_t modified=0; + bool ipV6Support=false; + std::string ipAddressV6; + int subnetMaskV6=0; + std::string defaultGatewayV6; + std::string primaryDnsV6; + std::string secondaryDnsV6; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct WifiNetwork { + std::string type; // main, guest + std::string name; + std::string password; + std::string encryption; + std::vector bands; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct WifiNetworkList { + std::vector wifiNetworks; + uint64_t created=0; + uint64_t modified=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct AccessTime { + std::string day; + std::vector rangeList; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct AccessTimes { + std::vector schedule; + uint64_t created=0; + uint64_t modified=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubscriberDevice { + std::string name; + std::string description; + std::string macAddress; + std::string manufacturer; + uint64_t firstContact=0; + uint64_t lastContact=0; + std::string group; + std::string icon; + bool suspended=false; + std::string ip; + std::vector schedule; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubscriberDeviceList { + std::vector devices; + uint64_t created=0; + uint64_t modified=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Association { + std::string name; + std::string ssid; + std::string macAddress; + int rssi=0; + int power=0; + std::string ipv4; + std::string ipv6; + uint64_t tx=0; + uint64_t rx=0; + std::string manufacturer; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct AssociationList { + std::vector associations; + uint64_t created=0; + uint64_t modified=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Client { + std::string macAddress; + std::string speed; + std::string mode; + std::string ipv4; + std::string ipv6; + uint64_t tx=0; + uint64_t rx=0; + std::string manufacturer; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct ClientList { + std::vector clients; + uint64_t created=0; + uint64_t modified=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct Location { + std::string buildingName; + std::vector addressLines; + std::string city; + std::string state; + std::string postal; + std::string country; + std::vector phones; + std::vector mobiles; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadioHE { + bool multipleBSSID = false; + bool ema = false; + uint64_t bssColor = 64; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadioRates { + uint64_t beacon = 6000; + uint64_t multicast = 24000; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct RadioInformation { + std::string band; + uint64_t bandwidth; + uint64_t channel = 0 ; + std::string country; + std::string channelMode{"HE"}; + uint64_t channelWidth = 80; + std::string requireMode; + uint64_t txpower=0; + bool legacyRates = false; + uint64_t beaconInterval = 100; + uint64_t dtimPeriod = 2; + uint64_t maximumClients = 64; + RadioRates rates; + RadioHE he; + bool allowDFS=false; + std::string mimo; + std::vector rawInfo; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct AccessPoint { + std::string id; + std::string macAddress; + std::string serialNumber; + std::string name; + std::string deviceType; + SubscriberDeviceList subscriberDevices; + IPReservationList ipReservations; + Location address; + WifiNetworkList wifiNetworks; + InternetConnection internetConnection; + HomeDeviceMode deviceMode; + DnsConfiguration dnsConfiguration; + std::vector radios; + bool automaticUpgrade = true; + std::string configurationUUID; + std::string currentFirmware; + uint64_t currentFirmwareDate; + std::string latestFirmware; + uint64_t latestFirmwareDate; + bool newFirmwareAvailable; + std::string latestFirmwareURI; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct AccessPointList { + std::vector list; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct SubscriberInfo { + std::string id; + std::string userId; + std::string firstName; + std::string initials; + std::string lastName; + std::string phoneNumber; + std::string secondaryEmail; + AccessPointList accessPoints; + Location serviceAddress; + Location billingAddress; + uint64_t created = 0; + uint64_t modified = 0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct StatsEntry { + uint64_t timestamp=0; + uint64_t tx=0; + uint64_t rx=0; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct StatsBlock { + uint64_t modified=0; + std::vector external, internal; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; +} + +#endif //OWSUB_RESTAPI_SUBOBJECTS_H diff --git a/microservice_sample/src/StorageService.cpp b/microservice_sample/src/StorageService.cpp index ab7fc50..e137337 100644 --- a/microservice_sample/src/StorageService.cpp +++ b/microservice_sample/src/StorageService.cpp @@ -13,13 +13,12 @@ namespace OpenWifi { int Storage::Start() { std::lock_guard Guard(Mutex_); StorageClass::Start(); - return 0; } void Storage::Stop() { std::lock_guard Guard(Mutex_); - Logger_.notice("Stopping."); + Logger().notice("Stopping."); StorageClass::Stop(); } } diff --git a/microservice_sample/src/StorageService.h b/microservice_sample/src/StorageService.h index 78e1f31..612bc21 100644 --- a/microservice_sample/src/StorageService.h +++ b/microservice_sample/src/StorageService.h @@ -16,22 +16,20 @@ namespace OpenWifi { class Storage : public StorageClass { - public: - - static Storage *instance() { - static Storage * instance_ = new Storage; - return instance_; + static auto instance() { + static auto instance_ = new Storage; + return instance_; } - int Start() override; - void Stop() override; + int Start() override; + void Stop() override; - private: + private: - }; + }; - inline Storage * StorageService() { return Storage::instance(); } + inline auto StorageService() { return Storage::instance(); } } // namespace diff --git a/microservice_sample/src/framework/API_Proxy.h b/microservice_sample/src/framework/API_Proxy.h new file mode 100644 index 0000000..82fd2e6 --- /dev/null +++ b/microservice_sample/src/framework/API_Proxy.h @@ -0,0 +1,93 @@ +// +// Created by stephane bourque on 2021-11-30. +// + +#pragma once + +#include "framework/MicroService.h" +#include "Poco/JSON/Parser.h" + +namespace OpenWifi { + inline void API_Proxy( Poco::Logger &Logger, + Poco::Net::HTTPServerRequest *Request, + Poco::Net::HTTPServerResponse *Response, + const char * ServiceType, + const char * PathRewrite, + uint64_t msTimeout_ = 10000 ) { + try { + auto Services = MicroService::instance().GetServices(ServiceType); + for(auto const &Svc:Services) { + Poco::URI SourceURI(Request->getURI()); + Poco::URI DestinationURI(Svc.PrivateEndPoint); + DestinationURI.setPath(PathRewrite); + DestinationURI.setQuery(SourceURI.getQuery()); + + // std::cout << " Source: " << SourceURI.toString() << std::endl; + // std::cout << "Destination: " << DestinationURI.toString() << std::endl; + + Poco::Net::HTTPSClientSession Session(DestinationURI.getHost(), DestinationURI.getPort()); + Session.setKeepAlive(true); + Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000)); + Poco::Net::HTTPRequest ProxyRequest(Request->getMethod(), + DestinationURI.getPathAndQuery(), + Poco::Net::HTTPMessage::HTTP_1_1); + if(Request->has("Authorization")) { + ProxyRequest.add("Authorization", Request->get("Authorization")); + } else { + ProxyRequest.add("X-API-KEY", Svc.AccessKey); + ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); + } + + if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) { + Session.sendRequest(ProxyRequest); + Poco::Net::HTTPResponse ProxyResponse; + Session.receiveResponse(ProxyResponse); + Response->setStatus(ProxyResponse.getStatus()); + Response->send(); + return; + } else { + Poco::JSON::Parser P; + std::stringstream SS; + try { + auto Body = P.parse(Request->stream()).extract(); + Poco::JSON::Stringifier::condense(Body,SS); + SS << "\r\n\r\n"; + } catch(const Poco::Exception &E) { + Logger.log(E); + } + + if(SS.str().empty()) { + Session.sendRequest(ProxyRequest); + } else { + ProxyRequest.setContentType("application/json"); + ProxyRequest.setContentLength(SS.str().size()); + std::ostream & os = Session.sendRequest(ProxyRequest); + os << SS.str() ; + } + + Poco::Net::HTTPResponse ProxyResponse; + std::stringstream SSR; + try { + std::istream &ProxyResponseStream = Session.receiveResponse(ProxyResponse); + Poco::JSON::Parser P2; + auto ProxyResponseBody = P2.parse(ProxyResponseStream).extract(); + Poco::JSON::Stringifier::condense(ProxyResponseBody,SSR); + Response->setContentType("application/json"); + Response->setContentLength(SSR.str().size()); + Response->setStatus(ProxyResponse.getStatus()); + Response->sendBuffer(SSR.str().c_str(),SSR.str().size()); + return; + } catch( const Poco::Exception & E) { + + } + Response->setStatus(ProxyResponse.getStatus()); + Response->send(); + return; + } + } + + } catch (const Poco::Exception &E) { + Logger.log(E); + } + } +} \ No newline at end of file diff --git a/microservice_sample/src/framework/ConfigurationValidator.cpp b/microservice_sample/src/framework/ConfigurationValidator.cpp index b395909..5170ef6 100644 --- a/microservice_sample/src/framework/ConfigurationValidator.cpp +++ b/microservice_sample/src/framework/ConfigurationValidator.cpp @@ -13,2334 +13,2642 @@ namespace OpenWifi { - static const std::string GitUCentralJSONSchemaFile{"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; +static const std::string GitUCentralJSONSchemaFile{ + "https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; + +static json DefaultUCentralSchema = R"( - static json DefaultUCentralSchema = R"( { - "$id": "https://openwrt.org/ucentral.schema.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "properties": { - "uuid": { - "type": "integer" - }, - "unit": { - "$ref": "#/$defs/unit" - }, - "globals": { - "$ref": "#/$defs/globals" - }, - "definitions": { - "$ref": "#/$defs/definitions" - }, - "ethernet": { - "type": "array", - "items": { - "$ref": "#/$defs/ethernet" - } - }, - "switch": { - "$ref": "#/$defs/switch" - }, - "radios": { - "type": "array", - "items": { - "$ref": "#/$defs/radio" - } - }, - "interfaces": { - "type": "array", - "items": { - "$ref": "#/$defs/interface" - } - }, - "services": { - "$ref": "#/$defs/service" - }, - "metrics": { - "$ref": "#/$defs/metrics" - }, - "config-raw": { - "$ref": "#/$defs/config-raw" - }, - "third-party": { - "type": "object", - "additionalProperties": true - } - }, - "$defs": { - "unit": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "location": { - "type": "string" - }, - "timezone": { - "type": "string", - "examples": [ - "UTC", - "EST5", - "CET-1CEST,M3.5.0,M10.5.0/3" - ] - }, - "leds-active": { - "type": "boolean", - "default": true - }, - "random-password": { - "type": "boolean", - "default": false - } - } - }, - "globals.wireless-multimedia.class-selector": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "CS1", - "CS2", - "CS3", - "CS4", - "CS5", - "CS6", - "AF11", - "AF12", - "AF13", - "AF21", - "AF22", - "AF23", - "AF31", - "AF32", - "AF33", - "AF41", - "AF42", - "AF43", - "DF", - "EF" - ] - } - }, - "globals.wireless-multimedia": { - "type": "object", - "properties": { - "UP0": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP1": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP2": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP3": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP4": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP5": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP6": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - }, - "UP7": { - "$ref": "#/$defs/globals.wireless-multimedia.class-selector" - } - } - }, - "globals.wireless-multimedia-profile": { - "type": "string", - "enum": [ - "enterprise" - ] - }, - "globals": { - "type": "object", - "properties": { - "ipv4-network": { - "type": "string", - "format": "uc-cidr4", - "examples": [ - "192.168.0.0/16" - ] - }, - "ipv6-network": { - "type": "string", - "format": "uc-cidr6", - "examples": [ - "fdca:1234:4567::/48" - ] - }, - "wireless-multimedia": { - "oneOf": [ - { - "$ref": "#/$defs/globals.wireless-multimedia" - }, - { - "$ref": "#/$defs/globals.wireless-multimedia-profile" - } - ] - } - } - }, - "definitions": { - "type": "object", - "properties": { - "wireless-encryption": { - "type": "object", - "patternProperties": { - ".+": { - "$ref": "#/$defs/interface.ssid.encryption", - "additionalProperties": false - } - } - } - } - }, - "ethernet": { - "type": "object", - "properties": { - "select-ports": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "LAN1", - "LAN2", - "LAN3", - "LAN4", - "LAN*", - "WAN*", - "*" - ] - } - }, - "speed": { - "type": "integer", - "enum": [ - 10, - 100, - 1000, - 2500, - 5000, - 10000 - ] - }, - "duplex": { - "type": "string", - "enum": [ - "half", - "full" - ] - }, - "services": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "quality-of-service" - ] - } - } - } - }, - "switch": { - "type": "object", - "properties": { - "port-mirror": { - "type": "object", - "properties": { - "monitor-ports": { - "type": "array", - "items": { - "type": "string" - } - }, - "analysis-port": { - "type": "string" - } - } - }, - "loop-detection": { - "type": "object", - "properties": { - "protocol": { - "type": "string", - "enum": [ - "rstp" - ], - "default": "rstp" - }, - "roles": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "upstream", - "downstream" - ] - } - } - } - } - } - }, - "radio.rates": { - "type": "object", - "properties": { - "beacon": { - "type": "integer", - "default": 6000, - "enum": [ - 0, - 1000, - 2000, - 5500, - 6000, - 9000, - 11000, - 12000, - 18000, - 24000, - 36000, - 48000, - 54000 - ] - }, - "multicast": { - "type": "integer", - "default": 24000, - "enum": [ - 0, - 1000, - 2000, - 5500, - 6000, - 9000, - 11000, - 12000, - 18000, - 24000, - 36000, - 48000, - 54000 - ] - } - } - }, - "radio.he": { - "type": "object", - "properties": { - "multiple-bssid": { - "type": "boolean", - "default": false - }, - "ema": { - "type": "boolean", - "default": false - }, - "bss-color": { - "type": "integer", - "default": 64 - } - } - }, - "radio": { - "type": "object", - "properties": { - "band": { - "type": "string", - "enum": [ - "2G", - "5G", - "5G-lower", - "5G-upper", - "6G" - ] - }, - "bandwidth": { - "type": "integer", - "enum": [ - 5, - 10, - 20 - ] - }, - "channel": { - "oneOf": [ - { - "type": "integer", - "maximum": 171, - "minimum": 1 - }, - { - "type": "string", - "const": "auto" - } - ] - }, - "country": { - "type": "string", - "maxLength": 2, - "minLength": 2, - "examples": [ - "US" - ] - }, - "channel-mode": { - "type": "string", - "enum": [ - "HT", - "VHT", - "HE" - ], - "default": "HE" - }, - "channel-width": { - "type": "integer", - "enum": [ - 20, - 40, - 80, - 160, - 8080 - ], - "default": 80 - }, - "require-mode": { - "type": "string", - "enum": [ - "HT", - "VHT", - "HE" - ] - }, - "mimo": { - "type": "string", - "enum": [ - "1x1", - "2x2", - "3x3", - "4x4", - "5x5", - "6x6", - "7x7", - "8x8" - ] - }, - "tx-power": { - "type": "integer", - "maximum": 30, - "minimum": 0 - }, - "legacy-rates": { - "type": "boolean", - "default": false - }, - "beacon-interval": { - "type": "integer", - "default": 100, - "maximum": 65535, - "minimum": 15 - }, - "dtim-period": { - "type": "integer", - "default": 2, - "maximum": 255, - "minimum": 1 - }, - "maximum-clients": { - "type": "integer", - "example": 64 - }, - "rates": { - "$ref": "#/$defs/radio.rates" - }, - "he-settings": { - "$ref": "#/$defs/radio.he" - }, - "hostapd-iface-raw": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "ap_table_expiration_time=3600", - "device_type=6-0050F204-1", - "ieee80211h=1", - "rssi_ignore_probe_request=-75", - "time_zone=EST5", - "uuid=12345678-9abc-def0-1234-56789abcdef0", - "venue_url=1:http://www.example.com/info-eng", - "wpa_deny_ptk0_rekey=0" - ] - } - } - } - }, - "interface.vlan": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "maximum": 4050 - }, - "proto": { - "decription": "The L2 vlan tag that shall be added (1q,1ad) ", - "type": "string", - "enum": [ - "802.1ad", - "802.1q" - ], - "default": "802.1q" + "$id": "https://openwrt.org/ucentral.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "uuid": { + "type": "integer" + }, + "unit": { + "$ref": "#/$defs/unit" + }, + "globals": { + "$ref": "#/$defs/globals" + }, + "definitions": { + "$ref": "#/$defs/definitions" + }, + "ethernet": { + "type": "array", + "items": { + "$ref": "#/$defs/ethernet" + } + }, + "switch": { + "$ref": "#/$defs/switch" + }, + "radiosgrep": { + "type": "array", + "items": { + "$ref": "#/$defs/radio" + } + }, + "interfaces": { + "type": "array", + "items": { + "$ref": "#/$defs/interface" + } + }, + "services": { + "$ref": "#/$defs/service" + }, + "metrics": { + "$ref": "#/$defs/metrics" + }, + "config-raw": { + "$ref": "#/$defs/config-raw" + }, + "third-party": { + "type": "object", + "additionalProperties": true + } + }, + "$defs": { + "unit": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "hostname": { + "type": "string", + "format": "hostname" + }, + "location": { + "type": "string" + }, + "timezone": { + "type": "string", + "examples": [ + "UTC", + "EST5", + "CET-1CEST,M3.5.0,M10.5.0/3" + ] + }, + "leds-active": { + "type": "boolean", + "default": true + }, + "random-password": { + "type": "boolean", + "default": false + } + } + }, + "globals.wireless-multimedia.class-selector": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "CS0", + "CS1", + "CS2", + "CS3", + "CS4", + "CS5", + "CS6", + "CS7", + "AF11", + "AF12", + "AF13", + "AF21", + "AF22", + "AF23", + "AF31", + "AF32", + "AF33", + "AF41", + "AF42", + "AF43", + "DF", + "EF", + "VA", + "LE" + ] + } + }, + "globals.wireless-multimedia.table": { + "type": "object", + "additionalProperties": false, + "properties": { + "UP0": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP1": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP2": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP3": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP4": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP5": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP6": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + }, + "UP7": { + "$ref": "#/$defs/globals.wireless-multimedia.class-selector" + } + } + }, + "globals.wireless-multimedia.profile": { + "type": "object", + "additionalProperties": false, + "properties": { + "profile": { + "type": "string", + "enum": [ + "enterprise", + "rfc8325", + "3gpp" + ] + } + } + }, + "globals": { + "type": "object", + "properties": { + "ipv4-network": { + "type": "string", + "format": "uc-cidr4", + "examples": [ + "192.168.0.0/16" + ] + }, + "ipv6-network": { + "type": "string", + "format": "uc-cidr6", + "examples": [ + "fdca:1234:4567::/48" + ] + }, + "wireless-multimedia": { + "anyOf": [{ + "$ref": "#/$defs/globals.wireless-multimedia.table" + }, + { + "$ref": "#/$defs/globals.wireless-multimedia.profile" + } + ] + } + } + }, + "definitions": { + "type": "object", + "properties": { + "wireless-encryption": { + "type": "object", + "patternProperties": { + ".+": { + "$ref": "#/$defs/interface.ssid.encryption", + "additionalProperties": false + } + } + } + } + }, + "ethernet": { + "type": "object", + "properties": { + "select-ports": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "LAN1", + "LAN2", + "LAN3", + "LAN4", + "LAN*", + "WAN*", + "*" + ] + } + }, + "speed": { + "type": "integer", + "enum": [ + 10, + 100, + 1000, + 2500, + 5000, + 10000 + ] + }, + "duplex": { + "type": "string", + "enum": [ + "half", + "full" + ] + }, + "services": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "quality-of-service" + ] + } + } + } + }, + "switch": { + "type": "object", + "properties": { + "port-mirror": { + "type": "object", + "properties": { + "monitor-ports": { + "type": "array", + "items": { + "type": "string" + } + }, + "analysis-port": { + "type": "string" + } + } + }, + "loop-detection": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "enum": [ + "rstp" + ], + "default": "rstp" + }, + "roles": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "upstream", + "downstream" + ] + } + } + } + } + } + }, + "radio.rates": { + "type": "object", + "properties": { + "beacon": { + "type": "integer", + "default": 6000, + "enum": [ + 0, + 1000, + 2000, + 5500, + 6000, + 9000, + 11000, + 12000, + 18000, + 24000, + 36000, + 48000, + 54000 + ] + }, + "multicast": { + "type": "integer", + "default": 24000, + "enum": [ + 0, + 1000, + 2000, + 5500, + 6000, + 9000, + 11000, + 12000, + 18000, + 24000, + 36000, + 48000, + 54000 + ] + } + } + }, + "radio.he": { + "type": "object", + "properties": { + "multiple-bssid": { + "type": "boolean", + "default": false + }, + "ema": { + "type": "boolean", + "default": false + }, + "bss-color": { + "type": "integer", + "default": 64 + } + } + }, + "radio": { + "type": "object", + "properties": { + "band": { + "type": "string", + "enum": [ + "2G", + "5G", + "5G-lower", + "5G-upper", + "6G" + ] + }, + "bandwidth": { + "type": "integer", + "enum": [ + 5, + 10, + 20 + ] + }, + "channel": { + "oneOf": [{ + "type": "integer", + "maximum": 196, + "minimum": 1 + }, + { + "type": "string", + "const": "auto" + } + ] + }, + "valid-channels": { + "type": "array", + "items": { + "type": "integer", + "maximum": 196, + "minimum": 1 + } + }, + "country": { + "type": "string", + "maxLength": 2, + "minLength": 2, + "examples": [ + "US" + ] + }, + "allow-dfs": { + "type": "boolean", + "default": true + }, + "channel-mode": { + "type": "string", + "enum": [ + "HT", + "VHT", + "HE" + ], + "default": "HE" + }, + "channel-width": { + "type": "integer", + "enum": [ + 20, + 40, + 80, + 160, + 8080 + ], + "default": 80 + }, + "require-mode": { + "type": "string", + "enum": [ + "HT", + "VHT", + "HE" + ] + }, + "mimo": { + "type": "string", + "enum": [ + "1x1", + "2x2", + "3x3", + "4x4", + "5x5", + "6x6", + "7x7", + "8x8" + ] + }, + "tx-power": { + "type": "integer", + "maximum": 30, + "minimum": 0 + }, + "legacy-rates": { + "type": "boolean", + "default": false + }, + "beacon-interval": { + "type": "integer", + "default": 100, + "maximum": 65535, + "minimum": 15 + }, + "dtim-period": { + "type": "integer", + "default": 2, + "maximum": 255, + "minimum": 1 + }, + "maximum-clients": { + "type": "integer", + "example": 64 + }, + "rates": { + "$ref": "#/$defs/radio.rates" + }, + "he-settings": { + "$ref": "#/$defs/radio.he" + }, + "hostapd-iface-raw": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "ap_table_expiration_time=3600", + "device_type=6-0050F204-1", + "ieee80211h=1", + "rssi_ignore_probe_request=-75", + "time_zone=EST5", + "uuid=12345678-9abc-def0-1234-56789abcdef0", + "venue_url=1:http://www.example.com/info-eng", + "wpa_deny_ptk0_rekey=0" + ] + } + } + } + }, + "interface.vlan": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "maximum": 4050 + }, + "proto": { + "decription": "The L2 vlan tag that shall be added (1q,1ad ) ", + "type": "string", + "enum": [ + "802.1ad", + "802.1q" + ], + "default": "802.1q" + } + } + }, + "interface.bridge": { + "type": "object", + "properties": { + "mtu": { + "type": "integer", + "maximum": 65535, + "minimum": 256, + "examples": [ + 1500 + ] + }, + "tx-queue-len": { + "type": "integer", + "examples": [ + 5000 + ] + }, + "isolate-ports": { + "type": "boolean", + "default": false + } + } + }, + "interface.ethernet": { + "type": "object", + "properties": { + "select-ports": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "LAN1", + "LAN2", + "LAN3", + "LAN4", + "LAN*", + "WAN*", + "*" + ] + } + }, + "multicast": { + "type": "boolean", + "default": true + }, + "learning": { + "type": "boolean", + "default": true + }, + "isolate": { + "type": "boolean", + "default": false + }, + "macaddr": { + "type": "string", + "format": "uc-mac" + }, + "reverse-path-filter": { + "type": "boolean", + "default": false + }, + "vlan-tag": { + "type": "string", + "enum": [ + "tagged", + "un-tagged", + "auto" + ], + "default": "auto" + } + } + }, + "interface.ipv4.dhcp": { + "type": "object", + "properties": { + "lease-first": { + "type": "integer", + "examples": [ + 10 + ] + }, + "lease-count": { + "type": "integer", + "examples": [ + 100 + ] + }, + "lease-time": { + "type": "string", + "format": "uc-timeout", + "default": "6h" + }, + "relay-server": { + "type": "string", + "format": "ipv4", + "example": "192.168.2.1" + }, + "circuit-id-format": { + "type": "string", + "example": [ + "\\{Interface\\}:\\{VLAN-Id\\}:\\{SSID\\}:\\{Model\\}:\\{Name\\}:\\{AP-MAC\\}:\\{Location\\}", + "\\{AP-MAC\\};\\{SSID\\};\\{Crypto\\}", + "\\{Name\\} \\{ESSID\\}" + ] + }, + "remote-id-format": { + "type": "string", + "example": [ + "\\{Client-MAC-hex\\} \\{SSID\\}", + "\\{AP-MAC-hex\\} \\{SSID\\}" + ] + } + } + }, + "interface.ipv4.dhcp-lease": { + "type": "object", + "properties": { + "macaddr": { + "type": "string", + "format": "uc-mac", + "examples": [ + "00:11:22:33:44:55" + ] + }, + "static-lease-offset": { + "type": "integer", + "examples": [ + 10 + ] + }, + "lease-time": { + "type": "string", + "format": "uc-timeout", + "default": "6h" + }, + "publish-hostname": { + "type": "boolean", + "default": true + } + } + }, + "interface.ipv4.port-forward": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "enum": [ + "tcp", + "udp", + "any" + ], + "default": "any" + }, + "external-port": { + "type": [ + "integer", + "string" + ], + "minimum": 0, + "maximum": 65535, + "format": "uc-portrange" + }, + "internal-address": { + "type": "string", + "format": "ipv4", + "example": "0.0.0.120" + }, + "internal-port": { + "type": [ + "integer", + "string" + ], + "minimum": 0, + "maximum": 65535, + "format": "uc-portrange" + } + }, + "required": [ + "external-port", + "internal-address" + ] + }, + "interface.ipv4": { + "type": "object", + "properties": { + "addressing": { + "type": "string", + "enum": [ + "dynamic", + "static" + ], + "examples": [ + "static" + ] + }, + "subnet": { + "type": "string", + "format": "uc-cidr4", + "examples": [ + "auto/24" + ] + }, + "gateway": { + "type": "string", + "format": "ipv4", + "examples": [ + "192.168.1.1" + ] + }, + "send-hostname": { + "type": "boolean", + "default": true, + "examples": [ + true + ] + }, + "use-dns": { + "type": "array", + "items": { + "type": "string", + "format": "ipv4", + "examples": [ + "8.8.8.8", + "4.4.4.4" + ] + } + }, + "dhcp": { + "$ref": "#/$defs/interface.ipv4.dhcp" + }, + "dhcp-leases": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ipv4.dhcp-lease" + } + }, + "port-forward": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ipv4.port-forward" + } + } + } + }, + "interface.ipv6.dhcpv6": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "hybrid", + "stateless", + "stateful", + "relay" + ] + }, + "announce-dns": { + "type": "array", + "items": { + "type": "string", + "format": "ipv6" + } + }, + "filter-prefix": { + "type": "string", + "format": "uc-cidr6", + "default": "::/0" + } + } + }, + "interface.ipv6.port-forward": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "enum": [ + "tcp", + "udp", + "any" + ], + "default": "any" + }, + "external-port": { + "type": [ + "integer", + "string" + ], + "minimum": 0, + "maximum": 65535, + "format": "uc-portrange" + }, + "internal-address": { + "type": "string", + "format": "ipv6", + "example": "::1234:abcd" + }, + "internal-port": { + "type": [ + "integer", + "string" + ], + "minimum": 0, + "maximum": 65535, + "format": "uc-portrange" + } + }, + "required": [ + "external-port", + "internal-address" + ] + }, + "interface.ipv6.traffic-allow": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "default": "any" + }, + "source-address": { + "type": "string", + "format": "uc-cidr6", + "example": "2001:db8:1234:abcd::/64", + "default": "::/0" + }, + "source-ports": { + "type": "array", + "minItems": 1, + "items": { + "type": [ + "integer", + "string" + ], + "minimum": 0, + "maximum": 65535, + "format": "uc-portrange" + } + }, + "destination-address": { + "type": "string", + "format": "ipv6", + "example": "::1000" + }, + "destination-ports": { + "type": "array", + "minItems": 1, + "items": { + "type": [ + "integer", + "string" + ], + "minimum": 0, + "maximum": 65535, + "format": "uc-portrange" + } + } + }, + "required": [ + "destination-address" + ] + }, + "interface.ipv6": { + "type": "object", + "properties": { + "addressing": { + "type": "string", + "enum": [ + "dynamic", + "static" + ] + }, + "subnet": { + "type": "string", + "format": "uc-cidr6", + "examples": [ + "auto/64" + ] + }, + "gateway": { + "type": "string", + "format": "ipv6", + "examples": [ + "2001:db8:123:456::1" + ] + }, + "prefix-size": { + "type": "integer", + "maximum": 64, + "minimum": 0 + }, + "dhcpv6": { + "$ref": "#/$defs/interface.ipv6.dhcpv6" + }, + "port-forward": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ipv6.port-forward" + } + }, + "traffic-allow": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ipv6.traffic-allow" + } + } + } + }, + "interface.broad-band.wwan": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "const": "wwan" + }, + "modem-type": { + "type": "string", + "enum": [ + "qmi", + "mbim", + "wwan" + ] + }, + "access-point-name": { + "type": "string" + }, + "authentication-type": { + "type": "string", + "enum": [ + "none", + "pap", + "chap", + "pap-chap" + ], + "default": "none" + }, + "pin-code": { + "type": "string" + }, + "user-name": { + "type": "string" + }, + "password": { + "type": "string" + }, + "packet-data-protocol": { + "type": "string", + "enum": [ + "ipv4", + "ipv6", + "dual-stack" + ], + "default": "dual-stack" + } + } + }, + "interface.broad-band.pppoe": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "const": "pppoe" + }, + "user-name": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "interface.broad-band": { + "oneOf": [{ + "$ref": "#/$defs/interface.broad-band.wwan" + }, + { + "$ref": "#/$defs/interface.broad-band.pppoe" + } + ] + }, + "interface.captive": { + "type": "object", + "properties": { + "gateway-name": { + "type": "string", + "default": "uCentral - Captive Portal" + }, + "gateway-fqdn": { + "type": "string", + "format": "uc-fqdn", + "default": "ucentral.splash" + }, + "max-clients": { + "type": "integer", + "default": 32 + }, + "upload-rate": { + "type": "integer", + "default": 0 + }, + "download-rate": { + "type": "integer", + "default": 0 + }, + "upload-quota": { + "type": "integer", + "default": 0 + }, + "download-quota": { + "type": "integer", + "default": 0 + } + } + }, + "interface.ssid.encryption": { + "type": "object", + "properties": { + "proto": { + "type": "string", + "enum": [ + "none", + "psk", + "psk2", + "psk-mixed", + "psk2-radius", + "wpa", + "wpa2", + "wpa-mixed", + "sae", + "sae-mixed", + "wpa3", + "wpa3-192", + "wpa3-mixed" + ], + "examples": [ + "psk2" + ] + }, + "key": { + "type": "string", + "maxLength": 63, + "minLength": 8 + }, + "ieee80211w": { + "type": "string", + "enum": [ + "disabled", + "optional", + "required" + ], + "default": "disabled" + } + } + }, + "interface.ssid.multi-psk": { + "type": "object", + "properties": { + "mac": { + "type": "string", + "format": "uc-mac" + }, + "key": { + "type": "string", + "maxLength": 63, + "minLength": 8 + }, + "vlan-id": { + "type": "integer", + "maximum": 4096, + "examples": [ + 3, + 100, + 200, + 4094 + ] + } + } + }, + "interface.ssid.rrm": { + "type": "object", + "properties": { + "neighbor-reporting": { + "type": "boolean", + "default": false + }, + "reduced-neighbor-reporting": { + "type": "boolean", + "default": false + }, + "lci": { + "type": "string" + }, + "civic-location": { + "type": "string" + }, + "ftm-responder": { + "type": "boolean", + "default": false + }, + "stationary-ap": { + "type": "boolean", + "default": false + } + } + }, + "interface.ssid.rate-limit": { + "type": "object", + "properties": { + "ingress-rate": { + "type": "integer", + "default": 0 + }, + "egress-rate": { + "type": "integer", + "default": 0 + } + } + }, + "interface.ssid.roaming": { + "type": "object", + "properties": { + "message-exchange": { + "type": "string", + "enum": [ + "air", + "ds" + ], + "default": "ds" + }, + "generate-psk": { + "type": "boolean", + "default": false + }, + "domain-identifier": { + "type": "string", + "maxLength": 4, + "minLength": 4, + "examples": [ + "abcd" + ] + }, + "pmk-r0-key-holder": { + "type": "string", + "example": "14:DD:20:47:14:E4,14DD204714E4,00112233445566778899aabbccddeeff" + }, + "pmk-r1-key-holder": { + "type": "string", + "example": "14:DD:20:47:14:E4,14DD204714E4,00112233445566778899aabbccddeeff" + } + } + }, + "interface.ssid.radius.local-user": { + "type": "object", + "properties": { + "mac": { + "type": "string", + "format": "uc-mac" + }, + "user-name": { + "type": "string", + "minLength": 1 + }, + "password": { + "type": "string", + "maxLength": 63, + "minLength": 8 + }, + "vlan-id": { + "type": "integer", + "maximum": 4096, + "examples": [ + 3, + 100, + 200, + 4094 + ] + } + } + }, + "interface.ssid.radius.local": { + "type": "object", + "properties": { + "server-identity": { + "type": "string", + "default": "uCentral" + }, + "users": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ssid.radius.local-user" + } + } + } + }, + "interface.ssid.radius.server": { + "type": "object", + "properties": { + "host": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 1024, + "examples": [ + 1812 + ] + }, + "secret": { + "type": "string", + "examples": [ + "secret" + ] + }, + "request-attribute": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "maximum": 255, + "minimum": 1 + }, + "value": { + "anyOf": [{ + "type": "integer", + "maximum": 4294967295, + "minimum": 0 + }, + { + "type": "string" + } + ] + } + }, + "examples": [{ + "id": 27, + "value": 900 + }, + { + "id": 32, + "value": "My NAS ID" + }, + { + "id": 56, + "value": 1004 + }, + { + "id": 126, + "value": "Example Operator" + } + ] + }, + "examples": [ + "126:s:Operator" + ] + } + } + }, + "interface.ssid.radius": { + "type": "object", + "properties": { + "nas-identifier": { + "type": "string" + }, + "chargeable-user-id": { + "type": "boolean", + "default": false + }, + "local": { + "$ref": "#/$defs/interface.ssid.radius.local" + }, + "dynamic-authorization": { + "type": "object", + "properties": { + "host": { + "type": "string", + "format": "uc-ip", + "examples": [ + "192.168.1.10" + ] + }, + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 1024, + "examples": [ + 1812 + ] + }, + "secret": { + "type": "string", + "examples": [ + "secret" + ] + } + } + }, + "authentication": { + "allOf": [{ + "$ref": "#/$defs/interface.ssid.radius.server" + }, + { + "type": "object", + "properties": { + "mac-filter": { + "type": "boolean", + "default": false + } + } + } + ] + }, + "accounting": { + "allOf": [{ + "$ref": "#/$defs/interface.ssid.radius.server" + }, + { + "type": "object", + "properties": { + "interval": { + "type": "integer", + "maximum": 600, + "minimum": 60, + "default": 60 + } + } + } + ] + } + } + }, + "interface.ssid.certificates": { + "type": "object", + "properties": { + "use-local-certificates": { + "type": "boolean", + "default": false + }, + "ca-certificate": { + "type": "string" + }, + "certificate": { + "type": "string" + }, + "private-key": { + "type": "string" + }, + "private-key-password": { + "type": "string" + } + } + }, + "interface.ssid.pass-point": { + "type": "object", + "properties": { + "venue-name": { + "type": "array", + "items": { + "type": "string" + } + }, + "venue-group": { + "type": "integer", + "maximum": 32 + }, + "venue-type": { + "type": "integer", + "maximum": 32 + }, + "venue-url": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + } + }, + "auth-type": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "terms-and-conditions", + "online-enrollment", + "http-redirection", + "dns-redirection" + ] + }, + "uri": { + "type": "string", + "format": "uri", + "examples": [ + "https://operator.example.org/wireless-access/terms-and-conditions.html", + "http://www.example.com/redirect/me/here/" + ] + } + }, + "minLength": 2, + "maxLength": 2 + }, + "domain-name": { + "type": "array", + "items": { + "type": "string", + "format": "hostname" + } + }, + "nai-realm": { + "type": "array", + "items": { + "type": "string" + } + }, + "osen": { + "type": "boolean" + }, + "anqp-domain": { + "type": "integer", + "maximum": 65535, + "minimum": 0 + }, + "anqp-3gpp-cell-net": { + "type": "array", + "items": { + "type": "string" + } + }, + "friendly-name": { + "type": "array", + "items": { + "type": "string" + } + }, + "access-network-type": { + "type": "integer", + "maximum": 15, + "default": 0 + }, + "internet": { + "type": "boolean", + "default": true + }, + "asra": { + "type": "boolean", + "default": false + }, + "esr": { + "type": "boolean", + "default": false + }, + "uesa": { + "type": "boolean", + "default": false + }, + "hessid": { + "type": "string", + "example": "00:11:22:33:44:55" + }, + "roaming-consortium": { + "type": "array", + "items": { + "type": "string" + } + }, + "disable-dgaf": { + "type": "boolean", + "default": false + }, + "ipaddr-type-available": { + "type": "integer", + "maximum": 255 + }, + "connection-capability": { + "type": "array", + "items": { + "type": "string" + } + }, + "icons": { + "type": "array", + "items": { + "type": "object", + "properties": { + "width": { + "type": "integer", + "examples": [ + 64 + ] + }, + "height": { + "type": "integer", + "examples": [ + 64 + ] + }, + "type": { + "type": "string", + "examples": [ + "image/png" + ] + }, + "icon": { + "type": "string", + "format": "uc-base64" + }, + "language": { + "type": "string", + "pattern": "^[a-z][a-z][a-z]$", + "examples": [ + "eng", + "fre", + "ger", + "ita" + ] + } + }, + "examples": [{ + "width": 32, + "height": 32, + "type": "image/png", + "language": "eng", + "icon": "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" + }] + } + }, + "wan-metrics": { + "type": "object", + "properties": { + "info": { + "type": "string", + "enum": [ + "up", + "down", + "testing" + ] + }, + "downlink": { + "type": "integer" + }, + "uplink": { + "type": "integer" + } + } + } + } + }, + "interface.ssid.quality-thresholds": { + "type": "object", + "properties": { + "probe-request-rssi": { + "type": "integer" + }, + "association-request-rssi": { + "type": "integer" + } + } + }, + "interface.ssid": { + "type": "object", + "properties": { + "purpose": { + "type": "string", + "enum": [ + "user-defined", + "onboarding-ap", + "onboarding-sta" + ], + "default": "user-defined" + }, + "name": { + "type": "string", + "maxLength": 32, + "minLength": 1 + }, + "wifi-bands": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "2G", + "5G", + "5G-lower", + "5G-upper", + "6G" + ] + } + }, + "bss-mode": { + "type": "string", + "enum": [ + "ap", + "sta", + "mesh", + "wds-ap", + "wds-sta", + "wds-repeater" + ], + "default": "ap" + }, + "bssid": { + "type": "string", + "format": "uc-mac" + }, + "hidden-ssid": { + "type": "boolean" + }, + "isolate-clients": { + "type": "boolean" + }, + "power-save": { + "type": "boolean" + }, + "rts-threshold": { + "type": "integer", + "maximum": 65535, + "minimum": 1 + }, + "broadcast-time": { + "type": "boolean" + }, + "unicast-conversion": { + "type": "boolean" + }, + "services": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "wifi-steering" + ] + } + }, + "maximum-clients": { + "type": "integer", + "example": 64 + }, + "proxy-arp": { + "type": "boolean", + "default": true + }, + "disassoc-low-ack": { + "decription": "Disassociate stations based on excessive transmission failures or other indications of connection loss.", + "type": "boolean", + "default": false + }, + "vendor-elements": { + "decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", + "type": "string" + }, + "fils-discovery-interval": { + "type": "integer", + "default": 20, + "maximum": 10000 + }, + "encryption": { + "$ref": "#/$defs/interface.ssid.encryption" + }, + "multi-psk": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ssid.multi-psk" + } + }, + "rrm": { + "$ref": "#/$defs/interface.ssid.rrm" + }, + "rate-limit": { + "$ref": "#/$defs/interface.ssid.rate-limit" + }, + "roaming": { + "$ref": "#/$defs/interface.ssid.roaming" + }, + "radius": { + "$ref": "#/$defs/interface.ssid.radius" + }, + "certificates": { + "$ref": "#/$defs/interface.ssid.certificates" + }, + "pass-point": { + "$ref": "#/$defs/interface.ssid.pass-point" + }, + "quality-thresholds": { + "$ref": "#/$defs/interface.ssid.quality-thresholds" + }, + "hostapd-bss-raw": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "ap_table_expiration_time=3600", + "device_type=6-0050F204-1", + "ieee80211h=1", + "rssi_ignore_probe_request=-75", + "time_zone=EST5", + "uuid=12345678-9abc-def0-1234-56789abcdef0", + "venue_url=1:http://www.example.com/info-eng", + "wpa_deny_ptk0_rekey=0" + ] + } + } + } + }, + "interface.tunnel.mesh": { + "type": "object", + "properties": { + "proto": { + "type": "string", + "const": "mesh" + } + } + }, + "interface.tunnel.vxlan": { + "type": "object", + "properties": { + "proto": { + "type": "string", + "const": "vxlan" + }, + "peer-address": { + "type": "string", + "format": "ipv4", + "example": "192.168.100.1" + }, + "peer-port": { + "type": "integer", + "maximum": 65535, + "minimum": 1, + "examples": [ + 4789 + ] + } + } + }, + "interface.tunnel.l2tp": { + "type": "object", + "properties": { + "proto": { + "type": "string", + "const": "l2tp" + }, + "server": { + "type": "string", + "format": "ipv4", + "example": "192.168.100.1" + }, + "user-name": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "interface.tunnel.gre": { + "type": "object", + "properties": { + "proto": { + "type": "string", + "const": "gre" + }, + "peer-address": { + "type": "string", + "format": "ipv4", + "example": "192.168.100.1" + } + } + }, + "interface.tunnel": { + "oneOf": [{ + "$ref": "#/$defs/interface.tunnel.mesh" + }, + { + "$ref": "#/$defs/interface.tunnel.vxlan" + }, + { + "$ref": "#/$defs/interface.tunnel.l2tp" + }, + { + "$ref": "#/$defs/interface.tunnel.gre" + } + ] + }, + "interface": { + "type": "object", + "properties": { + "name": { + "type": "string", + "examples": [ + "LAN" + ] + }, + "role": { + "type": "string", + "enum": [ + "upstream", + "downstream" + ] + }, + "isolate-hosts": { + "type": "boolean" + }, + "metric": { + "type": "integer", + "maximum": 4294967295, + "minimum": 0 + }, + "services": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "ssh", + "lldp" + ] + } + }, + "vlan": { + "$ref": "#/$defs/interface.vlan" + }, + "bridge": { + "$ref": "#/$defs/interface.bridge" + }, + "ethernet": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ethernet" + } + }, + "ipv4": { + "$ref": "#/$defs/interface.ipv4" + }, + "ipv6": { + "$ref": "#/$defs/interface.ipv6" + }, + "broad-band": { + "$ref": "#/$defs/interface.broad-band" + }, + "captive": { + "$ref": "#/$defs/interface.captive" + }, + "ssids": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ssid" + } + }, + "tunnel": { + "$ref": "#/$defs/interface.tunnel" + } + } + }, + "service.lldp": { + "type": "object", + "properties": { + "describe": { + "type": "string", + "default": "uCentral Access Point" + }, + "location": { + "type": "string", + "default": "uCentral Network" + } + } + }, + "service.ssh": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "maximum": 65535, + "default": 22 + }, + "authorized-keys": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC0ghdSd2D2y08TFowZLMZn3x1/Djw3BkNsIeHt/Z+RaXwvfV1NQAnNdaOngMT/3uf5jZtYxhpl+dbZtRhoUPRvKflKBeFHYBqjZVzD3r4ns2Ofm2UpHlbdOpMuy9oeTSCeF0IKZZ6szpkvSirQogeP2fe9KRkzQpiza6YxxaJlWw== user@example", + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ4FDjyCsg+1Mh2C5G7ibR3z0Kw1dU57kfXebLRwS6CL bob@work", + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP/JpJ/KHtKKImzISBDwLO0/EwytIr4pGZQXcP6GCSHchLMyfjf147KNlF9gC+3FibzqKH02EiQspVhRgfuK6y0= alice@home" + ] + } + }, + "password-authentication": { + "type": "boolean", + "default": true + } + } + }, + "service.ntp": { + "type": "object", + "properties": { + "servers": { + "type": "array", + "items": { + "type": "string", + "format": "uc-host" + }, + "examples": [ + "0.openwrt.pool.ntp.org" + ] + }, + "local-server": { + "type": "boolean", + "examples": [ + true + ] + } + } + }, + "service.mdns": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "default": false + } + } + }, + "service.rtty": { + "type": "object", + "properties": { + "host": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "port": { + "type": "integer", + "maximum": 65535, + "default": 5912 + }, + "token": { + "type": "string", + "maxLength": 32, + "minLength": 32, + "examples": [ + "01234567890123456789012345678901" + ] + } + } + }, + "service.log": { + "type": "object", + "properties": { + "host": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 100, + "examples": [ + 2000 + ] + }, + "proto": { + "type": "string", + "enum": [ + "tcp", + "udp" + ], + "default": "udp" + }, + "size": { + "type": "integer", + "minimum": 32, + "default": 1000 + }, + "priority": { + "type": "integer", + "minimum": 0, + "default": 7 + } + } + }, + "service.http": { + "type": "object", + "properties": { + "http-port": { + "type": "integer", + "maximum": 65535, + "minimum": 1, + "default": 80 + } + } + }, + "service.igmp": { + "type": "object", + "properties": { + "enable": { + "type": "boolean", + "default": false + } + } + }, + "service.ieee8021x": { + "type": "object", + "properties": { + "ca-certificate": { + "type": "string" + }, + "use-local-certificates": { + "type": "boolean", + "default": false + }, + "server-certificate": { + "type": "string" + }, + "private-key": { + "type": "string" + }, + "users": { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ssid.radius.local-user" + } + } + } + }, + "service.radius-proxy": { + "type": "object", + "properties": { + "realms": { + "type": "array", + "items": { + "type": "object", + "properties": { + "realm": { + "type": "string", + "default": "*" + }, + "auto-discover": { + "type": "boolean", + "default": false + }, + "host": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + }, + "port": { + "type": "integer", + "maximum": 65535, + "default": 2083 + }, + "secret": { + "type": "string" + }, + "use-local-certificates": { + "type": "boolean", + "default": false + }, + "ca-certificate": { + "type": "string" + }, + "certificate": { + "type": "string" + }, + "private-key": { + "type": "string" + }, + "private-key-password": { + "type": "string" + } + } + } + } + } + }, + "service.online-check": { + "type": "object", + "properties": { + "ping-hosts": { + "type": "array", + "items": { + "type": "string", + "format": "uc-host", + "examples": [ + "192.168.1.10" + ] + } + }, + "download-hosts": { + "type": "array", + "items": { + "type": "string", + "examples": [ + "www.example.org" + ] + } + }, + "check-interval": { + "type": "number", + "default": 60 + }, + "check-threshold": { + "type": "number", + "default": 1 + }, + "action": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "wifi", + "leds" + ] + } + } + } + }, + "service.open-flow": { + "type": "object", + "properties": { + "controller": { + "type": "string", + "format": "uc-ip", + "example": "192.168.10.1" + }, + "datapath-description": { + "type": "string", + "example": "Building 2, Floor 6, AP 2" + }, + "mode": { + "type": "string", + "enum": [ + "pssl", + "ptcp", + "ssl", + "tcp" + ], + "default": "ssl" + }, + "port": { + "type": "integer", + "maximum": 65535, + "default": 6653 + }, + "ca-certificate": { + "type": "string" + }, + "ssl-certificate": { + "type": "string" + }, + "private-key": { + "type": "string" + } + } + }, + "service.data-plane": { + "type": "object", + "properties": { + "ingress-filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "program": { + "type": "string", + "format": "uc-base64" + } + } + } + } + } + }, + "service.wifi-steering": { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "local", + "cloud" + ], + "examples": [ + "local" + ] + }, + "assoc-steering": { + "type": "boolean", + "default": false + }, + "required-snr": { + "type": "integer", + "default": 0 + }, + "required-probe-snr": { + "type": "integer", + "default": 0 + }, + "required-roam-snr": { + "type": "integer", + "default": 0 + }, + "load-kick-threshold": { + "type": "integer", + "default": 0 + }, + "auto-channel": { + "type": "boolean", + "default": false + }, + "ipv6": { + "type": "boolean", + "default": false + } + } + }, + "service.quality-of-service.class-selector": { + "type": "string", + "enum": [ + "CS0", + "CS1", + "CS2", + "CS3", + "CS4", + "CS5", + "CS6", + "CS7", + "AF11", + "AF12", + "AF13", + "AF21", + "AF22", + "AF23", + "AF31", + "AF32", + "AF33", + "AF41", + "AF42", + "AF43", + "DF", + "EF", + "VA", + "LE" + ] + }, + "service.quality-of-service": { + "type": "object", + "properties": { + "select-ports": { + "type": "array", + "items": { + "type": "string", + "default": "WAN" + } + }, + "bandwidth-up": { + "type": "integer", + "default": 0 + }, + "bandwidth-down": { + "type": "integer", + "default": 0 + }, + "bulk-detection": { + "type": "object", + "properties": { + "dscp": { + "$ref": "#/$defs/service.quality-of-service.class-selector", + "default": "CS0" + }, + "packets-per-second": { + "type": "number", + "default": 0 + } + } + }, + "classifier": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dscp": { + "$ref": "#/$defs/service.quality-of-service.class-selector", + "default": "CS1" + }, + "ports": { + "type": "array", + "items": { + "type": "object", + "properties": { + "protocol": { + "type": "string", + "enum": [ + "any", + "tcp", + "udp" + ], + "default": "any" + }, + "port": { + "type": "integer" + }, + "range-end": { + "type": "integer" + }, + "reclassify": { + "type": "boolean", + "default": true + } + } + } + }, + "dns": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "format": "uc-fqdn" + }, + "suffix-matching": { + "type": "boolean", + "default": true + }, + "reclassify": { + "type": "boolean", + "default": true + } + } + } + } + } + } + } + } + }, + "service.facebook-wifi": { + "type": "object", + "properties": { + "vendor-id": { + "type": "string" + }, + "gateway-id": { + "type": "string" + }, + "secret": { + "type": "string" + } + } + }, + "service.airtime-fairness": { + "type": "object", + "properties": { + "voice-weight": { + "type": "number", + "default": 4 + }, + "packet-threshold": { + "type": "number", + "default": 100 + }, + "bulk-threshold": { + "type": "number", + "default": 50 + }, + "priority-threshold": { + "type": "number", + "default": 30 + }, + "weight-normal": { + "type": "number", + "default": 256 + }, + "weight-priority": { + "type": "number", + "default": 394 + }, + "weight-bulk": { + "type": "number", + "default": 128 + } + } + }, + "service": { + "type": "object", + "properties": { + "lldp": { + "$ref": "#/$defs/service.lldp" + }, + "ssh": { + "$ref": "#/$defs/service.ssh" + }, + "ntp": { + "$ref": "#/$defs/service.ntp" + }, + "mdns": { + "$ref": "#/$defs/service.mdns" + }, + "rtty": { + "$ref": "#/$defs/service.rtty" + }, + "log": { + "$ref": "#/$defs/service.log" + }, + "http": { + "$ref": "#/$defs/service.http" + }, + "igmp": { + "$ref": "#/$defs/service.igmp" + }, + "ieee8021x": { + "$ref": "#/$defs/service.ieee8021x" + }, + "radius-proxy": { + "$ref": "#/$defs/service.radius-proxy" + }, + "online-check": { + "$ref": "#/$defs/service.online-check" + }, + "open-flow": { + "$ref": "#/$defs/service.open-flow" + }, + "data-plane": { + "$ref": "#/$defs/service.data-plane" + }, + "wifi-steering": { + "$ref": "#/$defs/service.wifi-steering" + }, + "quality-of-service": { + "$ref": "#/$defs/service.quality-of-service" + }, + "facebook-wifi": { + "$ref": "#/$defs/service.facebook-wifi" + }, + "airtime-fairness": { + "$ref": "#/$defs/service.airtime-fairness" + } + } + }, + "metrics.statistics": { + "type": "object", + "properties": { + "interval": { + "type": "integer" + }, + "types": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ssids", + "lldp", + "clients" + ] + } + } + } + }, + "metrics.health": { + "type": "object", + "properties": { + "interval": { + "type": "integer", + "minimum": 60 + } + } + }, + "metrics.wifi-frames": { + "type": "object", + "properties": { + "filters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "probe", + "auth", + "assoc", + "disassoc", + "deauth", + "local-deauth", + "inactive-deauth", + "key-mismatch", + "beacon-report", + "radar-detected" + ] + } + } + } + }, + "metrics.dhcp-snooping": { + "type": "object", + "properties": { + "filters": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ack", + "discover", + "offer", + "request", + "solicit", + "reply", + "renew" + ] + } + } + } + }, + "metrics": { + "type": "object", + "properties": { + "statistics": { + "$ref": "#/$defs/metrics.statistics" + }, + "health": { + "$ref": "#/$defs/metrics.health" + }, + "wifi-frames": { + "$ref": "#/$defs/metrics.wifi-frames" + }, + "dhcp-snooping": { + "$ref": "#/$defs/metrics.dhcp-snooping" + } + } + }, + "config-raw": { + "type": "array", + "items": { + "type": "array", + "minItems": 2, + "items": { + "type": "string" + }, + "examples": [ + [ + "set", + "system.@system[0].timezone", + "GMT0" + ], + [ + "delete", + "firewall.@zone[0]" + ], + [ + "delete", + "dhcp.wan" + ], + [ + "add", + "dhcp", + "dhcp" + ], + [ + "add-list", + "system.ntp.server", + "0.pool.example.org" + ], + [ + "del-list", + "system.ntp.server", + "1.openwrt.pool.ntp.org" + ] + ] + } + } + } } -} -}, -"interface.bridge": { - "type": "object", - "properties": { - "mtu": { - "type": "integer", - "maximum": 65535, - "minimum": 256, - "examples": [ - 1500 - ] - }, - "tx-queue-len": { - "type": "integer", - "examples": [ - 5000 - ] - }, - "isolate-ports": { - "type": "boolean", - "default": false - } - } - }, - "interface.ethernet": { - "type": "object", - "properties": { - "select-ports": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "LAN1", - "LAN2", - "LAN3", - "LAN4", - "LAN*", - "WAN*", - "*" - ] - } - }, - "multicast": { - "type": "boolean", - "default": true - }, - "learning": { - "type": "boolean", - "default": true - }, - "isolate": { - "type": "boolean", - "default": false - }, - "macaddr": { - "type": "string", - "format": "uc-mac" - }, - "reverse-path-filter": { - "type": "boolean", - "default": false - }, - "vlan-tag": { - "type": "string", - "enum": [ - "tagged", - "un-tagged", - "auto" - ], - "default": "auto" - } - } - }, - "interface.ipv4.dhcp": { - "type": "object", - "properties": { - "lease-first": { - "type": "integer", - "examples": [ - 10 - ] - }, - "lease-count": { - "type": "integer", - "examples": [ - 100 - ] - }, - "lease-time": { - "type": "string", - "format": "uc-timeout", - "default": "6h" - }, - "relay-server": { - "type": "string", - "format": "ipv4", - "example": "192.168.2.1" - }, - "circuit-id-format": { - "type": "string", - "example": [ - "\\{Interface\\}:\\{VLAN-Id\\}:\\{SSID\\}:\\{Model\\}:\\{Name\\}:\\{AP-MAC\\}:\\{Location\\}", - "\\{AP-MAC\\};\\{SSID\\};\\{Crypto\\}", - "\\{Name\\} \\{ESSID\\}" - ] - }, - "remote-id-format": { - "type": "string", - "example": [ - "\\{Client-MAC-hex\\} \\{SSID\\}", - "\\{AP-MAC-hex\\} \\{SSID\\}" - ] - } - } - }, - "interface.ipv4.dhcp-lease": { - "type": "object", - "properties": { - "macaddr": { - "type": "string", - "format": "uc-mac", - "examples": [ - "00:11:22:33:44:55" - ] - }, - "static-lease-offset": { - "type": "integer", - "examples": [ - 10 - ] - }, - "lease-time": { - "type": "string", - "format": "uc-timeout", - "default": "6h" - }, - "publish-hostname": { - "type": "boolean", - "default": true - } - } - }, - "interface.ipv4": { - "type": "object", - "properties": { - "addressing": { - "type": "string", - "enum": [ - "dynamic", - "static" - ], - "examples": [ - "static" - ] - }, - "subnet": { - "type": "string", - "format": "uc-cidr4", - "examples": [ - "auto/24" - ] - }, - "gateway": { - "type": "string", - "format": "ipv4", - "examples": [ - "192.168.1.1" - ] - }, - "send-hostname": { - "type": "boolean", - "default": true, - "examples": [ - true - ] - }, - "use-dns": { - "type": "array", - "items": { - "type": "string", - "format": "ipv4", - "examples": [ - "8.8.8.8", - "4.4.4.4" - ] - } - }, - "dhcp": { - "$ref": "#/$defs/interface.ipv4.dhcp" - }, - "dhcp-leases": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ipv4.dhcp-lease" - } - } - } - }, - "interface.ipv6.dhcpv6": { - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "hybrid", - "stateless", - "stateful", - "relay" - ] - }, - "announce-dns": { - "type": "array", - "items": { - "type": "string", - "format": "ipv6" - } - }, - "filter-prefix": { - "type": "string", - "format": "uc-cidr6", - "default": "::/0" - } - } - }, - "interface.ipv6": { - "type": "object", - "properties": { - "addressing": { - "type": "string", - "enum": [ - "dynamic", - "static" - ] - }, - "subnet": { - "type": "string", - "format": "uc-cidr6", - "examples": [ - "auto/64" - ] - }, - "gateway": { - "type": "string", - "format": "ipv6", - "examples": [ - "2001:db8:123:456::1" - ] - }, - "prefix-size": { - "type": "integer", - "maximum": 64, - "minimum": 0 - }, - "dhcpv6": { - "$ref": "#/$defs/interface.ipv6.dhcpv6" - } - } - }, - "interface.broad-band.wwan": { - "type": "object", - "properties": { - "protocol": { - "type": "string", - "const": "wwan" - }, - "modem-type": { - "type": "string", - "enum": [ - "qmi", - "mbim", - "wwan" - ] - }, - "access-point-name": { - "type": "string" - }, - "authentication-type": { - "type": "string", - "enum": [ - "none", - "pap", - "chap", - "pap-chap" - ], - "default": "none" - }, - "pin-code": { - "type": "string" - }, - "user-name": { - "type": "string" - }, - "password": { - "type": "string" - }, - "packet-data-protocol": { - "type": "string", - "enum": [ - "ipv4", - "ipv6", - "dual-stack" - ], - "default": "dual-stack" - } - } - }, - "interface.broad-band.pppoe": { - "type": "object", - "properties": { - "protocol": { - "type": "string", - "const": "pppoe" - }, - "user-name": { - "type": "string" - }, - "password": { - "type": "string" - } - } - }, - "interface.broad-band": { - "oneOf": [ - { - "$ref": "#/$defs/interface.broad-band.wwan" - }, - { - "$ref": "#/$defs/interface.broad-band.pppoe" - } - ] - }, - "interface.captive": { - "type": "object", - "properties": { - "gateway-name": { - "type": "string", - "default": "uCentral - Captive Portal" - }, - "gateway-fqdn": { - "type": "string", - "format": "fqdn", - "default": "ucentral.splash" - }, - "max-clients": { - "type": "integer", - "default": 32 - }, - "upload-rate": { - "type": "integer", - "default": 0 - }, - "download-rate": { - "type": "integer", - "default": 0 - }, - "upload-quota": { - "type": "integer", - "default": 0 - }, - "download-quota": { - "type": "integer", - "default": 0 - } - } - }, - "interface.ssid.encryption": { - "type": "object", - "properties": { - "proto": { - "type": "string", - "enum": [ - "none", - "psk", - "psk2", - "psk-mixed", - "wpa", - "wpa2", - "wpa-mixed", - "sae", - "sae-mixed", - "wpa3", - "wpa3-192", - "wpa3-mixed" - ], - "examples": [ - "psk2" - ] - }, - "key": { - "type": "string", - "maxLength": 63, - "minLength": 8 - }, - "ieee80211w": { - "type": "string", - "enum": [ - "disabled", - "optional", - "required" - ], - "default": "disabled" - } - } - }, - "interface.ssid.multi-psk": { - "type": "object", - "properties": { - "mac": { - "type": "string", - "format": "uc-mac" - }, - "key": { - "type": "string", - "maxLength": 63, - "minLength": 8 - }, - "vlan-id": { - "type": "integer", - "maximum": 4096, - "examples": [ - 3, - 100, - 200, - 4094 - ] - } - } - }, - "interface.ssid.rrm": { - "type": "object", - "properties": { - "neighbor-reporting": { - "type": "boolean", - "default": false - }, - "lci": { - "type": "string" - }, - "civic-location": { - "type": "string" - }, - "ftm-responder": { - "type": "boolean", - "default": false - }, - "stationary-ap": { - "type": "boolean", - "default": false - } - } - }, - "interface.ssid.rate-limit": { - "type": "object", - "properties": { - "ingress-rate": { - "type": "integer", - "default": 0 - }, - "egress-rate": { - "type": "integer", - "default": 0 - } - } - }, - "interface.ssid.roaming": { - "type": "object", - "properties": { - "message-exchange": { - "type": "string", - "enum": [ - "air", - "ds" - ], - "default": "ds" - }, - "generate-psk": { - "type": "boolean", - "default": false - }, - "domain-identifier": { - "type": "string", - "maxLength": 4, - "minLength": 4, - "examples": [ - "abcd" - ] - }, - "pmk-r0-key-holder": { - "type": "string", - "example": "14:DD:20:47:14:E4,14DD204714E4,00112233445566778899aabbccddeeff" - }, - "pmk-r1-key-holder": { - "type": "string", - "example": "14:DD:20:47:14:E4,14DD204714E4,00112233445566778899aabbccddeeff" - } - } - }, - "interface.ssid.radius.local-user": { - "type": "object", - "properties": { - "mac": { - "type": "string", - "format": "uc-mac" - }, - "user-name": { - "type": "string", - "minLength": 1 - }, - "password": { - "type": "string", - "maxLength": 63, - "minLength": 8 - }, - "vlan-id": { - "type": "integer", - "maximum": 4096, - "examples": [ - 3, - 100, - 200, - 4094 - ] - } - } - }, - "interface.ssid.radius.local": { - "type": "object", - "properties": { - "server-identity": { - "type": "string", - "default": "uCentral" - }, - "users": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ssid.radius.local-user" - } - } - } - }, - "interface.ssid.radius.server": { - "type": "object", - "properties": { - "host": { - "type": "string", - "format": "uc-host", - "examples": [ - "192.168.1.10" - ] - }, - "port": { - "type": "integer", - "maximum": 65535, - "minimum": 1024, - "examples": [ - 1812 - ] - }, - "secret": { - "type": "string", - "examples": [ - "secret" - ] - }, - "request-attribute": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "maximum": 255, - "minimum": 1 - }, - "value": { - "anyOf": [ - { - "type": "integer", - "maximum": 4294967295, - "minimum": 0 - }, - { - "type": "string" - } - ] - } - }, - "examples": [ - { - "id": 27, - "value": 900 - }, - { - "id": 32, - "value": "My NAS ID" - }, - { - "id": 56, - "value": 1004 - }, - { - "id": 126, - "value": "Example Operator" - } - ] - }, - "examples": [ - "126:s:Operator" - ] - } - } - }, - "interface.ssid.radius": { - "type": "object", - "properties": { - "nas-identifier": { - "type": "string" - }, - "chargeable-user-id": { - "type": "boolean", - "default": false - }, - "local": { - "$ref": "#/$defs/interface.ssid.radius.local" - }, - "authentication": { - "$ref": "#/$defs/interface.ssid.radius.server" - }, - "accounting": { - "allOf": [ - { - "$ref": "#/$defs/interface.ssid.radius.server" - }, - { - "type": "object", - "properties": { - "interval": { - "type": "integer", - "maximum": 600, - "minimum": 60, - "default": 60 - } - } - } - ] - } - } - }, - "interface.ssid.certificates": { - "type": "object", - "properties": { - "use-local-certificates": { - "type": "boolean", - "default": false - }, - "ca-certificate": { - "type": "string" - }, - "certificate": { - "type": "string" - }, - "private-key": { - "type": "string" - }, - "private-key-password": { - "type": "string" - } - } - }, - "interface.ssid.pass-point": { - "type": "object", - "properties": { - "venue-name": { - "type": "array", - "items": { - "type": "string" - } - }, - "venue-group": { - "type": "integer", - "maximum": 32 - }, - "venue-type": { - "type": "integer", - "maximum": 32 - }, - "venue-url": { - "type": "array", - "items": { - "type": "string", - "format": "uri" - } - }, - "auth-type": { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "terms-and-conditions", - "online-enrollment", - "http-redirection", - "dns-redirection" - ] - }, - "uri": { - "type": "string", - "format": "uri", - "examples": [ - "https://operator.example.org/wireless-access/terms-and-conditions.html", - "http://www.example.com/redirect/me/here/" - ] - } - }, - "minLength": 2, - "maxLength": 2 - }, - "domain-name": { - "type": "array", - "items": { - "type": "string", - "format": "hostname" - } - }, - "nai-realm": { - "type": "array", - "items": { - "type": "string" - } - }, - "osen": { - "type": "boolean" - }, - "anqp-domain": { - "type": "integer", - "maximum": 65535, - "minimum": 0 - }, - "anqp-3gpp-cell-net": { - "type": "array", - "items": { - "type": "string" - } - }, - "friendly-name": { - "type": "array", - "items": { - "type": "string" - } - }, - "access-network-type": { - "type": "integer", - "maximum": 15, - "default": 0 - }, - "internet": { - "type": "boolean", - "default": true - }, - "asra": { - "type": "boolean", - "default": false - }, - "esr": { - "type": "boolean", - "default": false - }, - "uesa": { - "type": "boolean", - "default": false - }, - "hessid": { - "type": "string", - "example": "00:11:22:33:44:55" - }, - "roaming-consortium": { - "type": "array", - "items": { - "type": "string" - } - }, - "disable-dgaf": { - "type": "boolean", - "default": false - }, - "ipaddr-type-available": { - "type": "integer", - "maximum": 255 - }, - "connection-capability": { - "type": "array", - "items": { - "type": "string" - } - }, - "icons": { - "type": "array", - "items": { - "type": "object", - "properties": { - "width": { - "type": "integer", - "examples": [ - 64 - ] - }, - "height": { - "type": "integer", - "examples": [ - 64 - ] - }, - "type": { - "type": "string", - "examples": [ - "image/png" - ] - }, - "icon": { - "type": "string", - "format": "uc-base64" - }, - "language": { - "type": "string", - "pattern": "^[a-z][a-z][a-z]$", - "examples": [ - "eng", - "fre", - "ger", - "ita" - ] - } - }, - "examples": [ - { - "width": 32, - "height": 32, - "type": "image/png", - "language": "eng", - "icon": "R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7" - } - ] - } - }, - "wan-metrics": { - "type": "object", - "properties": { - "info": { - "type": "string", - "enum": [ - "up", - "down", - "testing" - ] - }, - "downlink": { - "type": "integer" - }, - "uplink": { - "type": "integer" - } - } - } - } - }, - "interface.ssid.quality-thresholds": { - "type": "object", - "properties": { - "probe-request-rssi": { - "type": "integer" - }, - "association-request-rssi": { - "type": "integer" - } - } - }, - "interface.ssid": { - "type": "object", - "properties": { - "purpose": { - "type": "string", - "enum": [ - "user-defined", - "onboarding-ap", - "onboarding-sta" - ], - "default": "user-defined" - }, - "name": { - "type": "string", - "maxLength": 32, - "minLength": 1 - }, - "wifi-bands": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "2G", - "5G", - "5G-lower", - "5G-upper", - "6G" - ] - } - }, - "bss-mode": { - "type": "string", - "enum": [ - "ap", - "sta", - "mesh", - "wds-ap", - "wds-sta", - "wds-repeater" - ], - "default": "ap" - }, - "bssid": { - "type": "string", - "format": "uc-mac" - }, - "hidden-ssid": { - "type": "boolean" - }, - "isolate-clients": { - "type": "boolean" - }, - "power-save": { - "type": "boolean" - }, - "rts-threshold": { - "type": "integer", - "maximum": 65535, - "minimum": 1 - }, - "broadcast-time": { - "type": "boolean" - }, - "unicast-conversion": { - "type": "boolean" - }, - "services": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "wifi-steering" - ] - } - }, - "maximum-clients": { - "type": "integer", - "example": 64 - }, - "proxy-arp": { - "type": "boolean", - "default": true - }, - "disassoc-low-ack": { - "decription": "Disassociate stations based on excessive transmission failures or other indications of connection loss.", - "type": "boolean", - "default": false - }, - "vendor-elements": { - "decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", - "type": "string" - }, - "encryption": { - "$ref": "#/$defs/interface.ssid.encryption" - }, - "multi-psk": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ssid.multi-psk" - } - }, - "rrm": { - "$ref": "#/$defs/interface.ssid.rrm" - }, - "rate-limit": { - "$ref": "#/$defs/interface.ssid.rate-limit" - }, - "roaming": { - "$ref": "#/$defs/interface.ssid.roaming" - }, - "radius": { - "$ref": "#/$defs/interface.ssid.radius" - }, - "certificates": { - "$ref": "#/$defs/interface.ssid.certificates" - }, - "pass-point": { - "$ref": "#/$defs/interface.ssid.pass-point" - }, - "quality-thresholds": { - "$ref": "#/$defs/interface.ssid.quality-thresholds" - }, - "hostapd-bss-raw": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "ap_table_expiration_time=3600", - "device_type=6-0050F204-1", - "ieee80211h=1", - "rssi_ignore_probe_request=-75", - "time_zone=EST5", - "uuid=12345678-9abc-def0-1234-56789abcdef0", - "venue_url=1:http://www.example.com/info-eng", - "wpa_deny_ptk0_rekey=0" - ] - } - } - } - }, - "interface.tunnel.mesh": { - "type": "object", - "properties": { - "proto": { - "type": "string", - "const": "mesh" - } - } - }, - "interface.tunnel.vxlan": { - "type": "object", - "properties": { - "proto": { - "type": "string", - "const": "vxlan" - }, - "peer-address": { - "type": "string", - "format": "ipv4", - "example": "192.168.100.1" - }, - "peer-port": { - "type": "integer", - "maximum": 65535, - "minimum": 1, - "examples": [ - 4789 - ] - } - } - }, - "interface.tunnel.l2tp": { - "type": "object", - "properties": { - "proto": { - "type": "string", - "const": "l2tp" - }, - "server": { - "type": "string", - "format": "ipv4", - "example": "192.168.100.1" - }, - "user-name": { - "type": "string" - }, - "password": { - "type": "string" - } - } - }, - "interface.tunnel.gre": { - "type": "object", - "properties": { - "proto": { - "type": "string", - "const": "gre" - }, - "peer-address": { - "type": "string", - "format": "ipv4", - "example": "192.168.100.1" - } - } - }, - "interface.tunnel": { - "oneOf": [ - { - "$ref": "#/$defs/interface.tunnel.mesh" - }, - { - "$ref": "#/$defs/interface.tunnel.vxlan" - }, - { - "$ref": "#/$defs/interface.tunnel.l2tp" - }, - { - "$ref": "#/$defs/interface.tunnel.gre" - } - ] - }, - "interface": { - "type": "object", - "properties": { - "name": { - "type": "string", - "examples": [ - "LAN" - ] - }, - "role": { - "type": "string", - "enum": [ - "upstream", - "downstream" - ] - }, - "isolate-hosts": { - "type": "boolean" - }, - "metric": { - "type": "integer", - "maximum": 4294967295, - "minimum": 0 - }, - "services": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "ssh", - "lldp" - ] - } - }, - "vlan": { - "$ref": "#/$defs/interface.vlan" - }, - "bridge": { - "$ref": "#/$defs/interface.bridge" - }, - "ethernet": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ethernet" - } - }, - "ipv4": { - "$ref": "#/$defs/interface.ipv4" - }, - "ipv6": { - "$ref": "#/$defs/interface.ipv6" - }, - "broad-band": { - "$ref": "#/$defs/interface.broad-band" - }, - "captive": { - "$ref": "#/$defs/interface.captive" - }, - "ssids": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ssid" - } - }, - "tunnel": { - "$ref": "#/$defs/interface.tunnel" - } - } - }, - "service.lldp": { - "type": "object", - "properties": { - "describe": { - "type": "string", - "default": "uCentral Access Point" - }, - "location": { - "type": "string", - "default": "uCentral Network" - } - } - }, - "service.ssh": { - "type": "object", - "properties": { - "port": { - "type": "integer", - "maximum": 65535, - "default": 22 - }, - "authorized-keys": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC0ghdSd2D2y08TFowZLMZn3x1/Djw3BkNsIeHt/Z+RaXwvfV1NQAnNdaOngMT/3uf5jZtYxhpl+dbZtRhoUPRvKflKBeFHYBqjZVzD3r4ns2Ofm2UpHlbdOpMuy9oeTSCeF0IKZZ6szpkvSirQogeP2fe9KRkzQpiza6YxxaJlWw== user@example", - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ4FDjyCsg+1Mh2C5G7ibR3z0Kw1dU57kfXebLRwS6CL bob@work", - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBP/JpJ/KHtKKImzISBDwLO0/EwytIr4pGZQXcP6GCSHchLMyfjf147KNlF9gC+3FibzqKH02EiQspVhRgfuK6y0= alice@home" - ] - } - }, - "password-authentication": { - "type": "boolean", - "default": true - } - } - }, - "service.ntp": { - "type": "object", - "properties": { - "servers": { - "type": "array", - "items": { - "type": "string", - "format": "uc-host" - }, - "examples": [ - "0.openwrt.pool.ntp.org" - ] - }, - "local-server": { - "type": "boolean", - "examples": [ - true - ] - } - } - }, - "service.mdns": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "default": false - } - } - }, - "service.rtty": { - "type": "object", - "properties": { - "host": { - "type": "string", - "format": "uc-host", - "examples": [ - "192.168.1.10" - ] - }, - "port": { - "type": "integer", - "maximum": 65535, - "default": 5912 - }, - "token": { - "type": "string", - "maxLength": 32, - "minLength": 32, - "examples": [ - "01234567890123456789012345678901" - ] - } - } - }, - "service.log": { - "type": "object", - "properties": { - "host": { - "type": "string", - "format": "uc-host", - "examples": [ - "192.168.1.10" - ] - }, - "port": { - "type": "integer", - "maximum": 65535, - "minimum": 100, - "examples": [ - 2000 - ] - }, - "proto": { - "type": "string", - "enum": [ - "tcp", - "udp" - ], - "default": "udp" - }, - "size": { - "type": "integer", - "minimum": 32, - "default": 1000 - } - } - }, - "service.http": { - "type": "object", - "properties": { - "http-port": { - "type": "integer", - "maximum": 65535, - "minimum": 1, - "default": 80 - } - } - }, - "service.igmp": { - "type": "object", - "properties": { - "enable": { - "type": "boolean", - "default": false - } - } - }, - "service.ieee8021x": { - "type": "object", - "properties": { - "ca-certificate": { - "type": "string" - }, - "use-local-certificates": { - "type": "boolean", - "default": false - }, - "server-certificate": { - "type": "string" - }, - "private-key": { - "type": "string" - }, - "users": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ssid.radius.local-user" - } - } - } - }, - "service.radius-proxy": { - "type": "object", - "properties": { - "realms": { - "type": "array", - "items": { - "type": "object", - "properties": { - "realm": { - "type": "string", - "default": "*" - }, - "auto-discover": { - "type": "boolean", - "default": false - }, - "host": { - "type": "string", - "format": "uc-host", - "examples": [ - "192.168.1.10" - ] - }, - "port": { - "type": "integer", - "maximum": 65535, - "default": 2083 - }, - "secret": { - "type": "string" - }, - "use-local-certificates": { - "type": "boolean", - "default": false - }, - "ca-certificate": { - "type": "string" - }, - "certificate": { - "type": "string" - }, - "private-key": { - "type": "string" - }, - "private-key-password": { - "type": "string" - } - } - } - } - } - }, - "service.online-check": { - "type": "object", - "properties": { - "ping-hosts": { - "type": "array", - "items": { - "type": "string", - "format": "uc-host", - "examples": [ - "192.168.1.10" - ] - } - }, - "download-hosts": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "www.example.org" - ] - } - }, - "check-interval": { - "type": "number", - "default": 60 - }, - "check-threshold": { - "type": "number", - "default": 1 - }, - "action": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "wifi", - "leds" - ] - } - } - } - }, - "service.open-flow": { - "type": "object", - "properties": { - "controller": { - "type": "string", - "format": "ip", - "example": "192.168.10.1" - }, - "datapath-description": { - "type": "string", - "example": "Building 2, Floor 6, AP 2" - }, - "mode": { - "type": "string", - "enum": [ - "pssl", - "ptcp", - "ssl", - "tcp" - ], - "default": "ssl" - }, - "ca-certificate": { - "type": "string" - }, - "ssl-certificate": { - "type": "string" - }, - "private-key": { - "type": "string" - } - } - }, - "service.data-plane": { - "type": "object", - "properties": { - "ingress-filters": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "program": { - "type": "string", - "format": "uc-base64" - } - } - } - } - } - }, - "service.wifi-steering": { - "type": "object", - "properties": { - "mode": { - "type": "string", - "enum": [ - "local", - "cloud" - ], - "examples": [ - "local" - ] - }, - "assoc-steering": { - "type": "boolean", - "default": false - }, - "required-snr": { - "type": "integer", - "default": 0 - }, - "required-probe-snr": { - "type": "integer", - "default": 0 - }, - "required-roam-snr": { - "type": "integer", - "default": 0 - }, - "load-kick-threshold": { - "type": "integer", - "default": 0 - }, - "auto-channel": { - "type": "boolean", - "default": false - } - } - }, - "service.quality-of-service": { - "type": "object", - "properties": { - "select-ports": { - "type": "array", - "items": { - "type": "string", - "default": "WAN" - } - }, - "bandwidth-up": { - "type": "integer", - "default": 0 - }, - "bandwidth-down": { - "type": "integer", - "default": 0 - }, - "classifier": { - "type": "array", - "items": { - "type": "object", - "properties": { - "dscp": { - "type": "string", - "enum": [ - "CS0", - "CS1", - "CS2", - "CS3", - "CS4", - "CS5", - "CS6", - "CS7" - ], - "default": "CS1" - }, - "ports": { - "type": "array", - "items": { - "type": "object", - "properties": { - "protocol": { - "type": "string", - "enum": [ - "any", - "tcp", - "udp" - ], - "default": "any" - }, - "port": { - "type": "integer" - }, - "range-end": { - "type": "integer" - }, - "reclassify": { - "type": "boolean", - "default": true - } - } - }, - "dns": { - "type": "array", - "items": { - "type": "string", - "format": "fqdn" - } - } - } - } - } - } - } - }, - "service.facebook-wifi": { - "type": "object", - "properties": { - "vendor-id": { - "type": "string" - }, - "gateway-id": { - "type": "string" - }, - "secret": { - "type": "string" - } - } - }, - "service.airtime-policies": { - "type": "object", - "properties": { - "dns-match": { - "type": "array", - "items": { - "type": "string", - "examples": [ - "*.voice.example.com" - ] - } - }, - "dns-weight": { - "type": "integer", - "default": 256 - } - } - }, - "service": { - "type": "object", - "properties": { - "lldp": { - "$ref": "#/$defs/service.lldp" - }, - "ssh": { - "$ref": "#/$defs/service.ssh" - }, - "ntp": { - "$ref": "#/$defs/service.ntp" - }, - "mdns": { - "$ref": "#/$defs/service.mdns" - }, - "rtty": { - "$ref": "#/$defs/service.rtty" - }, - "log": { - "$ref": "#/$defs/service.log" - }, - "http": { - "$ref": "#/$defs/service.http" - }, - "igmp": { - "$ref": "#/$defs/service.igmp" - }, - "ieee8021x": { - "$ref": "#/$defs/service.ieee8021x" - }, - "radius-proxy": { - "$ref": "#/$defs/service.radius-proxy" - }, - "online-check": { - "$ref": "#/$defs/service.online-check" - }, - "open-flow": { - "$ref": "#/$defs/service.open-flow" - }, - "data-plane": { - "$ref": "#/$defs/service.data-plane" - }, - "wifi-steering": { - "$ref": "#/$defs/service.wifi-steering" - }, - "quality-of-service": { - "$ref": "#/$defs/service.quality-of-service" - }, - "facebook-wifi": { - "$ref": "#/$defs/service.facebook-wifi" - }, - "airtime-policies": { - "$ref": "#/$defs/service.airtime-policies" - } - } - }, - "metrics.statistics": { - "type": "object", - "properties": { - "interval": { - "type": "integer" - }, - "types": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "ssids", - "lldp", - "clients" - ] - } - } - } - }, - "metrics.health": { - "type": "object", - "properties": { - "interval": { - "type": "integer", - "minimum": 60 - } - } - }, - "metrics.wifi-frames": { - "type": "object", - "properties": { - "filters": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "probe", - "auth", - "assoc", - "disassoc", - "deauth", - "local-deauth", - "inactive-deauth", - "key-mismatch", - "beacon-report", - "radar-detected" - ] - } - } - } - }, - "metrics.dhcp-snooping": { - "type": "object", - "properties": { - "filters": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "ack", - "discover", - "offer", - "request", - "solicit", - "reply", - "renew" - ] - } - } - } - }, - "metrics": { - "type": "object", - "properties": { - "statistics": { - "$ref": "#/$defs/metrics.statistics" - }, - "health": { - "$ref": "#/$defs/metrics.health" - }, - "wifi-frames": { - "$ref": "#/$defs/metrics.wifi-frames" - }, - "dhcp-snooping": { - "$ref": "#/$defs/metrics.dhcp-snooping" - } - } - }, - "config-raw": { - "type": "array", - "items": { - "type": "array", - "minItems": 2, - "items": { - "type": "string" - }, - "examples": [ - [ - "set", - "system.@system[0].timezone", - "GMT0" - ], - [ - "delete", - "firewall.@zone[0]" - ], - [ - "delete", - "dhcp.wan" - ], - [ - "add", - "dhcp", - "dhcp" - ], - [ - "add-list", - "system.ntp.server", - "0.pool.example.org" - ], - [ - "del-list", - "system.ntp.server", - "1.openwrt.pool.ntp.org" - ] - ] - } -} -} -} - )"_json; +)"_json; - class ConfigurationValidator *ConfigurationValidator::instance_ = nullptr; + class custom_error_handler : public nlohmann::json_schema::basic_error_handler + { + void error(const nlohmann::json_pointer> &pointer, const json &instance, + const std::string &message) override + { + nlohmann::json_schema::basic_error_handler::error(pointer, instance, message); + std::cout << "ERROR: '" << pointer << "' - '" << instance << "': " << message << "\n"; + } + }; void ConfigurationValidator::Init() { if(Initialized_) return; + std::string GitSchema; + if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) { + RootSchema_ = DefaultUCentralSchema; + Logger().information("Using uCentral validation from built-in default."); + Initialized_ = Working_ = true; + return; + } + try { - if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { - auto schema = json::parse(GitSchema); - Validator_->set_root_schema(schema); - Logger_.information("Using uCentral validation schema from GIT."); + auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile); + if(Utils::wgets(GitURI, GitSchema)) { + RootSchema_ = json::parse(GitSchema); + Logger().information("Using uCentral validation schema from GIT."); } else { std::string FileName{ MicroService::instance().DataDir() + "/ucentral.schema.json" }; std::ifstream input(FileName); std::stringstream schema_file; schema_file << input.rdbuf(); input.close(); - auto schema = json::parse(schema_file.str()); - Validator_->set_root_schema(schema); - Logger_.information("Using uCentral validation schema from local file."); + RootSchema_ = json::parse(schema_file.str()); + Logger().information("Using uCentral validation schema from local file."); } } catch (const Poco::Exception &E) { - Validator_->set_root_schema(DefaultUCentralSchema); - Logger_.information("Using uCentral validation from built-in default."); + RootSchema_ = DefaultUCentralSchema; + Logger().information("Using uCentral validation from built-in default."); } Initialized_ = Working_ = true; } @@ -2392,6 +2700,17 @@ namespace OpenWifi { return IsCIDRv4(value) || IsCIDRv6(value); } + static inline bool IsPortRangeIsValid(const std::string &r) { + const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM); + + for(const auto &port:ports) { + uint32_t port_num = std::stoul(port); + if(port_num==0 || port_num>65535) + return false; + } + return true; + } + void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) { static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; @@ -2414,7 +2733,7 @@ namespace OpenWifi { } else if(format == "uc-mac") { if(std::regex_match(value,mac_regex)) return; - throw std::invalid_argument(value + " is not a valid MAC: should be something like 2e60:3500::/64."); + throw std::invalid_argument(value + " is not a valid MAC: should be something like 11:22:33:44:55:66"); } else if(format == "uc-timeout") { if(std::regex_match(value,uc_timeout_regex)) return; @@ -2442,16 +2761,20 @@ namespace OpenWifi { } catch (...) { } throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); + } else if(format == "uc-portrange") { + try { + if(IsPortRangeIsValid(value)) + return; + throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); + } catch (...) { + } + throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); } else if(format == "ip") { if (IsIP(value)) return; throw std::invalid_argument(value + " is not a valid IP address."); } else { - try { - nlohmann::json_schema::default_string_format_check(format,value); - } catch (const std::logic_error &E) { - std::string Error{"JSON Schema validation: "}; - } + nlohmann::json_schema::default_string_format_check(format,value); } } @@ -2459,19 +2782,32 @@ namespace OpenWifi { if(Working_) { try { auto Doc = json::parse(C); - Validator_->validate(Doc); + custom_error_handler CE; + json_validator Validator(nullptr, my_format_checker); + Validator.set_root_schema(RootSchema_); + Validator.validate(Doc,CE); return true; + } catch (const std::invalid_argument &E) { + std::cout << "1 Validation failed, here is why: " << E.what() << "\n"; + Error = E.what(); + return false; + } catch (const std::logic_error &E) { + std::cout << "2 Validation failed, here is why: " << E.what() << "\n"; + Error = E.what(); + return false; } catch(const std::exception &E) { Error = E.what(); - std::cout << "Validation failed, here is why: " << E.what() << "\n"; + std::cout << "3 Validation failed, here is why: " << E.what() << "\n"; return false; + } catch(...) { + std::cout << "4 Some kind of bullshit exception..." << std::endl; } } return true; } - void ConfigurationValidator::reinitialize(Poco::Util::Application &self) { - Logger_.information("Reinitializing."); + void ConfigurationValidator::reinitialize([[maybe_unused]] Poco::Util::Application &self) { + Logger().information("Reinitializing."); Working_ = Initialized_ = false; Init(); } diff --git a/microservice_sample/src/framework/ConfigurationValidator.h b/microservice_sample/src/framework/ConfigurationValidator.h index 522697c..6fe401e 100644 --- a/microservice_sample/src/framework/ConfigurationValidator.h +++ b/microservice_sample/src/framework/ConfigurationValidator.h @@ -14,9 +14,8 @@ namespace OpenWifi { class ConfigurationValidator : public SubSystemServer { public: - static ConfigurationValidator *instance() { - if(instance_== nullptr) - instance_ = new ConfigurationValidator; + static auto instance() { + static auto instance_ = new ConfigurationValidator; return instance_; } @@ -27,18 +26,17 @@ namespace OpenWifi { void reinitialize(Poco::Util::Application &self) override; private: - static ConfigurationValidator * instance_; bool Initialized_=false; bool Working_=false; void Init(); - std::unique_ptr Validator_=std::make_unique(nullptr, my_format_checker); + nlohmann::json RootSchema_; ConfigurationValidator(): SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") { } }; - inline ConfigurationValidator * ConfigurationValidator() { return ConfigurationValidator::instance(); } + inline auto ConfigurationValidator() { return ConfigurationValidator::instance(); } inline bool ValidateUCentralConfiguration(const std::string &C, std::string &Error) { return ConfigurationValidator::instance()->Validate(C, Error); } } diff --git a/microservice_sample/src/framework/KafkaTopics.h b/microservice_sample/src/framework/KafkaTopics.h index 393b355..0fee341 100644 --- a/microservice_sample/src/framework/KafkaTopics.h +++ b/microservice_sample/src/framework/KafkaTopics.h @@ -17,6 +17,8 @@ namespace OpenWifi::KafkaTopics { static const std::string COMMAND{"command"}; static const std::string SERVICE_EVENTS{"service_events"}; static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"}; + static const std::string DEVICE_TELEMETRY{"device_telemetry"}; + static const std::string PROVISIONING_CHANGE{"provisioning_change"}; namespace ServiceEvents { static const std::string EVENT_JOIN{"join"}; diff --git a/microservice_sample/src/framework/MicroService.h b/microservice_sample/src/framework/MicroService.h index b5f337b..a62b46c 100644 --- a/microservice_sample/src/framework/MicroService.h +++ b/microservice_sample/src/framework/MicroService.h @@ -8,6 +8,7 @@ #pragma once + #include #include #include @@ -20,6 +21,16 @@ #include #include #include +#include + +namespace OpenWifi { + inline uint64_t Now() { return std::time(nullptr); }; +} + +namespace OpenWifi::Utils { + std::vector base64decode(const std::string& input); + std::string base64encode(const unsigned char *input, uint32_t size); +} using namespace std::chrono_literals; @@ -61,16 +72,35 @@ using namespace std::chrono_literals; #include "Poco/JSON/Object.h" #include "Poco/JSON/Parser.h" #include "Poco/StringTokenizer.h" - +#include "Poco/AsyncChannel.h" +#include "Poco/ConsoleChannel.h" +#include "Poco/AutoPtr.h" +#include "Poco/FormattingChannel.h" +#include "Poco/PatternFormatter.h" +#include "Poco/FileChannel.h" +#include "Poco/SimpleFileChannel.h" +#include "Poco/Util/PropertyFileConfiguration.h" +#include "Poco/SplitterChannel.h" +#include "Poco/JWT/Signer.h" +#include "Poco/DeflatingStream.h" +#include "Poco/Net/SocketReactor.h" +#include "Poco/Net/WebSocket.h" +#include "Poco/Environment.h" +#include "Poco/NObserver.h" +#include "Poco/Net/SocketNotification.h" +#include "Poco/Base64Decoder.h" #include "cppkafka/cppkafka.h" +#include "framework/OpenWifiTypes.h" #include "framework/KafkaTopics.h" -#include "framework/RESTAPI_protocol.h" -#include "framework/RESTAPI_errors.h" -#include "framework/uCentral_Protocol.h" +#include "framework/ow_constants.h" #include "RESTObjects/RESTAPI_SecurityObjects.h" #include "nlohmann/json.hpp" +#include "ow_version.h" +#include "fmt/core.h" +#define _OWDEBUG_ std::cout<< __FILE__ <<":" << __LINE__ << std::endl; +// #define _OWDEBUG_ Logger().debug(Poco::format("%s: %lu",__FILE__,__LINE__)); namespace OpenWifi { enum UNAUTHORIZED_REASON { @@ -84,7 +114,11 @@ namespace OpenWifi { ACCESS_DENIED, INVALID_TOKEN, EXPIRED_TOKEN, - RATE_LIMIT_EXCEEDED + RATE_LIMIT_EXCEEDED, + BAD_MFA_TRANSACTION, + MFA_FAILURE, + SECURITY_SERVICE_UNREACHABLE, + CANNOT_REFRESH_TOKEN }; class AppServiceRegistry { @@ -92,7 +126,7 @@ namespace OpenWifi { inline AppServiceRegistry(); static AppServiceRegistry & instance() { - static AppServiceRegistry *instance_= new AppServiceRegistry; + static auto instance_= new AppServiceRegistry; return *instance_; } @@ -150,6 +184,9 @@ namespace OpenWifi { std::string FileName; nlohmann::json Registry_; }; + + inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); } + } namespace OpenWifi::RESTAPI_utils { @@ -166,10 +203,51 @@ namespace OpenWifi::RESTAPI_utils { Obj.set(Field,V); } - inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::string & S) { + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, double V) { + Obj.set(Field,V); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, float V) { + Obj.set(Field,V); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::string & S) { Obj.set(Field,S); } + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const char * S) { + Obj.set(Field,S); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int16_t Value) { + Obj.set(Field, Value); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int32_t Value) { + Obj.set(Field, Value); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int64_t Value) { + Obj.set(Field, Value); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint16_t Value) { + Obj.set(Field, Value); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint32_t Value) { + Obj.set(Field, Value); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint64_t Value) { + Obj.set(Field,Value); + } + + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) { + auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size()); + Obj.set(Field,Result); + } + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) { Poco::JSON::Array Array; for(const auto &i:S) { @@ -181,14 +259,6 @@ namespace OpenWifi::RESTAPI_utils { Obj.set(Field,Array); } - inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const char * S) { - Obj.set(Field,S); - } - - inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint64_t V) { - Obj.set(Field,V); - } - inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringVec &V) { Poco::JSON::Array A; for(const auto &i:V) @@ -214,6 +284,24 @@ namespace OpenWifi::RESTAPI_utils { Obj.set(Field,A); } + inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::Counted3DMapSII &M) { + Poco::JSON::Array A; + for(const auto &[OrgName,MonthlyNumberMap]:M) { + Poco::JSON::Object OrgObject; + OrgObject.set("tag",OrgName); + Poco::JSON::Array MonthlyArray; + for(const auto &[Month,Counter]:MonthlyNumberMap) { + Poco::JSON::Object Inner; + Inner.set("value", Month); + Inner.set("counter", Counter); + MonthlyArray.add(Inner); + } + OrgObject.set("index",MonthlyArray); + A.add(OrgObject); + } + Obj.set(Field, A); + } + template void field_to_json(Poco::JSON::Object &Obj, const char *Field, const T &V, @@ -221,31 +309,93 @@ namespace OpenWifi::RESTAPI_utils { Obj.set(Field, F(V)); } - template bool field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, T & V, + template void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::vector &Value) { + Poco::JSON::Array Arr; + for(const auto &i:Value) { + Poco::JSON::Object AO; + i.to_json(AO); + Arr.add(AO); + } + Obj.set(Field, Arr); + } + + template void field_to_json(Poco::JSON::Object &Obj, const char *Field, const T &Value) { + Poco::JSON::Object Answer; + Value.to_json(Answer); + Obj.set(Field, Answer); + } + + /////////////////////////// + /////////////////////////// + /////////////////////////// + /////////////////////////// + + template bool field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, T & V, std::function F) { - if(Obj->has(Field)) + if(Obj->has(Field) && !Obj->isNull(Field)) V = F(Obj->get(Field).toString()); return true; } - inline void field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, std::string &S) { - if(Obj->has(Field)) + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, std::string &S) { + if(Obj->has(Field) && !Obj->isNull(Field)) S = Obj->get(Field).toString(); } - inline void field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, uint64_t &V) { - if(Obj->has(Field)) - V = Obj->get(Field); + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (double)Obj->get(Field); } - inline void field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, bool &V) { - if(Obj->has(Field)) - V = (Obj->get(Field).toString() == "true"); + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (float)Obj->get(Field); } + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (Obj->get(Field).toString() == "true"); + } - inline void field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, Types::StringPairVec &Vec) { - if(Obj->isArray(Field)) { + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int16_t &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (int16_t)Obj->get(Field); + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int32_t &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (int32_t) Obj->get(Field); + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int64_t &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (int64_t)Obj->get(Field); + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint16_t &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (uint16_t)Obj->get(Field); + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint32_t &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (uint32_t)Obj->get(Field); + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) + Value = (uint64_t)Obj->get(Field); + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) { + if(Obj->has(Field) && !Obj->isNull(Field)) { + auto Result = Utils::base64decode(Obj->get(Field).toString()); + Value.assignRaw((const unsigned char *)&Result[0],Result.size()); + } + } + + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) { + if(Obj->isArray(Field) && !Obj->isNull(Field)) { auto O = Obj->getArray(Field); for(const auto &i:*O) { std::string S1,S2; @@ -260,48 +410,28 @@ namespace OpenWifi::RESTAPI_utils { } } - inline void field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, Types::StringVec &V) { - if(Obj->isArray(Field)) { - V.clear(); + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringVec &Value) { + if(Obj->isArray(Field) && !Obj->isNull(Field)) { + Value.clear(); Poco::JSON::Array::Ptr A = Obj->getArray(Field); for(const auto &i:*A) { - V.push_back(i.toString()); + Value.push_back(i.toString()); } } } - inline void field_from_json(Poco::JSON::Object::Ptr Obj, const char *Field, Types::TagList &V) { - if(Obj->isArray(Field)) { - V.clear(); + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::TagList &Value) { + if(Obj->isArray(Field) && !Obj->isNull(Field)) { + Value.clear(); Poco::JSON::Array::Ptr A = Obj->getArray(Field); for(const auto &i:*A) { - V.push_back(i); + Value.push_back(i); } } } - template void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::vector &Value) { - Poco::JSON::Array Arr; - for(const auto &i:Value) { - Poco::JSON::Object AO; - i.to_json(AO); - Arr.add(AO); - } - Obj.set(Field, Arr); - } - - inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int Value) { - Obj.set(Field, Value); - } - - template void field_to_json(Poco::JSON::Object &Obj, const char *Field, const T &Value) { - Poco::JSON::Object Answer; - Value.to_json(Answer); - Obj.set(Field, Answer); - } - template void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, std::vector &Value) { - if(Obj->isArray(Field)) { + if(Obj->isArray(Field) && !Obj->isNull(Field)) { Poco::JSON::Array::Ptr Arr = Obj->getArray(Field); for(auto &i:*Arr) { auto InnerObj = i.extract(); @@ -312,14 +442,8 @@ namespace OpenWifi::RESTAPI_utils { } } - inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int &Value) { - if(Obj->isObject(Field)) { - Value = Obj->get(Field); - } - } - template void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, T &Value) { - if(Obj->isObject(Field)) { + if(Obj->isObject(Field) && !Obj->isNull(Field)) { Poco::JSON::Object::Ptr A = Obj->getObject(Field); Value.from_json(A); } @@ -476,7 +600,7 @@ namespace OpenWifi::RESTAPI_utils { try { Poco::JSON::Parser P; auto Object = P.parse(ObjectString).template extract(); - for (auto const i : *Object) { + for (auto const &i : *Object) { auto InnerObject = i.template extract(); T Obj; Obj.from_json(InnerObject); @@ -536,6 +660,27 @@ namespace OpenWifi::RESTAPI_utils { namespace OpenWifi::Utils { + inline void SetThreadName(const char *name) { +#ifdef __linux__ + Poco::Thread::current()->setName(name); + pthread_setname_np(pthread_self(), name); +#endif +#ifdef __APPLE__ + Poco::Thread::current()->setName(name); + pthread_setname_np(name); +#endif + } + + inline void SetThreadName(Poco::Thread &thr, const char *name) { +#ifdef __linux__ + thr.setName(name); + pthread_setname_np(thr.tid(), name); +#endif +#ifdef __APPLE__ + thr.setName(name); +#endif + } + enum MediaTypeEncodings { PLAIN, BINARY, @@ -551,6 +696,26 @@ namespace OpenWifi::Utils { std::all_of(Serial.begin(),Serial.end(),[](auto i){return std::isxdigit(i);})); } + [[nodiscard]] inline bool ValidUUID(const std::string &UUID) { + if(UUID.size()>36) + return false; + uint dashes=0; + return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0); + } + + template std::string ComputeHash(Args&&... args) { + Poco::SHA2Engine E; + auto as_string = [](auto p) { + if constexpr(std::is_arithmetic_v) { + return std::to_string(p); + } else { + return p; + } + }; + (E.update(as_string(args)),...); + return Poco::SHA2Engine::digestToHex(E.digest()); + } + [[nodiscard]] inline std::vector Split(const std::string &List, char Delimiter=',' ) { std::vector ReturnList; @@ -609,6 +774,23 @@ namespace OpenWifi::Utils { return buf; } + inline uint64_t MACToInt(const std::string &MAC) { + uint64_t Result = 0 ; + for(const auto &c:MAC) { + if(c==':') + continue; + Result <<= 4; + if(c>='0' && c<='9') { + Result += (c - '0'); + } else if (c>='a' && c<='f') { + Result += (c-'a'+10); + } else if (c>='A' && c<='F') { + Result += (c-'A'+10); + } + } + return Result; + } + [[nodiscard]] inline std::string ToHex(const std::vector & B) { std::string R; R.reserve(B.size()*2); @@ -629,15 +811,12 @@ namespace OpenWifi::Utils { using byte = std::uint8_t; - [[nodiscard]] inline std::string base64encode(const byte *input, unsigned long size) { + [[nodiscard]] inline std::string base64encode(const byte *input, uint32_t size) { std::string encoded; encoded.reserve(((size / 3) + (size % 3 > 0)) * 4); - std::uint32_t temp; - - std::size_t i; - - int ee = (int)(size/3); + std::uint32_t temp,i,ee; + ee = (size/3); for (i = 0; i < 3*ee; ++i) { temp = input[i++] << 16; @@ -729,7 +908,7 @@ namespace OpenWifi::Utils { inline bool ParseTime(const std::string &Time, int & Hours, int & Minutes, int & Seconds) { Poco::StringTokenizer TimeTokens(Time,":",Poco::StringTokenizer::TOK_TRIM); - Hours = Minutes = Hours = 0 ; + Hours = Minutes = Seconds = 0 ; if(TimeTokens.count()==1) { Hours = std::atoi(TimeTokens[0].c_str()); } else if(TimeTokens.count()==2) { @@ -787,20 +966,7 @@ namespace OpenWifi::Utils { } [[nodiscard]] inline uint64_t SerialNumberToInt(const std::string & S) { - uint64_t R=0; - - for(const auto &i:S) - if(i>='0' && i<='9') { - R <<= 4; - R += (i-'0'); - } else if(i>='a' && i<='f') { - R <<= 4; - R += (i-'a') + 10 ; - } else if(i>='A' && i<='F') { - R <<= 4; - R += (i-'A') + 10 ; - } - return R; + return std::stoull(S,nullptr,16); } [[nodiscard]] inline std::string IntToSerialNumber(uint64_t S) { @@ -881,13 +1047,11 @@ namespace OpenWifi::Utils { [[nodiscard]] inline bool ValidEMailAddress(const std::string &email) { // define a regular expression static const std::regex pattern - ("(\\w+)(\\.|_)?(\\w*)@(\\w+)(\\.(\\w+))+"); - + ("[_a-z0-9-]+(\\.[_a-z0-9-]+)*(\\+[a-z0-9-]+)?@[a-z0-9-]+(\\.[a-z0-9-]+)*"); // try to match the string with the regular expression return std::regex_match(email, pattern); } - [[nodiscard]] inline std::string LoadFile( const Poco::File & F) { std::string Result; try { @@ -1008,6 +1172,39 @@ namespace OpenWifi::Utils { return stream.str(); } + inline bool ExtractBase64CompressedData(const std::string &CompressedData, + std::string &UnCompressedData, uint64_t compress_sz ) { + std::istringstream ifs(CompressedData); + Poco::Base64Decoder b64in(ifs); + std::ostringstream ofs; + Poco::StreamCopier::copyStream(b64in, ofs); + + int factor = 20; + unsigned long MaxSize = compress_sz ? (unsigned long) (compress_sz + 5000) : (unsigned long) (ofs.str().size() * factor); + while(true) { + std::vector UncompressedBuffer(MaxSize); + unsigned long FinalSize = MaxSize; + auto status = uncompress((uint8_t *)&UncompressedBuffer[0], &FinalSize, + (uint8_t *)ofs.str().c_str(), ofs.str().size()); + if(status==Z_OK) { + UncompressedBuffer[FinalSize] = 0; + UnCompressedData = (char *)&UncompressedBuffer[0]; + return true; + } + if(status==Z_BUF_ERROR) { + if(factor<300) { + factor+=10; + MaxSize = ofs.str().size() * factor; + continue; + } else { + return false; + } + } + return false; + } + return false; + } + } namespace OpenWifi { @@ -1020,25 +1217,145 @@ namespace OpenWifi { static const std::string uSERVICE_OWLS{ "owls"}; static const std::string uSERVICE_SUBCRIBER{ "owsub"}; static const std::string uSERVICE_INSTALLER{ "owinst"}; + static const std::string uSERVICE_ANALYTICS{ "owanalytics"}; + static const std::string uSERVICE_OWRRM{ "owrrm"}; + class ConfigurationEntry { + public: + template explicit ConfigurationEntry(T def) : + Default_(def), + Current_(def){ + } - class MyErrorHandler : public Poco::ErrorHandler { + template explicit ConfigurationEntry(T def, T cur, const std::string &Hint="") : + Default_(def), + Current_(cur), + Hint_(Hint){ + } + + inline ConfigurationEntry()=default; + inline ~ConfigurationEntry()=default; + + template explicit operator T () const { return std::get(Current_); } + inline ConfigurationEntry & operator=(const char *v) { Current_ = std::string(v); return *this;} + template ConfigurationEntry & operator=(T v) { Current_ = (T) v; return *this;} + + void reset() { + Current_ = Default_; + } + + private: + std::variant Default_, Current_; + std::string Hint_; + }; + inline std::string to_string(const ConfigurationEntry &v) { return (std::string) v; } + + typedef std::map ConfigurationMap_t; + + template class FIFO { + public: + explicit FIFO(uint32_t Size) : + Size_(Size) { + Buffer_ = new T [Size_]; + } + + ~FIFO() { + delete [] Buffer_; + } + + mutable Poco::BasicEvent Writable_; + mutable Poco::BasicEvent Readable_; + + inline bool Read(T &t) { + { + std::lock_guard M(Mutex_); + if (Write_ == Read_) { + return false; + } + + t = Buffer_[Read_++]; + if (Read_ == Size_) { + Read_ = 0; + } + Used_--; + } + bool flag = true; + Writable_.notify(this, flag); + return true; + } + + inline bool Write(const T &t) { + { + std::lock_guard M(Mutex_); + + Buffer_[Write_++] = t; + if (Write_ == Size_) { + Write_ = 0; + } + Used_++; + MaxEverUsed_ = std::max(Used_,MaxEverUsed_); + } + bool flag = true; + Readable_.notify(this, flag); + return false; + } + + inline bool isFull() { + std::lock_guard M(Mutex_); + return Used_==Buffer_->capacity(); + } + + inline auto MaxEverUser() const { return MaxEverUsed_; } + + private: + std::recursive_mutex Mutex_; + uint32_t Size_=0; + uint32_t Read_=0; + uint32_t Write_=0; + uint32_t Used_=0; + uint32_t MaxEverUsed_=0; + T * Buffer_ = nullptr; + }; + + template class RecordCache { + public: + explicit RecordCache( KeyType Record::* Q) : + MemberOffset(Q){ + }; + inline auto update(const Record &R) { + return Cache_.update(R.*MemberOffset, R); + } + inline auto get(const KeyType &K) { + return Cache_.get(K); + } + inline auto remove(const KeyType &K) { + return Cache_.remove(K); + } + inline auto remove(const Record &R) { + return Cache_.remove(R.*MemberOffset); + } + private: + KeyType Record::* MemberOffset; + Poco::ExpireLRUCache Cache_{Size,Expiry}; + }; + + class MyErrorHandler : public Poco::ErrorHandler { public: explicit MyErrorHandler(Poco::Util::Application &App) : App_(App) {} inline void exception(const Poco::Exception & E) { Poco::Thread * CurrentThread = Poco::Thread::current(); App_.logger().log(E); - App_.logger().error(Poco::format("Exception occurred in %s",CurrentThread->getName())); + App_.logger().error(fmt::format("Exception occurred in {}",CurrentThread->getName())); } inline void exception(const std::exception & E) { Poco::Thread * CurrentThread = Poco::Thread::current(); - App_.logger().warning(Poco::format("std::exception on %s",CurrentThread->getName())); + App_.logger().warning(fmt::format("std::exception in {}: {}",CurrentThread->getName(),E.what())); } inline void exception() { Poco::Thread * CurrentThread = Poco::Thread::current(); - App_.logger().warning(Poco::format("exception on %s",CurrentThread->getName())); + App_.logger().warning(fmt::format("exception in {}",CurrentThread->getName())); } private: Poco::Util::Application &App_; @@ -1050,7 +1367,7 @@ namespace OpenWifi { inline void Start(); inline void Stop(); private: - std::atomic_bool Running_ = false; + mutable std::atomic_bool Running_ = false; Poco::Thread Thread_; }; @@ -1058,9 +1375,10 @@ namespace OpenWifi { public: explicit MyPrivateKeyPassphraseHandler(const std::string &Password, Poco::Logger & Logger): PrivateKeyPassphraseHandler(true), - Logger_(Logger), - Password_(Password) {} - void onPrivateKeyRequested(const void * pSender,std::string & privateKey) { + Password_(Password), + Logger_(Logger) + {} + void onPrivateKeyRequested([[maybe_unused]] const void * pSender,std::string & privateKey) { Logger_.information("Returning key passphrase."); privateKey = Password_; }; @@ -1078,21 +1396,30 @@ namespace OpenWifi { Poco::Net::Context::VerificationMode M = Poco::Net::Context::VerificationMode::VERIFY_RELAXED, int backlog = 64) - : address_(std::move(Address)), port_(port), key_file_(std::move(Key_file)), - cert_file_(std::move(Cert_file)), root_ca_(std::move(RootCa)), - issuer_cert_file_(std::move(Issuer)), client_cas_(std::move(ClientCas)), - cas_(std::move(Cas)), key_file_password_(std::move(Key_file_password)), - name_(std::move(Name)), level_(M), backlog_(backlog){}; + : address_(std::move(Address)), + port_(port), + cert_file_(std::move(Cert_file)), + key_file_(std::move(Key_file)), + root_ca_(std::move(RootCa)), + key_file_password_(std::move(Key_file_password)), + issuer_cert_file_(std::move(Issuer)), + client_cas_(std::move(ClientCas)), + cas_(std::move(Cas)), + name_(std::move(Name)), + backlog_(backlog), + level_(M) + {}; [[nodiscard]] inline const std::string &Address() const { return address_; }; [[nodiscard]] inline uint32_t Port() const { return port_; }; - [[nodiscard]] inline const std::string &KeyFile() const { return key_file_; }; - [[nodiscard]] inline const std::string &CertFile() const { return cert_file_; }; - [[nodiscard]] inline const std::string &RootCA() const { return root_ca_; }; - [[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; }; - [[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; }; - [[nodiscard]] inline const std::string &Name() const { return name_; }; + [[nodiscard]] inline auto KeyFile() const { return key_file_; }; + [[nodiscard]] inline auto CertFile() const { return cert_file_; }; + [[nodiscard]] inline auto RootCA() const { return root_ca_; }; + [[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; }; + [[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; }; + [[nodiscard]] inline auto Name() const { return name_; }; [[nodiscard]] inline int Backlog() const { return backlog_; } + [[nodiscard]] inline auto Cas() const { return cas_; } [[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const { Poco::Net::Context::Params P; @@ -1137,7 +1464,7 @@ namespace OpenWifi { SSL_CTX *SSLCtx = Context->sslContext(); if (!SSL_CTX_check_private_key(SSLCtx)) { - L.fatal(Poco::format("Wrong Certificate(%s) for Key(%s)", cert_file_, key_file_)); + L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_)); } SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr); @@ -1150,7 +1477,7 @@ namespace OpenWifi { Context->enableSessionCache(); Context->setSessionCacheSize(0); - Context->setSessionTimeout(10); + Context->setSessionTimeout(60); Context->enableExtendedCertificateVerification(true); Context->disableStatelessSessionResumption(); } @@ -1170,60 +1497,76 @@ namespace OpenWifi { } } + [[nodiscard]] inline Poco::Net::ServerSocket CreateSocket([[maybe_unused]] Poco::Logger &L) const { + Poco::Net::Context::Params P; + + if (address_ == "*") { + Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard( + Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6 + : Poco::Net::AddressFamily::IPv4)); + Poco::Net::SocketAddress SockAddr(Addr, port_); + return Poco::Net::ServerSocket(SockAddr, backlog_); + } else { + Poco::Net::IPAddress Addr(address_); + Poco::Net::SocketAddress SockAddr(Addr, port_); + return Poco::Net::ServerSocket(SockAddr, backlog_); + } + } + inline void LogCertInfo(Poco::Logger &L, const Poco::Crypto::X509Certificate &C) const { L.information("============================================================================================="); - L.information(Poco::format("> Issuer: %s", C.issuerName())); + L.information(fmt::format("> Issuer: {}", C.issuerName())); L.information("---------------------------------------------------------------------------------------------"); - L.information(Poco::format("> Common Name: %s", + L.information(fmt::format("> Common Name: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_COMMON_NAME))); - L.information(Poco::format("> Country: %s", + L.information(fmt::format("> Country: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_COUNTRY))); - L.information(Poco::format("> Locality: %s", + L.information(fmt::format("> Locality: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME))); - L.information(Poco::format("> State/Prov: %s", + L.information(fmt::format("> State/Prov: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE))); - L.information(Poco::format("> Org name: %s", + L.information(fmt::format("> Org name: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME))); L.information( - Poco::format("> Org unit: %s", + fmt::format("> Org unit: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME))); L.information( - Poco::format("> Email: %s", + fmt::format("> Email: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS))); - L.information(Poco::format("> Serial#: %s", + L.information(fmt::format("> Serial#: {}", C.issuerName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER))); L.information("---------------------------------------------------------------------------------------------"); - L.information(Poco::format("> Subject: %s", C.subjectName())); + L.information(fmt::format("> Subject: {}", C.subjectName())); L.information("---------------------------------------------------------------------------------------------"); - L.information(Poco::format("> Common Name: %s", + L.information(fmt::format("> Common Name: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_COMMON_NAME))); - L.information(Poco::format("> Country: %s", + L.information(fmt::format("> Country: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_COUNTRY))); - L.information(Poco::format("> Locality: %s", + L.information(fmt::format("> Locality: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME))); L.information( - Poco::format("> State/Prov: %s", + fmt::format("> State/Prov: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE))); L.information( - Poco::format("> Org name: %s", + fmt::format("> Org name: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME))); L.information( - Poco::format("> Org unit: %s", + fmt::format("> Org unit: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME))); L.information( - Poco::format("> Email: %s", + fmt::format("> Email: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS))); - L.information(Poco::format("> Serial#: %s", + L.information(fmt::format("> Serial#: {}", C.subjectName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER))); L.information("---------------------------------------------------------------------------------------------"); - L.information(Poco::format("> Signature Algo: %s", C.signatureAlgorithm())); + L.information(fmt::format("> Signature Algo: {}", C.signatureAlgorithm())); auto From = Poco::DateTimeFormatter::format(C.validFrom(), Poco::DateTimeFormat::HTTP_FORMAT); - L.information(Poco::format("> Valid from: %s", From)); + L.information(fmt::format("> Valid from: {}", From)); auto Expires = Poco::DateTimeFormatter::format(C.expiresOn(), Poco::DateTimeFormat::HTTP_FORMAT); - L.information(Poco::format("> Expires on: %s", Expires)); - L.information(Poco::format("> Version: %d", (int)C.version())); - L.information(Poco::format("> Serial #: %s", C.serialNumber())); + L.information(fmt::format("> Expires on: {}", Expires)); + L.information(fmt::format("> Version: {}", (int)C.version())); + L.information(fmt::format("> Serial #: {}", C.serialNumber())); L.information("============================================================================================="); } @@ -1232,7 +1575,7 @@ namespace OpenWifi { Poco::Crypto::X509Certificate C(cert_file_); L.information("============================================================================================="); L.information("============================================================================================="); - L.information(Poco::format("Certificate Filename: %s", cert_file_)); + L.information(fmt::format("Certificate Filename: {}", cert_file_)); LogCertInfo(L, C); L.information("============================================================================================="); @@ -1240,7 +1583,7 @@ namespace OpenWifi { Poco::Crypto::X509Certificate C1(issuer_cert_file_); L.information("============================================================================================="); L.information("============================================================================================="); - L.information(Poco::format("Issues Certificate Filename: %s", issuer_cert_file_)); + L.information(fmt::format("Issues Certificate Filename: {}", issuer_cert_file_)); LogCertInfo(L, C1); L.information("============================================================================================="); } @@ -1251,11 +1594,11 @@ namespace OpenWifi { L.information("============================================================================================="); L.information("============================================================================================="); - L.information(Poco::format("Client CAs Filename: %s", client_cas_)); + L.information(fmt::format("Client CAs Filename: {}", client_cas_)); L.information("============================================================================================="); auto i = 1; for (const auto &C3 : Certs) { - L.information(Poco::format(" Index: %d", i)); + L.information(fmt::format(" Index: {}", i)); L.information("============================================================================================="); LogCertInfo(L, C3); i++; @@ -1275,11 +1618,11 @@ namespace OpenWifi { L.information("============================================================================================="); L.information("============================================================================================="); - L.information(Poco::format("CA Filename: %s", root_ca_)); + L.information(fmt::format("CA Filename: {}", root_ca_)); L.information("============================================================================================="); auto i = 1; for (const auto &C : Certs) { - L.information(Poco::format(" Index: %d", i)); + L.information(fmt::format(" Index: {}", i)); L.information("============================================================================================="); LogCertInfo(L, C); i++; @@ -1292,6 +1635,7 @@ namespace OpenWifi { private: std::string address_; + uint32_t port_; std::string cert_file_; std::string key_file_; std::string root_ca_; @@ -1299,7 +1643,6 @@ namespace OpenWifi { std::string issuer_cert_file_; std::string client_cas_; std::string cas_; - uint32_t port_; std::string name_; int backlog_; Poco::Net::Context::VerificationMode level_; @@ -1308,37 +1651,44 @@ namespace OpenWifi { class SubSystemServer : public Poco::Util::Application::Subsystem { public: SubSystemServer(std::string Name, const std::string &LoggingPrefix, - std::string SubSystemConfigPrefix) - : Name_(std::move(Name)), Logger_(Poco::Logger::get(LoggingPrefix)), - SubSystemConfigPrefix_(std::move(SubSystemConfigPrefix)) { - Logger_.setLevel(Poco::Message::PRIO_NOTICE); - } + std::string SubSystemConfigPrefix); inline void initialize(Poco::Util::Application &self) override; inline void uninitialize() override { } - inline void reinitialize(Poco::Util::Application &self) override { - Logger_.information("Reloading of this subsystem is not supported."); + inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override { + Logger().information("Reloading of this subsystem is not supported."); } - inline void defineOptions(Poco::Util::OptionSet &options) override { + inline void defineOptions([[maybe_unused]] Poco::Util::OptionSet &options) override { } inline const std::string & Name() const { return Name_; }; inline const char * name() const override { return Name_.c_str(); } inline const PropertiesFileServerEntry & Host(uint64_t index) { return ConfigServersList_[index]; }; inline uint64_t HostSize() const { return ConfigServersList_.size(); } - inline Poco::Logger &Logger() { return Logger_; }; - inline void SetLoggingLevel(Poco::Message::Priority NewPriority) { Logger_.setLevel(NewPriority); } - inline int GetLoggingLevel() { return Logger_.getLevel(); } + inline Poco::Logger &Logger() { if(Log_) + return Log_->L; + return Poco::Logger::get("tmp"); + }; + inline void SetLoggingLevel(Poco::Message::Priority NewPriority) { Logger().setLevel(NewPriority); } + inline int GetLoggingLevel() { return Logger().getLevel(); } virtual int Start() = 0; virtual void Stop() = 0; + struct LoggerWrapper { + Poco::Logger &L; + explicit inline LoggerWrapper(Poco::Logger &Logger) : L(Logger) {} + }; + protected: std::recursive_mutex Mutex_; - Poco::Logger &Logger_; + std::vector ConfigServersList_; + private: + std::unique_ptr Log_; + // Poco::Logger &Logger_; std::string Name_; - std::vector ConfigServersList_; + std::string LoggerPrefix_; std::string SubSystemConfigPrefix_; }; @@ -1452,8 +1802,8 @@ namespace OpenWifi { int Count=0; }; - static RESTAPI_RateLimiter *instance() { - static RESTAPI_RateLimiter * instance_ = new RESTAPI_RateLimiter; + static auto instance() { + static auto instance_ = new RESTAPI_RateLimiter; return instance_; } @@ -1473,7 +1823,7 @@ namespace OpenWifi { E->Count++; Cache_.update(H,E); if(E->Count > MaxCalls) { - Logger_.warning(Poco::format("RATE-LIMIT-EXCEEDED: from '%s'", R.clientAddress().toString())); + Logger().warning(fmt::format("RATE-LIMIT-EXCEEDED: from '{}'", R.clientAddress().toString())); return true; } return false; @@ -1499,13 +1849,14 @@ namespace OpenWifi { }; - inline RESTAPI_RateLimiter * RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); } + inline auto RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); } class RESTAPIHandler : public Poco::Net::HTTPRequestHandler { public: struct QueryBlock { uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ; - std::string SerialNumber, Filter, Select; + std::string SerialNumber, Filter; + std::vector Select; bool Lifetime=false, LastOnly=false, Newest=false, CountOnly=false, AdditionalInfo=false; }; typedef std::map BindingMap; @@ -1519,21 +1870,26 @@ namespace OpenWifi { Poco::Logger &l, std::vector Methods, RESTAPI_GenericServer & Server, - bool Internal=false, + uint64_t TransactionId, + bool Internal, bool AlwaysAuthorize=true, bool RateLimited=false, - const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100}) + const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100}, + bool SubscriberOnly=false) : Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), - Server_(Server), Internal_(Internal), - AlwaysAuthorize_(AlwaysAuthorize), RateLimited_(RateLimited), - MyRates_(Profile){ + SubOnlyService_(SubscriberOnly), + AlwaysAuthorize_(AlwaysAuthorize), + Server_(Server), + MyRates_(Profile), + TransactionId_(TransactionId) + { } - inline bool RoleIsAuthorized(const std::string & Path, const std::string & Method, std::string & Reason) { + inline bool RoleIsAuthorized([[maybe_unused]] const std::string & Path, [[maybe_unused]] const std::string & Method, [[maybe_unused]] std::string & Reason) { return true; } @@ -1543,76 +1899,82 @@ namespace OpenWifi { Request = &RequestIn; Response = &ResponseIn; +// std::string th_name = "restsvr_" + std::to_string(TransactionId_); +// Utils::SetThreadName(th_name.c_str()); + + if(Request->getContentLength()>0) { + if(Request->getContentType().find("application/json")!=std::string::npos) { + ParsedBody_ = IncomingParser_.parse(Request->stream()).extract(); + } + } + if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) { - return UnAuthorized("Rate limit exceeded.",RATE_LIMIT_EXCEEDED); + return UnAuthorized(RESTAPI::Errors::RATE_LIMIT_EXCEEDED); } if (!ContinueProcessing()) return; - bool Expired=false; - if (AlwaysAuthorize_ && !IsAuthorized(Expired)) { + bool Expired=false, Contacted=false; + if (AlwaysAuthorize_ && !IsAuthorized(Expired, Contacted, SubOnlyService_)) { if(Expired) - return UnAuthorized(RESTAPI::Errors::ExpiredToken, EXPIRED_TOKEN); - return UnAuthorized(RESTAPI::Errors::InvalidCredentials, ACCESS_DENIED); + return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN); + if(Contacted) + return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN); + else + return UnAuthorized(RESTAPI::Errors::SECURITY_SERVICE_UNREACHABLE); } std::string Reason; if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) { - return UnAuthorized(Reason, ACCESS_DENIED); + return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); } ParseParameters(); if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_GET) - DoGet(); + return DoGet(); else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_POST) - DoPost(); + return DoPost(); else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) - DoDelete(); + return DoDelete(); else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_PUT) - DoPut(); - else - BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod); - return; + return DoPut(); + return BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod); } catch (const Poco::Exception &E) { Logger_.log(E); - BadRequest(RESTAPI::Errors::InternalError); + return BadRequest(RESTAPI::Errors::InternalError); } } - inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; } - inline const std::string & SelectedRecords() const { return QB_.Select; } + [[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; } + [[nodiscard]] inline const std::vector & SelectedRecords() const { return QB_.Select; } - inline const Poco::JSON::Object::Ptr & ParseStream() { - return IncomingParser_.parse(Request->stream()).extract(); - } + inline static bool ParseBindings(const std::string & Request, const std::list & EndPoints, BindingMap &bindings) { + bindings.clear(); + auto PathItems = Poco::StringTokenizer(Request, "/"); + for(const auto &EndPoint:EndPoints) { + auto ParamItems = Poco::StringTokenizer(EndPoint, "/"); + if (PathItems.count() != ParamItems.count()) + continue; - inline static bool ParseBindings(const std::string & Request, const std::list & EndPoints, BindingMap &bindings) { - bindings.clear(); - std::vector PathItems = Utils::Split(Request, '/'); - - for(const auto &EndPoint:EndPoints) { - std::vector ParamItems = Utils::Split(EndPoint, '/'); - if (PathItems.size() != ParamItems.size()) - continue; - - bool Matched = true; - for (auto i = 0; i != PathItems.size() && Matched; i++) { - if (PathItems[i] != ParamItems[i]) { - if (ParamItems[i][0] == '{') { - auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2); - bindings[Poco::toLower(ParamName)] = PathItems[i]; - } else { - Matched = false; - } - } - } - if(Matched) - return true; - } - return false; - } + bool Matched = true; + for (size_t i = 0; i < PathItems.count(); i++) { + if (PathItems[i] != ParamItems[i]) { + if (ParamItems[i][0] == '{') { + auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2); + bindings[Poco::toLower(ParamName)] = PathItems[i]; + } else { + Matched = false; + break; + } + } + } + if(Matched) + return true; + } + return false; + } inline void PrintBindings() { for (const auto &[key, value] : Bindings_) @@ -1635,29 +1997,29 @@ namespace OpenWifi { return false; } - inline uint64_t GetParameter(const std::string &Name, const uint64_t Default) { - auto Hint = std::find_if(Parameters_.begin(),Parameters_.end(),[Name](const std::pair &S){ return S.first==Name; }); + [[nodiscard]] inline uint64_t GetParameter(const std::string &Name, const uint64_t Default) { + auto Hint = std::find_if(Parameters_.begin(),Parameters_.end(),[&](const std::pair &S){ return S.first==Name; }); if(Hint==Parameters_.end() || !is_number(Hint->second)) return Default; return std::stoull(Hint->second); } - inline bool GetBoolParameter(const std::string &Name, bool Default) { - auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](const std::pair &S){ return S.first==Name; }); + [[nodiscard]] inline bool GetBoolParameter(const std::string &Name, bool Default=false) { + auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair &S){ return S.first==Name; }); if(Hint==end(Parameters_) || !is_bool(Hint->second)) return Default; return Hint->second=="true"; } - [[nodiscard]] inline std::string GetParameter(const std::string &Name, const std::string &Default) { - auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](const std::pair &S){ return S.first==Name; }); + [[nodiscard]] inline std::string GetParameter(const std::string &Name, const std::string &Default="") { + auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair &S){ return S.first==Name; }); if(Hint==end(Parameters_)) return Default; return Hint->second; } [[nodiscard]] inline bool HasParameter(const std::string &Name, std::string &Value) { - auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](const std::pair &S){ return S.first==Name; }); + auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair &S){ return S.first==Name; }); if(Hint==end(Parameters_)) return false; Value = Hint->second; @@ -1665,14 +2027,14 @@ namespace OpenWifi { } [[nodiscard]] inline bool HasParameter(const std::string &Name, uint64_t & Value) { - auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](const std::pair &S){ return S.first==Name; }); + auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair &S){ return S.first==Name; }); if(Hint==end(Parameters_)) return false; Value = std::stoull(Hint->second); return true; } - [[nodiscard]] inline const std::string & GetBinding(const std::string &Name, const std::string &Default) { + [[nodiscard]] inline const std::string & GetBinding(const std::string &Name, const std::string &Default="") { auto E = Bindings_.find(Poco::toLower(Name)); if (E == Bindings_.end()) return Default; @@ -1680,18 +2042,28 @@ namespace OpenWifi { return E->second; } - inline static std::string MakeList(const std::vector &L) { + [[nodiscard]] inline static std::string MakeList(const std::vector &L) { std::string Return; - for (const auto &i : L) - if (Return.empty()) - Return = i; - else - Return += ", " + i; - - return Return; + for (const auto &i : L) { + if (Return.empty()) + Return = i; + else + Return += ", " + i; + } + return Return; } - inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, std::string &Value) { + static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Types::UUIDvec_t & Value) { + if(O->has(Field) && O->isArray(Field)) { + auto Arr = O->getArray(Field); + for(const auto &i:*Arr) + Value.emplace_back(i.toString()); + return true; + } + return false; + } + + static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, std::string &Value) { if(O->has(Field)) { Value = O->get(Field).toString(); return true; @@ -1699,7 +2071,7 @@ namespace OpenWifi { return false; } - inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, uint64_t &Value) { + static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, uint64_t &Value) { if(O->has(Field)) { Value = O->get(Field); return true; @@ -1707,7 +2079,7 @@ namespace OpenWifi { return false; } - inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, bool &Value) { + static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, bool &Value) { if(O->has(Field)) { Value = O->get(Field).toString()=="true"; return true; @@ -1715,76 +2087,120 @@ namespace OpenWifi { return false; } - inline void AddCORS() { - auto Origin = Request->find("Origin"); - if (Origin != Request->end()) { - Response->set("Access-Control-Allow-Origin", Origin->second); - Response->set("Vary", "Origin"); - } else { - Response->set("Access-Control-Allow-Origin", "*"); - } - Response->set("Access-Control-Allow-Headers", "*"); - Response->set("Access-Control-Allow-Methods", MakeList(Methods_)); - Response->set("Access-Control-Max-Age", "86400"); - } + static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, double &Value) { + if(O->has(Field)) { + Value = (double) O->get(Field); + return true; + } + return false; + } - inline void SetCommonHeaders(bool CloseConnection=false) { + static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) { + if(O->has(Field)) { + std::string Content = O->get(Field).toString(); + auto DecodedBlob = Utils::base64decode(Content); + Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size()); + return true; + } + return false; + } + + + template bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) { + if(O->has(Field)) { + assignee = value; + return true; + } + return false; + } + + inline void SetCommonHeaders(bool CloseConnection=false) { Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1); Response->setChunkedTransferEncoding(true); Response->setContentType("application/json"); + auto Origin = Request->find("Origin"); + if (Origin != Request->end()) { + Response->set("Access-Control-Allow-Origin", Origin->second); + } else { + Response->set("Access-Control-Allow-Origin", "*"); + } + Response->set("Vary", "Origin, Accept-Encoding"); if(CloseConnection) { Response->set("Connection", "close"); Response->setKeepAlive(false); } else { Response->setKeepAlive(true); Response->set("Connection", "Keep-Alive"); - Response->set("Keep-Alive", "timeout=5, max=1000"); + Response->set("Keep-Alive", "timeout=30, max=1000"); } } inline void ProcessOptions() { - AddCORS(); - SetCommonHeaders(); - Response->setContentLength(0); - Response->set("Access-Control-Allow-Credentials", "true"); - Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK); - Response->set("Vary", "Origin, Access-Control-Request-Headers, Access-Control-Request-Method"); + Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1); + Response->setChunkedTransferEncoding(true); + auto Origin = Request->find("Origin"); + if (Origin != Request->end()) { + Response->set("Access-Control-Allow-Origin", Origin->second); + } else { + Response->set("Access-Control-Allow-Origin", "*"); + } + Response->set("Access-Control-Allow-Methods", MakeList(Methods_)); + auto RequestHeaders = Request->find("Access-Control-Request-Headers"); + if(RequestHeaders!=Request->end()) + Response->set("Access-Control-Allow-Headers", RequestHeaders->second); + Response->set("Vary", "Origin, Accept-Encoding"); + Response->set("Access-Control-Allow-Credentials", "true"); + Response->set("Access-Control-Max-Age", "86400"); + Response->set("Connection", "Keep-Alive"); + Response->set("Keep-Alive", "timeout=30, max=1000"); + + Response->setContentLength(0); + Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK); Response->send(); } inline void PrepareResponse(Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK, bool CloseConnection = false) { Response->setStatus(Status); - AddCORS(); SetCommonHeaders(CloseConnection); } - inline void BadRequest(const std::string & Reason) { + inline void BadRequest(const OpenWifi::RESTAPI::Errors::msg &E) { PrepareResponse(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST); Poco::JSON::Object ErrorObject; ErrorObject.set("ErrorCode",400); ErrorObject.set("ErrorDetails",Request->getMethod()); - ErrorObject.set("ErrorDescription",Reason.empty() ? "Command is missing parameters or wrong values." : Reason) ; + ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ; std::ostream &Answer = Response->send(); Poco::JSON::Stringifier::stringify(ErrorObject, Answer); } - inline void InternalError(const std::string & Reason = "") { +/* inline void BadRequest(uint64_t ErrorCode, const std::string & ErrorText) { + PrepareResponse(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST); + Poco::JSON::Object ErrorObject; + ErrorObject.set("ErrorCode", ErrorCode); + ErrorObject.set("ErrorDetails",Request->getMethod()); + ErrorObject.set("ErrorDescription", ErrorText) ; + std::ostream &Answer = Response->send(); + Poco::JSON::Stringifier::stringify(ErrorObject, Answer); + } +*/ + inline void InternalError(const OpenWifi::RESTAPI::Errors::msg &E) { PrepareResponse(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); Poco::JSON::Object ErrorObject; ErrorObject.set("ErrorCode",500); ErrorObject.set("ErrorDetails",Request->getMethod()); - ErrorObject.set("ErrorDescription",Reason.empty() ? "Please try later or review the data submitted." : Reason) ; + ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ; std::ostream &Answer = Response->send(); Poco::JSON::Stringifier::stringify(ErrorObject, Answer); } - inline void UnAuthorized(const std::string & Reason = "", int Code = INVALID_CREDENTIALS ) { + inline void UnAuthorized(const OpenWifi::RESTAPI::Errors::msg &E) { PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN); Poco::JSON::Object ErrorObject; - ErrorObject.set("ErrorCode",Code); + ErrorObject.set("ErrorCode",E.err_num); ErrorObject.set("ErrorDetails",Request->getMethod()); - ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ; + ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ; std::ostream &Answer = Response->send(); Poco::JSON::Stringifier::stringify(ErrorObject, Answer); } @@ -1794,10 +2210,11 @@ namespace OpenWifi { Poco::JSON::Object ErrorObject; ErrorObject.set("ErrorCode",404); ErrorObject.set("ErrorDetails",Request->getMethod()); - ErrorObject.set("ErrorDescription","This resource does not exist."); + const auto & E = OpenWifi::RESTAPI::Errors::Error404; + ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ; std::ostream &Answer = Response->send(); Poco::JSON::Stringifier::stringify(ErrorObject, Answer); - Logger_.debug(Poco::format("RES-NOTFOUND: User='%s@%s' Method='%s' Path='%s", + Logger_.debug(fmt::format("RES-NOTFOUND: User='{}@{}' Method='{}' Path='{}", UserInfo_.userinfo.email, Utils::FormatIPv6(Request->clientAddress().toString()), Request->getMethod(), @@ -1807,7 +2224,7 @@ namespace OpenWifi { inline void OK() { PrepareResponse(); if( Request->getMethod()==Poco::Net::HTTPRequest::HTTP_DELETE || - Request->getMethod()==Poco::Net::HTTPRequest::HTTP_OPTIONS) { + Request->getMethod()==Poco::Net::HTTPRequest::HTTP_OPTIONS) { Response->send(); } else { Poco::JSON::Object ErrorObject; @@ -1819,34 +2236,52 @@ namespace OpenWifi { } } + inline void SendCompressedTarFile(const std::string & FileName, const std::string & Content) { + Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK); + SetCommonHeaders(); + Response->set("Content-Type","application/gzip"); + Response->set("Content-Disposition", "attachment; filename=" + FileName ); + Response->set("Content-Transfer-Encoding","binary"); + Response->set("Accept-Ranges", "bytes"); + Response->set("Cache-Control", "no-store"); + Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); + Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK); + Response->setContentLength(Content.size()); + Response->setChunkedTransferEncoding(true); + std::ostream& OutputStream = Response->send(); + OutputStream << Content; + } + inline void SendFile(Poco::File & File, const std::string & UUID) { + Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK); + SetCommonHeaders(); Response->set("Content-Type","application/octet-stream"); Response->set("Content-Disposition", "attachment; filename=" + UUID ); Response->set("Content-Transfer-Encoding","binary"); Response->set("Accept-Ranges", "bytes"); - Response->set("Cache-Control", "private"); - Response->set("Pragma", "private"); + Response->set("Cache-Control", "no-store"); Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); Response->setContentLength(File.getSize()); - AddCORS(); Response->sendFile(File.path(),"application/octet-stream"); } inline void SendFile(Poco::File & File) { + Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK); + SetCommonHeaders(); Poco::Path P(File.path()); auto MT = Utils::FindMediaType(File); if(MT.Encoding==Utils::BINARY) { Response->set("Content-Transfer-Encoding","binary"); Response->set("Accept-Ranges", "bytes"); } - Response->set("Cache-Control", "private"); - Response->set("Pragma", "private"); + Response->set("Cache-Control", "no-store"); Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); - AddCORS(); Response->sendFile(File.path(),MT.ContentType); } - inline void SendFile(Poco::TemporaryFile &TempAvatar, const std::string &Type, const std::string & Name) { + inline void SendFile(Poco::TemporaryFile &TempAvatar, [[maybe_unused]] const std::string &Type, const std::string & Name) { + Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK); + SetCommonHeaders(); auto MT = Utils::FindMediaType(Name); if(MT.Encoding==Utils::BINARY) { Response->set("Content-Transfer-Encoding","binary"); @@ -1854,21 +2289,39 @@ namespace OpenWifi { } Response->set("Content-Disposition", "attachment; filename=" + Name ); Response->set("Accept-Ranges", "bytes"); - Response->set("Cache-Control", "private"); - Response->set("Pragma", "private"); + Response->set("Cache-Control", "no-store"); Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); - AddCORS(); + Response->setContentLength(TempAvatar.getSize()); Response->sendFile(TempAvatar.path(),MT.ContentType); } - inline void SendHTMLFileBack(Poco::File & File, + inline void SendFileContent(const std::string &Content, const std::string &Type, const std::string & Name) { + Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK); + SetCommonHeaders(); + auto MT = Utils::FindMediaType(Name); + if(MT.Encoding==Utils::BINARY) { + Response->set("Content-Transfer-Encoding","binary"); + Response->set("Accept-Ranges", "bytes"); + } + Response->set("Content-Disposition", "attachment; filename=" + Name ); + Response->set("Accept-Ranges", "bytes"); + Response->set("Cache-Control", "no-store"); + Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); + Response->setContentLength(Content.size()); + Response->setContentType(Type ); + auto & OutputStream = Response->send(); + OutputStream << Content ; + } + + inline void SendHTMLFileBack(Poco::File & File, const Types::StringPairVec & FormVars) { + Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK); + SetCommonHeaders(); Response->set("Pragma", "private"); Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT"); std::string FormContent = Utils::LoadFile(File.path()); Utils::ReplaceVariables(FormContent, FormVars); Response->setContentLength(FormContent.size()); - AddCORS(); Response->setChunkedTransferEncoding(true); Response->setContentType("text/html"); std::ostream& ostr = Response->send(); @@ -1897,13 +2350,28 @@ namespace OpenWifi { return true; } - inline bool IsAuthorized(bool & Expired); + inline bool IsAuthorized(bool & Expired, bool & Contacted, bool SubOnly = false ); - inline void ReturnObject(Poco::JSON::Object &Object) { - PrepareResponse(); - std::ostream &Answer = Response->send(); - Poco::JSON::Stringifier::stringify(Object, Answer); - } + inline void ReturnObject(Poco::JSON::Object &Object) { + PrepareResponse(); + if(Request!= nullptr) { + // can we compress ??? + auto AcceptedEncoding = Request->find("Accept-Encoding"); + if(AcceptedEncoding!=Request->end()) { + if( AcceptedEncoding->second.find("gzip")!=std::string::npos || + AcceptedEncoding->second.find("compress")!=std::string::npos) { + Response->set("Content-Encoding", "gzip"); + std::ostream &Answer = Response->send(); + Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP); + Poco::JSON::Stringifier::stringify(Object, deflater); + deflater.close(); + return; + } + } + } + std::ostream &Answer = Response->send(); + Poco::JSON::Stringifier::stringify(Object, Answer); + } inline void ReturnCountOnly(uint64_t Count) { Poco::JSON::Object Answer; @@ -1921,7 +2389,6 @@ namespace OpenWifi { QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0); QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100); QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, ""); - QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, ""); QB_.Lifetime = GetBoolParameter(RESTAPI::Protocol::LIFETIME,false); QB_.LogType = GetParameter(RESTAPI::Protocol::LOGTYPE,0); QB_.LastOnly = GetBoolParameter(RESTAPI::Protocol::LASTONLY,false); @@ -1929,6 +2396,12 @@ namespace OpenWifi { QB_.CountOnly = GetBoolParameter(RESTAPI::Protocol::COUNTONLY,false); QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false); + auto RawSelect = GetParameter(RESTAPI::Protocol::SELECT, ""); + + auto Entries = Poco::StringTokenizer(RawSelect,","); + for(const auto &i:Entries) { + QB_.Select.emplace_back(i); + } if(QB_.Offset<1) QB_.Offset=0; return true; @@ -1969,29 +2442,34 @@ namespace OpenWifi { virtual void DoPost() = 0 ; virtual void DoPut() = 0 ; + Poco::Net::HTTPServerRequest *Request= nullptr; + Poco::Net::HTTPServerResponse *Response= nullptr; + SecurityObjects::UserInfoAndPolicy UserInfo_; + QueryBlock QB_; + const std::string & Requester() const { return REST_Requester_; } protected: BindingMap Bindings_; Poco::URI::QueryParameters Parameters_; Poco::Logger &Logger_; std::string SessionToken_; - SecurityObjects::UserInfoAndPolicy UserInfo_; std::vector Methods_; - QueryBlock QB_; bool Internal_=false; bool RateLimited_=false; bool QueryBlockInitialized_=false; - Poco::Net::HTTPServerRequest *Request= nullptr; - Poco::Net::HTTPServerResponse *Response= nullptr; + bool SubOnlyService_=false; bool AlwaysAuthorize_=true; Poco::JSON::Parser IncomingParser_; RESTAPI_GenericServer & Server_; RateLimit MyRates_; + uint64_t TransactionId_; + Poco::JSON::Object::Ptr ParsedBody_; + std::string REST_Requester_; }; class RESTAPI_UnknownRequestHandler : public RESTAPIHandler { public: - RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server) - : RESTAPIHandler(bindings, L, std::vector{}, Server) {} + RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) + : RESTAPIHandler(bindings, L, std::vector{}, Server, TransactionId, Internal) {} inline void DoGet() override {}; inline void DoPost() override {}; inline void DoPut() override {}; @@ -2010,44 +2488,46 @@ namespace OpenWifi { } template - RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger, RESTAPI_GenericServer & Server) { + RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, + Poco::Logger & Logger, RESTAPI_GenericServer & Server, uint64_t TransactionId) { static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method."); if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) { - return new T(Bindings, Logger, Server, false); + return new T(Bindings, Logger, Server, TransactionId, false); } if constexpr (sizeof...(Args) == 0) { - return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server); + return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, false); } else { - return RESTAPI_Router(RequestedPath, Bindings, Logger, Server); + return RESTAPI_Router(RequestedPath, Bindings, Logger, Server, TransactionId); } } template - RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger, RESTAPI_GenericServer & Server) { + RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, + Poco::Logger & Logger, RESTAPI_GenericServer & Server, uint64_t TransactionId) { static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method."); if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) { - return new T(Bindings, Logger, Server, true); + return new T(Bindings, Logger, Server, TransactionId, true ); } if constexpr (sizeof...(Args) == 0) { - return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server); + return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, true); } else { - return RESTAPI_Router_I(RequestedPath, Bindings, Logger, Server); + return RESTAPI_Router_I(RequestedPath, Bindings, Logger, Server, TransactionId); } } class OpenAPIRequestGet { public: - explicit OpenAPIRequestGet( std::string Type, - std::string EndPoint, - Types::StringPairVec & QueryData, + explicit OpenAPIRequestGet( const std::string & Type, + const std::string & EndPoint, + const Types::StringPairVec & QueryData, uint64_t msTimeout): - Type_(std::move(Type)), - EndPoint_(std::move(EndPoint)), + Type_(Type), + EndPoint_(EndPoint), QueryData_(QueryData), msTimeout_(msTimeout) {}; - inline int Do(Poco::JSON::Object::Ptr &ResponseObject); + inline Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = ""); private: std::string Type_; std::string EndPoint_; @@ -2057,18 +2537,18 @@ namespace OpenWifi { class OpenAPIRequestPut { public: - explicit OpenAPIRequestPut( std::string Type, - std::string EndPoint, - Types::StringPairVec & QueryData, - Poco::JSON::Object Body, + explicit OpenAPIRequestPut( const std::string & Type, + const std::string & EndPoint, + const Types::StringPairVec & QueryData, + const Poco::JSON::Object & Body, uint64_t msTimeout): - Type_(std::move(Type)), - EndPoint_(std::move(EndPoint)), + Type_(Type), + EndPoint_(EndPoint), QueryData_(QueryData), msTimeout_(msTimeout), - Body_(std::move(Body)){}; + Body_(Body){}; - inline int Do(Poco::JSON::Object::Ptr &ResponseObject); + inline Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = ""); private: std::string Type_; @@ -2080,17 +2560,17 @@ namespace OpenWifi { class OpenAPIRequestPost { public: - explicit OpenAPIRequestPost( std::string Type, - std::string EndPoint, - Types::StringPairVec & QueryData, - Poco::JSON::Object Body, + explicit OpenAPIRequestPost( const std::string & Type, + const std::string & EndPoint, + const Types::StringPairVec & QueryData, + const Poco::JSON::Object & Body, uint64_t msTimeout): - Type_(std::move(Type)), - EndPoint_(std::move(EndPoint)), + Type_(Type), + EndPoint_(EndPoint), QueryData_(QueryData), msTimeout_(msTimeout), - Body_(std::move(Body)){}; - inline int Do(Poco::JSON::Object::Ptr &ResponseObject); + Body_(Body){}; + inline Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = ""); private: std::string Type_; std::string EndPoint_; @@ -2099,65 +2579,196 @@ namespace OpenWifi { Poco::JSON::Object Body_; }; + class OpenAPIRequestDelete { + public: + explicit OpenAPIRequestDelete( const std::string & Type, + const std::string & EndPoint, + const Types::StringPairVec & QueryData, + uint64_t msTimeout): + Type_(Type), + EndPoint_(EndPoint), + QueryData_(QueryData), + msTimeout_(msTimeout){}; + inline Poco::Net::HTTPServerResponse::HTTPStatus Do(const std::string & BearerToken = ""); + + private: + std::string Type_; + std::string EndPoint_; + Types::StringPairVec QueryData_; + uint64_t msTimeout_; + Poco::JSON::Object Body_; + }; + + class KafkaMessage: public Poco::Notification { + public: + KafkaMessage( const std::string &Topic, const std::string &Key, const std::string & Payload) : + Topic_(Topic), Key_(Key), Payload_(Payload) + { + + } + + inline const std::string & Topic() { return Topic_; } + inline const std::string & Key() { return Key_; } + inline const std::string & Payload() { return Payload_; } + + private: + std::string Topic_; + std::string Key_; + std::string Payload_; + + }; + class KafkaProducer : public Poco::Runnable { public: - inline void run(); - void Start() { - if(!Running_) { - Running_=true; - Worker_.start(*this); - } - } - void Stop() { - if(Running_) { - Running_=false; - Worker_.wakeUp(); - Worker_.join(); - } - } + + inline void run () override; + inline void Start() { + if(!Running_) { + Running_=true; + Worker_.start(*this); + } + } + + inline void Stop() { + if(Running_) { + Running_=false; + Queue_.wakeUpAll(); + Worker_.join(); + } + } + + inline void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload) { + std::lock_guard G(Mutex_); + Queue_.enqueueNotification( new KafkaMessage(Topic,Key,Payload)); + } + private: - std::mutex Mutex_; - Poco::Thread Worker_; - std::atomic_bool Running_=false; + std::recursive_mutex Mutex_; + Poco::Thread Worker_; + mutable std::atomic_bool Running_=false; + Poco::NotificationQueue Queue_; }; class KafkaConsumer : public Poco::Runnable { public: - inline void run(); - void Start() { + inline void run() override; + + void Start() { if(!Running_) { Running_=true; Worker_.start(*this); } } - void Stop() { + + void Stop() { if(Running_) { Running_=false; Worker_.wakeUp(); Worker_.join(); } } - private: - std::mutex Mutex_; - Poco::Thread Worker_; - std::atomic_bool Running_=false; + + private: + std::recursive_mutex Mutex_; + Poco::Thread Worker_; + mutable std::atomic_bool Running_=false; }; + class KafkaDispatcher : public Poco::Runnable { + public: + + inline void Start() { + if(!Running_) { + Running_=true; + Worker_.start(*this); + } + } + + inline void Stop() { + if(Running_) { + Running_=false; + Queue_.wakeUpAll(); + Worker_.join(); + } + } + + inline auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) { + std::lock_guard G(Mutex_); + auto It = Notifiers_.find(Topic); + if(It == Notifiers_.end()) { + Types::TopicNotifyFunctionList L; + L.emplace(L.end(),std::make_pair(F,FunctionId_)); + Notifiers_[Topic] = std::move(L); + } else { + It->second.emplace(It->second.end(),std::make_pair(F,FunctionId_)); + } + return FunctionId_++; + } + + inline void UnregisterTopicWatcher(const std::string &Topic, int Id) { + std::lock_guard G(Mutex_); + auto It = Notifiers_.find(Topic); + if(It != Notifiers_.end()) { + Types::TopicNotifyFunctionList & L = It->second; + for(auto it=L.begin(); it!=L.end(); it++) + if(it->second == Id) { + L.erase(it); + break; + } + } + } + + void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload) { + std::lock_guard G(Mutex_); + auto It = Notifiers_.find(Topic); + if(It!=Notifiers_.end()) { + Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload)); + } + } + + inline void run() override { + Poco::AutoPtr Note(Queue_.waitDequeueNotification()); + Utils::SetThreadName("kafka:dispatch"); + while(Note && Running_) { + auto Msg = dynamic_cast(Note.get()); + if(Msg!= nullptr) { + auto It = Notifiers_.find(Msg->Topic()); + if (It != Notifiers_.end()) { + const auto & FL = It->second; + for(const auto &[CallbackFunc,_]:FL) { + CallbackFunc(Msg->Key(), Msg->Payload()); + } + } + } + Note = Queue_.waitDequeueNotification(); + } + } + + inline void Topics(std::vector &T) { + T.clear(); + for(const auto &[TopicName,_]:Notifiers_) + T.push_back(TopicName); + } + + private: + std::recursive_mutex Mutex_; + Types::NotifyTable Notifiers_; + Poco::Thread Worker_; + mutable std::atomic_bool Running_=false; + uint64_t FunctionId_=1; + Poco::NotificationQueue Queue_; + }; + class KafkaManager : public SubSystemServer { public: - struct KMessage { - std::string Topic, - Key, - PayLoad; - }; friend class KafkaConsumer; friend class KafkaProducer; inline void initialize(Poco::Util::Application & self) override; - static KafkaManager *instance() { - static KafkaManager * instance_ = new KafkaManager; + static auto instance() { + static auto instance_ = new KafkaManager; return instance_; } @@ -2166,11 +2777,13 @@ namespace OpenWifi { return 0; ConsumerThr_.Start(); ProducerThr_.Start(); + Dispatcher_.Start(); return 0; } inline void Stop() override { if(KafkaEnabled_) { + Dispatcher_.Stop(); ProducerThr_.Stop(); ConsumerThr_.Stop(); return; @@ -2179,69 +2792,50 @@ namespace OpenWifi { inline void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true ) { if(KafkaEnabled_) { - std::lock_guard G(Mutex_); - KMessage M{ - .Topic = topic, - .Key = key, - .PayLoad = WrapMessage ? WrapSystemId(PayLoad) : PayLoad }; - Queue_.push(M); + ProducerThr_.Produce(topic,key,WrapMessage ? WrapSystemId(PayLoad) : PayLoad); } } + inline void Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload) { + Dispatcher_.Dispatch(Topic, Key, Payload); + } + [[nodiscard]] inline std::string WrapSystemId(const std::string & PayLoad) { - return std::move( SystemInfoWrapper_ + PayLoad + "}"); + return SystemInfoWrapper_ + PayLoad + "}"; } [[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; } - inline int RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) { + inline uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) { if(KafkaEnabled_) { - std::lock_guard G(Mutex_); - auto It = Notifiers_.find(Topic); - if(It == Notifiers_.end()) { - Types::TopicNotifyFunctionList L; - L.emplace(L.end(),std::make_pair(F,FunctionId_)); - Notifiers_[Topic] = std::move(L); - } else { - It->second.emplace(It->second.end(),std::make_pair(F,FunctionId_)); - } - return FunctionId_++; + return Dispatcher_.RegisterTopicWatcher(Topic,F); } else { return 0; } } - inline void UnregisterTopicWatcher(const std::string &Topic, int Id) { + inline void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) { if(KafkaEnabled_) { - std::lock_guard G(Mutex_); - auto It = Notifiers_.find(Topic); - if(It != Notifiers_.end()) { - Types::TopicNotifyFunctionList & L = It->second; - for(auto it=L.begin(); it!=L.end(); it++) - if(it->second == Id) { - L.erase(it); - break; - } - } + Dispatcher_.UnregisterTopicWatcher(Topic, Id); } } - // void WakeUp(); + inline void Topics(std::vector &T) { + Dispatcher_.Topics(T); + } private: bool KafkaEnabled_ = false; - std::queue Queue_; std::string SystemInfoWrapper_; - int FunctionId_=1; - Types::NotifyTable Notifiers_; KafkaProducer ProducerThr_; KafkaConsumer ConsumerThr_; + KafkaDispatcher Dispatcher_; inline void PartitionAssignment(const cppkafka::TopicPartitionList& partitions) { - Logger_.information(Poco::format("Partition assigned: %Lu...",(uint64_t )partitions.front().get_partition())); + Logger().information(fmt::format("Partition assigned: {}...", partitions.front().get_partition())); } inline void PartitionRevocation(const cppkafka::TopicPartitionList& partitions) { - Logger_.information(Poco::format("Partition revocation: %Lu...",(uint64_t )partitions.front().get_partition())); + Logger().information(fmt::format("Partition revocation: {}...",partitions.front().get_partition())); } KafkaManager() noexcept: @@ -2250,7 +2844,7 @@ namespace OpenWifi { } }; - inline KafkaManager * KafkaManager() { return KafkaManager::instance(); } + inline auto KafkaManager() { return KafkaManager::instance(); } class AuthClient : public SubSystemServer { public: @@ -2259,8 +2853,8 @@ namespace OpenWifi { { } - static AuthClient *instance() { - static AuthClient * instance_ = new AuthClient; + static auto instance() { + static auto instance_ = new AuthClient; return instance_; } @@ -2269,6 +2863,7 @@ namespace OpenWifi { } inline void Stop() override { + std::lock_guard G(Mutex_); Cache_.clear(); } @@ -2278,19 +2873,29 @@ namespace OpenWifi { } inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) { - return ((T.expires_in_+T.created_)has("tokenInfo") && Response->has("userInfo")) { UInfo.from_json(Response); if(IsTokenExpired(UInfo.webtoken)) { @@ -2298,18 +2903,22 @@ namespace OpenWifi { return false; } Expired = false; + std::lock_guard G(Mutex_); Cache_.update(SessionToken, UInfo); return true; - } + } else { + return false; + } } } catch (...) { - } Expired = false; return false; } - inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) { + inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, + bool & Expired, bool & Contacted, bool Sub = false) { + std::lock_guard G(Mutex_); auto User = Cache_.get(SessionToken); if(!User.isNull()) { if(IsTokenExpired(User->webtoken)) { @@ -2320,40 +2929,49 @@ namespace OpenWifi { UInfo = *User; return true; } - return RetrieveTokenInformation(SessionToken, UInfo, Expired); + return RetrieveTokenInformation(SessionToken, UInfo, Expired, Contacted, Sub); } private: - Poco::ExpireLRUCache Cache_{1024,1200000 }; + Poco::ExpireLRUCache Cache_{512,1200000 }; }; - inline AuthClient * AuthClient() { return AuthClient::instance(); } + inline auto AuthClient() { return AuthClient::instance(); } class ALBRequestHandler: public Poco::Net::HTTPRequestHandler /// Return a HTML document with the current date and time. { public: - explicit ALBRequestHandler(Poco::Logger & L) - : Logger_(L) + explicit ALBRequestHandler(Poco::Logger & L, uint64_t id) + : Logger_(L), id_(id) { } - void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) + void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override { - Logger_.information(Poco::format("ALB-REQUEST(%s): New ALB request.",Request.clientAddress().toString())); - Response.setChunkedTransferEncoding(true); - Response.setContentType("text/html"); - Response.setDate(Poco::Timestamp()); - Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK); - Response.setKeepAlive(true); - Response.set("Connection","keep-alive"); - Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1); - std::ostream &Answer = Response.send(); - Answer << "uCentralGW Alive and kicking!" ; + Utils::SetThreadName("alb-request"); + try { + if((id_ % 100) == 0) { + Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", + Request.clientAddress().toString(), id_)); + } + Response.setChunkedTransferEncoding(true); + Response.setContentType("text/html"); + Response.setDate(Poco::Timestamp()); + Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK); + Response.setKeepAlive(true); + Response.set("Connection", "keep-alive"); + Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1); + std::ostream &Answer = Response.send(); + Answer << "process Alive and kicking!"; + } catch (...) { + + } } private: Poco::Logger & Logger_; + uint64_t id_; }; class ALBRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory @@ -2367,13 +2985,14 @@ namespace OpenWifi { ALBRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request) override { if (request.getURI() == "/") - return new ALBRequestHandler(Logger_); + return new ALBRequestHandler(Logger_, req_id_++); else return nullptr; } private: Poco::Logger &Logger_; + inline static std::atomic_uint64_t req_id_=1; }; class ALBHealthCheckServer : public SubSystemServer { @@ -2383,8 +3002,8 @@ namespace OpenWifi { { } - static ALBHealthCheckServer *instance() { - static ALBHealthCheckServer * instance = new ALBHealthCheckServer; + static auto instance() { + static auto instance = new ALBHealthCheckServer; return instance; } @@ -2399,176 +3018,202 @@ namespace OpenWifi { std::unique_ptr Server_; std::unique_ptr Socket_; int Port_ = 0; - std::atomic_bool Running_=false; + mutable std::atomic_bool Running_=false; }; - inline ALBHealthCheckServer * ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } + inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } - Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, - Poco::Logger & L, RESTAPI_GenericServer & S); + Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, + Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t Id); - Poco::Net::HTTPRequestHandler * RESTAPI_internal_server(const char *Path, RESTAPIHandler::BindingMap &Bindings, - Poco::Logger & L, RESTAPI_GenericServer & S); + Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings, + Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t Id); - class RESTAPI_server : public SubSystemServer { + class RESTAPI_ExtServer : public SubSystemServer { public: - static RESTAPI_server *instance() { - static RESTAPI_server *instance_ = new RESTAPI_server; + static auto instance() { + static auto instance_ = new RESTAPI_ExtServer; return instance_; } int Start() override; inline void Stop() override { - Logger_.information("Stopping "); + Logger().information("Stopping..."); for( const auto & svr : RESTServers_ ) svr->stop(); + Pool_.stopAll(); Pool_.joinAll(); RESTServers_.clear(); } + inline void reinitialize(Poco::Util::Application &self) override; - inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) { + inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { RESTAPIHandler::BindingMap Bindings; - return RESTAPI_external_server(Path, Bindings, Logger_, Server_); + Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str()); + return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id); } + const Poco::ThreadPool & Pool() { return Pool_; } private: std::vector> RESTServers_; - Poco::ThreadPool Pool_; + Poco::ThreadPool Pool_{"x-rest",2,32}; RESTAPI_GenericServer Server_; - RESTAPI_server() noexcept: - SubSystemServer("RESTAPIServer", "RESTAPIServer", "openwifi.restapi") + RESTAPI_ExtServer() noexcept: + SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi") { } }; - inline RESTAPI_server * RESTAPI_server() { return RESTAPI_server::instance(); }; + inline auto RESTAPI_ExtServer() { return RESTAPI_ExtServer::instance(); }; - class RequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { + class ExtRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { public: - RequestHandlerFactory(RESTAPI_GenericServer & Server) : - Logger_(RESTAPI_server::instance()->Logger()), - Server_(Server) - { - - } - + ExtRequestHandlerFactory() = default; inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { - Poco::URI uri(Request.getURI()); - auto *Path = uri.getPath().c_str(); - return RESTAPI_server()->CallServer(Path); - } + try { + Poco::URI uri(Request.getURI()); + Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str()); + return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++); + } catch (...) { + } + return nullptr; + } private: - Poco::Logger &Logger_; - RESTAPI_GenericServer &Server_; + static inline std::atomic_uint64_t TransactionId_ = 1; }; - inline int RESTAPI_server::Start() { - Logger_.information("Starting."); - Server_.InitLogging(); + class LogMuxer : public Poco::Channel { + public: - for(const auto & Svr: ConfigServersList_) { - Logger_.information(Poco::format("Starting: %s:%s Keyfile:%s CertFile: %s", Svr.Address(), std::to_string(Svr.Port()), - Svr.KeyFile(),Svr.CertFile())); + inline std::string getProperty( [[maybe_unused]] const std::string &p ) const final { + return ""; + } - auto Sock{Svr.CreateSecureSocket(Logger_)}; + inline void close() final { + } - Svr.LogCert(Logger_); - if(!Svr.RootCA().empty()) - Svr.LogCas(Logger_); + inline void open() final { + } - Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams; - Params->setMaxThreads(50); - Params->setMaxQueued(200); - Params->setKeepAlive(true); + inline static std::string to_string(Poco::Message::Priority p) { + switch(p) { + case Poco::Message::PRIO_INFORMATION: return "information"; + case Poco::Message::PRIO_CRITICAL: return "critical"; + case Poco::Message::PRIO_DEBUG: return "debug"; + case Poco::Message::PRIO_ERROR: return "error"; + case Poco::Message::PRIO_FATAL: return "level"; + case Poco::Message::PRIO_NOTICE: return "notice"; + case Poco::Message::PRIO_TRACE: return "trace"; + case Poco::Message::PRIO_WARNING: return "warning"; + default: return "none"; + } + } - auto NewServer = std::make_unique(new RequestHandlerFactory(Server_), Pool_, Sock, Params); - NewServer->start(); - RESTServers_.push_back(std::move(NewServer)); - } + inline void log(const Poco::Message &m) final { + if(Enabled_) { + /* + nlohmann::json log_msg; + log_msg["msg"] = m.getText(); + log_msg["level"] = to_string(m.getPriority()); + log_msg["timestamp"] = Poco::DateTimeFormatter::format(m.getTime(), Poco::DateTimeFormat::ISO8601_FORMAT); + log_msg["source"] = m.getSource(); + log_msg["thread_name"] = m.getThread(); + log_msg["thread_id"] = m.getTid(); - return 0; - } + std::cout << log_msg << std::endl; + */ + std::lock_guard G(Mutex_); + std::vector Remove; + for(const auto &[Id,CallBack]:CallBacks_) { + try { + CallBack(m); + } catch (...) { + Remove.push_back(Id); + } + } + for(const auto &i:Remove) + CallBacks_.erase(i); + } + } - class RESTAPI_InternalServer : public SubSystemServer { + inline void setProperty([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) final { + } + + inline static auto instance() { + static auto instance_ = new LogMuxer; + return instance_; + } + inline void Enable(bool enable) { Enabled_ = enable; } + typedef std::function logmuxer_callback_func_t; + inline void RegisterCallback(const logmuxer_callback_func_t & R, uint64_t &Id) { + std::lock_guard G(Mutex_); + Id = CallBackId_++; + CallBacks_[Id] = R; + } + private: + std::recursive_mutex Mutex_; + std::map CallBacks_; + inline static uint64_t CallBackId_=1; + bool Enabled_ = false; + }; + inline auto LogMuxer() { return LogMuxer::instance(); } + + + class RESTAPI_IntServer : public SubSystemServer { public: - static RESTAPI_InternalServer *instance() { - static RESTAPI_InternalServer *instance_ = new RESTAPI_InternalServer; + static auto instance() { + static auto instance_ = new RESTAPI_IntServer; return instance_; } inline int Start() override; inline void Stop() override { - Logger_.information("Stopping "); + Logger().information("Stopping..."); for( const auto & svr : RESTServers_ ) svr->stop(); - Pool_.stopAll(); + Pool_.stopAll(); + Pool_.joinAll(); } inline void reinitialize(Poco::Util::Application &self) override; - inline Poco::Net::HTTPRequestHandler *CallServer(const char *Path) { + inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { RESTAPIHandler::BindingMap Bindings; - return RESTAPI_internal_server(Path, Bindings, Logger_, Server_); + Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str()); + return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id); } + + const Poco::ThreadPool & Pool() { return Pool_; } private: std::vector> RESTServers_; - Poco::ThreadPool Pool_; + Poco::ThreadPool Pool_{"i-rest",2,16}; RESTAPI_GenericServer Server_; - RESTAPI_InternalServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi") - { - } + RESTAPI_IntServer() noexcept: + SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi") + { + } }; - inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); }; + inline auto RESTAPI_IntServer() { return RESTAPI_IntServer::instance(); }; - class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { + class IntRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory { public: - InternalRequestHandlerFactory(RESTAPI_GenericServer & Server) : - Logger_(RESTAPI_InternalServer()->Logger()), - Server_(Server){} - + inline IntRequestHandlerFactory() = default; inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { + Utils::SetThreadName(fmt::format("i-rest:{}",TransactionId_).c_str()); Poco::URI uri(Request.getURI()); - auto *Path = uri.getPath().c_str(); - return RESTAPI_InternalServer()->CallServer(Path); + return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_); } private: - Poco::Logger & Logger_; - RESTAPI_GenericServer & Server_; + static inline std::atomic_uint64_t TransactionId_ = 1; }; - inline int RESTAPI_InternalServer::Start() { - Logger_.information("Starting."); - Server_.InitLogging(); - - for(const auto & Svr: ConfigServersList_) { - Logger_.information(Poco::format("Starting: %s:%s Keyfile:%s CertFile: %s", Svr.Address(), std::to_string(Svr.Port()), - Svr.KeyFile(),Svr.CertFile())); - - auto Sock{Svr.CreateSecureSocket(Logger_)}; - - Svr.LogCert(Logger_); - if(!Svr.RootCA().empty()) - Svr.LogCas(Logger_); - auto Params = new Poco::Net::HTTPServerParams; - Params->setMaxThreads(50); - Params->setMaxQueued(200); - Params->setKeepAlive(true); - - auto NewServer = std::make_unique(new InternalRequestHandlerFactory(Server_), Pool_, Sock, Params); - NewServer->start(); - RESTServers_.push_back(std::move(NewServer)); - } - - return 0; - } - struct MicroServiceMeta { uint64_t Id=0; std::string Type; @@ -2579,10 +3224,8 @@ namespace OpenWifi { uint64_t LastUpdate=0; }; - - class SubSystemServer; - typedef std::map MicroServiceMetaMap; + typedef std::map MicroServiceMetaMap; typedef std::vector MicroServiceMetaVec; typedef std::vector SubSystemVec; @@ -2594,18 +3237,19 @@ namespace OpenWifi { std::string AppName, uint64_t BusTimer, SubSystemVec Subsystems) : - DAEMON_PROPERTIES_FILENAME(std::move(PropFile)), - DAEMON_ROOT_ENV_VAR(std::move(RootEnv)), - DAEMON_CONFIG_ENV_VAR(std::move(ConfigVar)), - DAEMON_APP_NAME(std::move(AppName)), - DAEMON_BUS_TIMER(BusTimer), - SubSystems_(std::move(Subsystems)) { + DAEMON_PROPERTIES_FILENAME(std::move(PropFile)), + DAEMON_ROOT_ENV_VAR(std::move(RootEnv)), + DAEMON_CONFIG_ENV_VAR(std::move(ConfigVar)), + DAEMON_APP_NAME(std::move(AppName)), + DAEMON_BUS_TIMER(BusTimer), + SubSystems_(std::move(Subsystems)), + Logger_(Poco::Logger::get("FRAMEWORK")) { instance_ = this; RandomEngine_.seed(std::chrono::steady_clock::now().time_since_epoch().count()); + // Logger_ = Poco::Logger::root().get("BASE-SVC"); } [[nodiscard]] std::string Version() { return Version_; } - [[nodiscard]] const Poco::SharedPtr & Key() { return AppKey_; } [[nodiscard]] inline const std::string & DataDir() { return DataDir_; } [[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; } [[nodiscard]] bool Debug() const { return DebugMode_; } @@ -2628,8 +3272,23 @@ namespace OpenWifi { return ((RandomEngine_() % (max-min)) + min); } - inline void Exit(int Reason); - inline void BusMessageReceived(const std::string &Key, const std::string & Message); + inline Poco::Logger & GetLogger(const std::string &Name) { + static auto initialized = false; + + if(!initialized) { + initialized = true; + InitializeLoggingSystem(); + } + return Poco::Logger::get(Name); + } + + virtual void GetExtraConfiguration(Poco::JSON::Object & Cfg) { + Cfg.set("additionalConfiguration",false); + } + + + static inline void Exit(int Reason); + inline void BusMessageReceived(const std::string &Key, const std::string & Payload); inline MicroServiceMetaVec GetServices(const std::string & Type); inline MicroServiceMetaVec GetServices(); inline void LoadConfigurationFile(); @@ -2664,12 +3323,37 @@ namespace OpenWifi { inline std::string ConfigPath(const std::string &Key); inline std::string Encrypt(const std::string &S); inline std::string Decrypt(const std::string &S); - inline std::string CreateHash(const std::string &S); inline std::string MakeSystemEventMessage( const std::string & Type ) const; [[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request); inline static void SavePID(); inline int main(const ArgVec &args) override; static MicroService & instance() { return *instance_; } + inline void InitializeLoggingSystem(); + inline void SaveConfig() { PropConfigurationFile_->save(ConfigFileName_); } + inline auto UpdateConfig() { return PropConfigurationFile_; } + inline void AddActivity(const std::string &Activity) { + if(!DataDir_.empty()) { + std::string ActivityFile{ DataDir_ + "/activity.log"}; + try { + std::ofstream of(ActivityFile,std::ios_base::app | std::ios_base::out ); + auto t = std::chrono::system_clock::now(); + std::time_t now = std::chrono::system_clock::to_time_t(t); + of << Activity << " at " << std::ctime(&now) ; + } catch (...) { + + } + } + } + inline bool NoAPISecurity() const { return NoAPISecurity_; } + [[nodiscard]] inline std::string Sign(Poco::JWT::Token &T, const std::string &Algo) { + if(NoBuiltInCrypto_) { + return T.toString(); + } else { + return Signer_.sign(T,Algo); + } + } + + inline Poco::ThreadPool & TimerPool() { return TimerPool_; } private: static MicroService * instance_; @@ -2682,71 +3366,82 @@ namespace OpenWifi { bool DebugMode_ = false; std::string DataDir_; std::string WWWAssetsDir_; - SubSystemVec SubSystems_; Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); Poco::Crypto::Cipher * Cipher_ = nullptr; - Poco::SHA2Engine SHA2_; MicroServiceMetaMap Services_; std::string MyHash_; std::string MyPrivateEndPoint_; std::string MyPublicEndPoint_; std::string UIURI_; - std::string Version_{std::string(APP_VERSION) + "("+ BUILD_NUMBER + ")"}; + std::string Version_{ OW_VERSION::VERSION + "("+ OW_VERSION::BUILD + ")" + " - " + OW_VERSION::HASH }; BusEventManager BusEventManager_; - std::mutex InfraMutex_; + std::recursive_mutex InfraMutex_; std::default_random_engine RandomEngine_; - - std::string DAEMON_PROPERTIES_FILENAME; - std::string DAEMON_ROOT_ENV_VAR; - std::string DAEMON_CONFIG_ENV_VAR; - std::string DAEMON_APP_NAME; - uint64_t DAEMON_BUS_TIMER; - }; + Poco::Util::PropertyFileConfiguration * PropConfigurationFile_ = nullptr; + std::string DAEMON_PROPERTIES_FILENAME; + std::string DAEMON_ROOT_ENV_VAR; + std::string DAEMON_CONFIG_ENV_VAR; + std::string DAEMON_APP_NAME; + uint64_t DAEMON_BUS_TIMER; + SubSystemVec SubSystems_; + bool NoAPISecurity_=false; + bool NoBuiltInCrypto_=false; + Poco::JWT::Signer Signer_; + Poco::Logger &Logger_; + Poco::ThreadPool TimerPool_{"timer:pool",2,16}; + }; inline void MicroService::Exit(int Reason) { std::exit(Reason); } - inline void MicroService::BusMessageReceived(const std::string &Key, const std::string & Message) { + inline void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key, const std::string & Payload) { std::lock_guard G(InfraMutex_); try { Poco::JSON::Parser P; - auto Object = P.parse(Message).extract(); + auto Object = P.parse(Payload).extract(); + if (Object->has(KafkaTopics::ServiceEvents::Fields::ID) && - Object->has(KafkaTopics::ServiceEvents::Fields::EVENT)) { + Object->has(KafkaTopics::ServiceEvents::Fields::EVENT)) { uint64_t ID = Object->get(KafkaTopics::ServiceEvents::Fields::ID); auto Event = Object->get(KafkaTopics::ServiceEvents::Fields::EVENT).toString(); if (ID != ID_) { if( Event==KafkaTopics::ServiceEvents::EVENT_JOIN || - Event==KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE || - Event==KafkaTopics::ServiceEvents::EVENT_LEAVE ) { + Event==KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE || + Event==KafkaTopics::ServiceEvents::EVENT_LEAVE ) { if( Object->has(KafkaTopics::ServiceEvents::Fields::TYPE) && - Object->has(KafkaTopics::ServiceEvents::Fields::PUBLIC) && - Object->has(KafkaTopics::ServiceEvents::Fields::PRIVATE) && - Object->has(KafkaTopics::ServiceEvents::Fields::VRSN) && - Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) { - - if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && Services_.find(ID) != Services_.end()) { - Services_[ID].LastUpdate = std::time(nullptr); + Object->has(KafkaTopics::ServiceEvents::Fields::PUBLIC) && + Object->has(KafkaTopics::ServiceEvents::Fields::PRIVATE) && + Object->has(KafkaTopics::ServiceEvents::Fields::VRSN) && + Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) { + auto PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(); + if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && Services_.find(PrivateEndPoint) != Services_.end()) { + Services_[PrivateEndPoint].LastUpdate = OpenWifi::Now(); } else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) { - Services_.erase(ID); - logger().information(Poco::format("Service %s ID=%Lu leaving system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID)); + Services_.erase(PrivateEndPoint); + poco_debug(logger(),fmt::format("Service {} ID={} leaving system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID)); } else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN || Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) { - logger().information(Poco::format("Service %s ID=%Lu joining system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID)); - Services_[ID] = MicroServiceMeta{ + poco_debug(logger(),fmt::format("Service {} ID={} joining system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID)); + Services_[PrivateEndPoint] = MicroServiceMeta{ .Id = ID, .Type = Poco::toLower(Object->get(KafkaTopics::ServiceEvents::Fields::TYPE).toString()), .PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(), .PublicEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PUBLIC).toString(), .AccessKey = Object->get(KafkaTopics::ServiceEvents::Fields::KEY).toString(), .Version = Object->get(KafkaTopics::ServiceEvents::Fields::VRSN).toString(), - .LastUpdate = (uint64_t)std::time(nullptr)}; - for (const auto &[Id, Svc] : Services_) { - logger().information(Poco::format("ID: %Lu Type: %s EndPoint: %s",Id,Svc.Type,Svc.PrivateEndPoint)); + .LastUpdate = OpenWifi::Now() }; + + std::string SvcList; + for (const auto &Svc: Services_) { + if(SvcList.empty()) + SvcList = Svc.second.Type; + else + SvcList += ", " + Svc.second.Type; } + logger().information(fmt::format("Current list of microservices: {}", SvcList)); } } else { - logger().error(Poco::format("KAFKA-MSG: invalid event '%s', missing a field.",Event)); + poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",Event)); } } else if (Event==KafkaTopics::ServiceEvents::EVENT_REMOVE_TOKEN) { if(Object->has(KafkaTopics::ServiceEvents::Fields::TOKEN)) { @@ -2754,27 +3449,27 @@ namespace OpenWifi { AuthClient()->RemovedCachedToken(Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString()); #endif } else { - logger().error(Poco::format("KAFKA-MSG: invalid event '%s', missing token",Event)); + poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing token",Event)); } } else { - logger().error(Poco::format("Unknown Event: %s Source: %Lu", Event, ID)); + poco_error(logger(),fmt::format("Unknown Event: {} Source: {}", Event, ID)); } } } else { - logger().error("Bad bus message."); + poco_error(logger(),"Bad bus message."); } auto i=Services_.begin(); - auto Now = (uint64_t )std::time(nullptr); + auto now = OpenWifi::Now(); for(;i!=Services_.end();) { - if((Now - i->second.LastUpdate)>60) { + if((now - i->second.LastUpdate)>60) { i = Services_.erase(i); } else ++i; } } catch (const Poco::Exception &E) { - logger().log(E); + Logger_.log(E); } } @@ -2783,7 +3478,7 @@ namespace OpenWifi { auto T = Poco::toLower(Type); MicroServiceMetaVec Res; - for(const auto &[Id,ServiceRec]:Services_) { + for(const auto &[_,ServiceRec]:Services_) { if(ServiceRec.Type==T) Res.push_back(ServiceRec); } @@ -2794,7 +3489,7 @@ namespace OpenWifi { std::lock_guard G(InfraMutex_); MicroServiceMetaVec Res; - for(const auto &[Id,ServiceRec]:Services_) { + for(const auto &[_,ServiceRec]:Services_) { Res.push_back(ServiceRec); } return Res; @@ -2802,9 +3497,8 @@ namespace OpenWifi { inline void MicroService::LoadConfigurationFile() { std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,"."); - Poco::Path ConfigFile; - - ConfigFile = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_; + ConfigFileName_ = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_; + Poco::Path ConfigFile(ConfigFileName_); if(!ConfigFile.isFile()) { @@ -2814,7 +3508,9 @@ namespace OpenWifi { std::exit(Poco::Util::Application::EXIT_CONFIG); } - loadConfiguration(ConfigFile.toString()); + // loadConfiguration(ConfigFile.toString()); + PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString()); + configPtr()->addWriteable(PropConfigurationFile_, PRIO_DEFAULT); } inline void MicroService::Reload() { @@ -2823,27 +3519,96 @@ namespace OpenWifi { } inline void MicroService::LoadMyConfig() { - std::string KeyFile = ConfigPath("openwifi.service.key"); - std::string KeyFilePassword = ConfigPath("openwifi.service.key.password" , "" ); - AppKey_ = Poco::SharedPtr(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword)); - Cipher_ = CipherFactory_.createCipher(*AppKey_); + NoAPISecurity_ = ConfigGetBool("openwifi.security.restapi.disable",false); + std::string KeyFile = ConfigPath("openwifi.service.key",""); + if(!KeyFile.empty()) { + std::string KeyFilePassword = ConfigPath("openwifi.service.key.password", ""); + AppKey_ = Poco::SharedPtr(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword)); + Cipher_ = CipherFactory_.createCipher(*AppKey_); + Signer_.setRSAKey(AppKey_); + Signer_.addAllAlgorithms(); + NoBuiltInCrypto_ = false; + } else { + NoBuiltInCrypto_ = true; + } + ID_ = Utils::GetSystemId(); if(!DebugMode_) DebugMode_ = ConfigGetBool("openwifi.system.debug",false); MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private"); MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public"); UIURI_ = ConfigGetString("openwifi.system.uri.ui"); - MyHash_ = CreateHash(MyPublicEndPoint_); + MyHash_ = Utils::ComputeHash(MyPublicEndPoint_); } void MicroServicePostInitialization(); + inline void MicroService::InitializeLoggingSystem() { + static auto initialized = false; + + if(!initialized) { + initialized = true; + LoadConfigurationFile(); + + auto LoggingDestination = MicroService::instance().ConfigGetString("logging.type", "file"); + auto LoggingFormat = MicroService::instance().ConfigGetString("logging.format", + "%Y-%m-%d %H:%M:%S %s: [%p] %t"); + if (LoggingDestination == "console") { + Poco::AutoPtr Console(new Poco::ConsoleChannel); + Poco::AutoPtr Async(new Poco::AsyncChannel(Console)); + Poco::AutoPtr Formatter(new Poco::PatternFormatter); + Formatter->setProperty("pattern", LoggingFormat); + Poco::AutoPtr FormattingChannel( + new Poco::FormattingChannel(Formatter, Async)); + Poco::Logger::root().setChannel(FormattingChannel); + } else if (LoggingDestination == "colorconsole") { + Poco::AutoPtr Console(new Poco::ColorConsoleChannel); + Poco::AutoPtr Async(new Poco::AsyncChannel(Console)); + Poco::AutoPtr Formatter(new Poco::PatternFormatter); + Formatter->setProperty("pattern", LoggingFormat); + Poco::AutoPtr FormattingChannel( + new Poco::FormattingChannel(Formatter, Async)); + Poco::Logger::root().setChannel(FormattingChannel); + } else if (LoggingDestination == "sql") { + //"CREATE TABLE T_POCO_LOG (Source VARCHAR, Name VARCHAR, ProcessId INTEGER, Thread VARCHAR, ThreadId INTEGER, Priority INTEGER, Text VARCHAR, DateTime DATE)" + + } else if (LoggingDestination == "syslog") { + + } else { + auto LoggingLocation = + MicroService::instance().ConfigPath("logging.path", "$OWCERT_ROOT/logs") + "/log"; + + Poco::AutoPtr FileChannel(new Poco::FileChannel); + FileChannel->setProperty("rotation", "10 M"); + FileChannel->setProperty("archive", "timestamp"); + FileChannel->setProperty("path", LoggingLocation); + Poco::AutoPtr Async_File(new Poco::AsyncChannel(FileChannel)); + Poco::AutoPtr Async_Muxer(new Poco::AsyncChannel(LogMuxer())); + Poco::AutoPtr Splitter(new Poco::SplitterChannel); + Splitter->addChannel(Async_File); + Splitter->addChannel(Async_Muxer); + Poco::AutoPtr Formatter(new Poco::PatternFormatter); + Formatter->setProperty("pattern", LoggingFormat); + Poco::AutoPtr FormattingChannel( + new Poco::FormattingChannel(Formatter, Splitter)); + Poco::Logger::root().setChannel(FormattingChannel); + } + auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug")); + Poco::Logger::root().setLevel(Level); + } + } + + void DaemonPostInitialization(Poco::Util::Application &self); + inline void MicroService::initialize(Poco::Util::Application &self) { - // add the default services + // add the default services + LoadConfigurationFile(); + InitializeLoggingSystem(); + SubSystems_.push_back(KafkaManager()); SubSystems_.push_back(ALBHealthCheckServer()); - SubSystems_.push_back(RESTAPI_server()); - SubSystems_.push_back(RESTAPI_InternalServer()); + SubSystems_.push_back(RESTAPI_ExtServer()); + SubSystems_.push_back(RESTAPI_IntServer()); Poco::Net::initializeSSL(); Poco::Net::HTTPStreamFactory::registerFactory(); @@ -2851,17 +3616,6 @@ namespace OpenWifi { Poco::Net::FTPStreamFactory::registerFactory(); Poco::Net::FTPSStreamFactory::registerFactory(); - LoadConfigurationFile(); - - static const char * LogFilePathKey = "logging.channels.c2.path"; - - if(LogDir_.empty()) { - std::string OriginalLogFileValue = ConfigPath(LogFilePathKey); - config().setString(LogFilePathKey, OriginalLogFileValue); - } else { - config().setString(LogFilePathKey, LogDir_); - } - Poco::File DataDir(ConfigPath("openwifi.system.data")); DataDir_ = DataDir.path(); if(!DataDir.exists()) { @@ -2879,11 +3633,10 @@ namespace OpenWifi { InitializeSubSystemServers(); ServerApplication::initialize(self); + DaemonPostInitialization(self); - Types::TopicNotifyFunction F = [this](std::string s1,std::string s2) { this->BusMessageReceived(s1,s2); }; + Types::TopicNotifyFunction F = [this](const std::string &Key,const std::string &Payload) { this->BusMessageReceived(Key, Payload); }; KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F); - - MicroServicePostInitialization(); } inline void MicroService::uninitialize() { @@ -2933,28 +3686,28 @@ namespace OpenWifi { } - inline void MicroService::handleHelp(const std::string &name, const std::string &value) { + inline void MicroService::handleHelp([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) { HelpRequested_ = true; displayHelp(); stopOptionsProcessing(); } - inline void MicroService::handleVersion(const std::string &name, const std::string &value) { + inline void MicroService::handleVersion([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) { HelpRequested_ = true; std::cout << Version() << std::endl; stopOptionsProcessing(); } - inline void MicroService::handleDebug(const std::string &name, const std::string &value) { + inline void MicroService::handleDebug([[maybe_unused]] const std::string &name, const std::string &value) { if(value == "true") DebugMode_ = true ; } - inline void MicroService::handleLogs(const std::string &name, const std::string &value) { + inline void MicroService::handleLogs([[maybe_unused]] const std::string &name, const std::string &value) { LogDir_ = value; } - inline void MicroService::handleConfig(const std::string &name, const std::string &value) { + inline void MicroService::handleConfig([[maybe_unused]] const std::string &name, const std::string &value) { ConfigFileName_ = value; } @@ -2972,6 +3725,7 @@ namespace OpenWifi { } inline void MicroService::StartSubSystemServers() { + AddActivity("Starting"); for(auto i:SubSystems_) { i->Start(); } @@ -2979,6 +3733,7 @@ namespace OpenWifi { } inline void MicroService::StopSubSystemServers() { + AddActivity("Stopping"); BusEventManager_.Stop(); for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) { (*i)->Stop(); @@ -3036,7 +3791,7 @@ namespace OpenWifi { } } } catch (const Poco::Exception & E) { - std::cout << "Exception" << std::endl; + std::cerr << "Exception" << std::endl; } return false; } @@ -3107,18 +3862,19 @@ namespace OpenWifi { } inline std::string MicroService::Encrypt(const std::string &S) { + if(NoBuiltInCrypto_) { + return S; + } return Cipher_->encryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);; } inline std::string MicroService::Decrypt(const std::string &S) { + if(NoBuiltInCrypto_) { + return S; + } return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);; } - inline std::string MicroService::CreateHash(const std::string &S) { - SHA2_.update(S); - return Utils::ToHex(SHA2_.digest()); - } - inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const { Poco::JSON::Object Obj; Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type); @@ -3155,15 +3911,95 @@ namespace OpenWifi { } } - inline int MicroService::main(const ArgVec &args) { + inline SubSystemServer::SubSystemServer(std::string Name, const std::string &LoggingPrefix, + std::string SubSystemConfigPrefix): + Name_(std::move(Name)), + LoggerPrefix_(LoggingPrefix), + SubSystemConfigPrefix_(std::move(SubSystemConfigPrefix)) { + } + inline int RESTAPI_ExtServer::Start() { + Server_.InitLogging(); + + for(const auto & Svr: ConfigServersList_) { + + if(MicroService::instance().NoAPISecurity()) { + Logger().information(fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port())); + } else { + Logger().information(fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(), + Svr.KeyFile(),Svr.CertFile())); + Svr.LogCert(Logger()); + if (!Svr.RootCA().empty()) + Svr.LogCas(Logger()); + } + + Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams; + Params->setMaxThreads(50); + Params->setMaxQueued(200); + Params->setKeepAlive(true); + Params->setName("ws:xrest"); + + std::unique_ptr NewServer; + if(MicroService::instance().NoAPISecurity()) { + auto Sock{Svr.CreateSocket(Logger())}; + NewServer = std::make_unique(new ExtRequestHandlerFactory, Pool_, Sock, Params); + } else { + auto Sock{Svr.CreateSecureSocket(Logger())}; + NewServer = std::make_unique(new ExtRequestHandlerFactory, Pool_, Sock, Params); + }; + NewServer->start(); + RESTServers_.push_back(std::move(NewServer)); + } + + return 0; + } + + inline int RESTAPI_IntServer::Start() { + Logger().information("Starting."); + Server_.InitLogging(); + + for(const auto & Svr: ConfigServersList_) { + + if(MicroService::instance().NoAPISecurity()) { + Logger().information(fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port())); + } else { + Logger().information(fmt::format("Starting: {}:{}. Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(), + Svr.KeyFile(),Svr.CertFile())); + Svr.LogCert(Logger()); + if (!Svr.RootCA().empty()) + Svr.LogCas(Logger()); + } + + auto Params = new Poco::Net::HTTPServerParams; + Params->setMaxThreads(50); + Params->setMaxQueued(200); + Params->setKeepAlive(true); + Params->setName("ws:irest"); + + std::unique_ptr NewServer; + if(MicroService::instance().NoAPISecurity()) { + auto Sock{Svr.CreateSocket(Logger())}; + NewServer = std::make_unique(new IntRequestHandlerFactory, Pool_, Sock, Params); + } else { + auto Sock{Svr.CreateSecureSocket(Logger())}; + NewServer = std::make_unique(new IntRequestHandlerFactory, Pool_, Sock, Params); + }; + NewServer->start(); + RESTServers_.push_back(std::move(NewServer)); + } + + return 0; + } + + inline int MicroService::main([[maybe_unused]] const ArgVec &args) { MyErrorHandler ErrorHandler(*this); Poco::ErrorHandler::set(&ErrorHandler); if (!HelpRequested_) { SavePID(); + Poco::Logger &logger = Poco::Logger::get(DAEMON_APP_NAME); - logger.notice(Poco::format("Starting %s version %s.",DAEMON_APP_NAME, Version())); + logger.notice(fmt::format("Starting {} version {}.",DAEMON_APP_NAME, Version())); if(Poco::Net::Socket::supportsIPv6()) logger.information("System supports IPv6."); @@ -3173,11 +4009,12 @@ namespace OpenWifi { if (config().getBool("application.runAsDaemon", false)) { logger.information("Starting as a daemon."); } - logger.information(Poco::format("System ID set to %Lu",ID_)); + + logger.information(fmt::format("System ID set to {}",ID_)); StartSubSystemServers(); waitForTerminationRequest(); StopSubSystemServers(); - logger.notice(Poco::format("Stopped %s...",DAEMON_APP_NAME)); + logger.notice(fmt::format("Stopped {}...",DAEMON_APP_NAME)); } return Application::EXIT_OK; @@ -3199,11 +4036,12 @@ namespace OpenWifi { } } - inline void SubSystemServer::initialize(Poco::Util::Application &self) { - Logger_.notice("Initializing..."); + inline void SubSystemServer::initialize([[maybe_unused]] Poco::Util::Application &self) { auto i = 0; bool good = true; + Log_ = std::make_unique(Poco::Logger::get(LoggerPrefix_)); + ConfigServersList_.clear(); while (good) { std::string root{SubSystemConfigPrefix_ + ".host." + std::to_string(i) + "."}; @@ -3260,7 +4098,8 @@ namespace OpenWifi { Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); Socket_ = std::make_unique(Port_); auto Params = new Poco::Net::HTTPServerParams; - Server_ = std::make_unique(new ALBRequestHandlerFactory(Logger_), *Socket_, Params); + Params->setName("ws:alb"); + Server_ = std::make_unique(new ALBRequestHandlerFactory(Logger()), *Socket_, Params); Server_->start(); } @@ -3269,6 +4108,7 @@ namespace OpenWifi { inline void BusEventManager::run() { Running_ = true; + Utils::SetThreadName("fmwk:EventMgr"); auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN); KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false); while(Running_) { @@ -3301,42 +4141,101 @@ namespace OpenWifi { KafkaEnabled_ = MicroService::instance().ConfigGetBool("openwifi.kafka.enable",false); } + inline void KafkaLoggerFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int level, const std::string & facility, const std::string &message) { + switch ((cppkafka::LogLevel) level) { + case cppkafka::LogLevel::LogNotice: { + KafkaManager()->Logger().notice(fmt::format("kafka-log: facility: {} message: {}",facility, message)); + } + break; + case cppkafka::LogLevel::LogDebug: { + KafkaManager()->Logger().debug(fmt::format("kafka-log: facility: {} message: {}",facility, message)); + } + break; + case cppkafka::LogLevel::LogInfo: { + KafkaManager()->Logger().information(fmt::format("kafka-log: facility: {} message: {}",facility, message)); + } + break; + case cppkafka::LogLevel::LogWarning: { + KafkaManager()->Logger().warning(fmt::format("kafka-log: facility: {} message: {}",facility, message)); + } + break; + case cppkafka::LogLevel::LogAlert: + case cppkafka::LogLevel::LogCrit: { + KafkaManager()->Logger().critical(fmt::format("kafka-log: facility: {} message: {}",facility, message)); + } + break; + case cppkafka::LogLevel::LogErr: + case cppkafka::LogLevel::LogEmerg: + default: { + KafkaManager()->Logger().error(fmt::format("kafka-log: facility: {} message: {}",facility, message)); + } + break; + } + } + + inline void KafkaErrorFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int error, const std::string &reason) { + KafkaManager()->Logger().error(fmt::format("kafka-error: {}, reason: {}", error, reason)); + } + + inline void AddKafkaSecurity(cppkafka::Configuration & Config) { + auto CA = MicroService::instance().ConfigGetString("openwifi.kafka.ssl.ca.location",""); + auto Certificate = MicroService::instance().ConfigGetString("openwifi.kafka.ssl.certificate.location",""); + auto Key = MicroService::instance().ConfigGetString("openwifi.kafka.ssl.key.location",""); + auto Password = MicroService::instance().ConfigGetString("openwifi.kafka.ssl.key.password",""); + + if(CA.empty() || Certificate.empty() || Key.empty()) + return; + + Config.set("ssl.ca.location", CA); + Config.set("ssl.certificate.location", Certificate); + Config.set("ssl.key.location", Key); + if(!Password.empty()) + Config.set("ssl.key.password", Password); + } + inline void KafkaProducer::run() { + + Utils::SetThreadName("Kafka:Prod"); cppkafka::Configuration Config({ - { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, - { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } + { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, + { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } }); + + AddKafkaSecurity(Config); + + Config.set_log_callback(KafkaLoggerFun); + Config.set_error_callback(KafkaErrorFun); + KafkaManager()->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" + std::to_string(MicroService::instance().ID()) + R"lit( , "host" : ")lit" + MicroService::instance().PrivateEndPoint() + R"lit(" } , "payload" : )lit" ; - cppkafka::Producer Producer(Config); + + cppkafka::Producer Producer(Config); Running_ = true; - while(Running_) { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - try - { - std::lock_guard G(Mutex_); - auto Num=0; - while (!KafkaManager()->Queue_.empty()) { - const auto M = KafkaManager()->Queue_.front(); - Producer.produce( - cppkafka::MessageBuilder(M.Topic).key(M.Key).payload(M.PayLoad)); - KafkaManager()->Queue_.pop(); - Num++; - } - if(Num) - Producer.flush(); - } catch (const cppkafka::HandleException &E ) { - KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (producer): %s",std::string{E.what()})); - } catch (const Poco::Exception &E) { - KafkaManager()->Logger_.log(E); - } - } - Producer.flush(); + + Poco::AutoPtr Note(Queue_.waitDequeueNotification()); + while(Note && Running_) { + try { + auto Msg = dynamic_cast(Note.get()); + if (Msg != nullptr) { + Producer.produce( + cppkafka::MessageBuilder(Msg->Topic()).key(Msg->Key()).payload(Msg->Payload())); + } + } catch (const cppkafka::HandleException &E) { + KafkaManager()->Logger().warning(fmt::format("Caught a Kafka exception (producer): {}", E.what())); + } catch( const Poco::Exception &E) { + KafkaManager()->Logger().log(E); + } catch (...) { + KafkaManager()->Logger().error("std::exception"); + } + Note = Queue_.waitDequeueNotification(); + } } inline void KafkaConsumer::run() { + Utils::SetThreadName("Kafka:Cons"); + cppkafka::Configuration Config({ { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, @@ -3346,6 +4245,11 @@ namespace OpenWifi { { "enable.partition.eof", false } }); + AddKafkaSecurity(Config); + + Config.set_log_callback(KafkaLoggerFun); + Config.set_error_callback(KafkaErrorFun); + cppkafka::TopicConfiguration topic_config = { { "auto.offset.reset", "smallest" } }; @@ -3354,16 +4258,16 @@ namespace OpenWifi { Config.set_default_topic_configuration(topic_config); cppkafka::Consumer Consumer(Config); - Consumer.set_assignment_callback([this](cppkafka::TopicPartitionList& partitions) { + Consumer.set_assignment_callback([](cppkafka::TopicPartitionList& partitions) { if(!partitions.empty()) { - KafkaManager()->Logger_.information(Poco::format("Partition assigned: %Lu...", - (uint64_t)partitions.front().get_partition())); + KafkaManager()->Logger().information(fmt::format("Partition assigned: {}...", + partitions.front().get_partition())); } }); - Consumer.set_revocation_callback([this](const cppkafka::TopicPartitionList& partitions) { + Consumer.set_revocation_callback([](const cppkafka::TopicPartitionList& partitions) { if(!partitions.empty()) { - KafkaManager()->Logger_.information(Poco::format("Partition revocation: %Lu...", - (uint64_t)partitions.front().get_partition())); + KafkaManager()->Logger().information(fmt::format("Partition revocation: {}...", + partitions.front().get_partition())); } }); @@ -3371,72 +4275,64 @@ namespace OpenWifi { auto BatchSize = MicroService::instance().ConfigGetInt("openwifi.kafka.consumer.batchsize",20); Types::StringVec Topics; - for(const auto &i:KafkaManager()->Notifiers_) - Topics.push_back(i.first); - + KafkaManager()->Topics(Topics); Consumer.subscribe(Topics); Running_ = true; while(Running_) { try { - std::vector MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(200)); + std::vector MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100)); for(auto const &Msg:MsgVec) { if (!Msg) continue; if (Msg.get_error()) { if (!Msg.is_eof()) { - KafkaManager()->Logger_.error(Poco::format("Error: %s", Msg.get_error().to_string())); - }if(!AutoCommit) + KafkaManager()->Logger().error(fmt::format("Error: {}", Msg.get_error().to_string())); + } + if(!AutoCommit) Consumer.async_commit(Msg); continue; } - std::lock_guard G(Mutex_); - auto It = KafkaManager()->Notifiers_.find(Msg.get_topic()); - if (It != KafkaManager()->Notifiers_.end()) { - Types::TopicNotifyFunctionList &FL = It->second; - std::string Key{Msg.get_key()}; - std::string Payload{Msg.get_payload()}; - for (auto &F : FL) { - std::thread T(F.first, Key, Payload); - T.detach(); - } - } + KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(),Msg.get_payload() ); if (!AutoCommit) Consumer.async_commit(Msg); } } catch (const cppkafka::HandleException &E) { - KafkaManager()->Logger_.warning(Poco::format("Caught a Kafka exception (consumer): %s",std::string{E.what()})); + KafkaManager()->Logger().warning(fmt::format("Caught a Kafka exception (consumer): {}", E.what())); } catch (const Poco::Exception &E) { - KafkaManager()->Logger_.log(E); - } + KafkaManager()->Logger().log(E); + } catch (...) { + KafkaManager()->Logger().error("std::exception"); + } } Consumer.unsubscribe(); } - inline void RESTAPI_server::reinitialize(Poco::Util::Application &self) { + inline void RESTAPI_ExtServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) { MicroService::instance().LoadConfigurationFile(); - Logger_.information("Reinitializing."); + Logger().information("Reinitializing."); Stop(); Start(); } - void RESTAPI_InternalServer::reinitialize(Poco::Util::Application &self) { + void RESTAPI_IntServer::reinitialize([[maybe_unused]] Poco::Util::Application &self) { MicroService::instance().LoadConfigurationFile(); - Logger_.information("Reinitializing."); + Logger().information("Reinitializing."); Stop(); Start(); } class RESTAPI_system_command : public RESTAPIHandler { public: - RESTAPI_system_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal) + RESTAPI_system_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal) : RESTAPIHandler(bindings, L, std::vector{Poco::Net::HTTPRequest::HTTP_POST, Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_OPTIONS}, Server, + TransactionId, Internal) {} - static const std::list PathName() { return std::list{"/api/v1/system"};} + static auto PathName() { return std::list{"/api/v1/system"};} inline void DoGet() { std::string Arg; @@ -3459,15 +4355,18 @@ namespace OpenWifi { for(uint64_t j=0;jHost(j).CertFile(); if(!CertFileName.empty()) { - auto InsertResult = CertNames.insert(CertFileName); - if(InsertResult.second) { - Poco::JSON::Object Inner; - Poco::Path F(CertFileName); - Inner.set("filename", F.getFileName()); - Poco::Crypto::X509Certificate C(CertFileName); - auto ExpiresOn = C.expiresOn(); - Inner.set("expiresOn",ExpiresOn.timestamp().epochTime()); - Certificates.add(Inner); + Poco::File F1(CertFileName); + if(F1.exists()) { + auto InsertResult = CertNames.insert(CertFileName); + if(InsertResult.second) { + Poco::JSON::Object Inner; + Poco::Path F(CertFileName); + Inner.set("filename", F.getFileName()); + Poco::Crypto::X509Certificate C(CertFileName); + auto ExpiresOn = C.expiresOn(); + Inner.set("expiresOn", ExpiresOn.timestamp().epochTime()); + Certificates.add(Inner); + } } } } @@ -3475,11 +4374,16 @@ namespace OpenWifi { Answer.set("certificates", Certificates); return ReturnObject(Answer); } + if(GetBoolParameter("extraConfiguration")) { + Poco::JSON::Object Answer; + MicroService::instance().GetExtraConfiguration(Answer); + return ReturnObject(Answer); + } BadRequest(RESTAPI::Errors::InvalidCommand); } inline void DoPost() final { - auto Obj = ParseStream(); + const auto & Obj = ParsedBody_; if (Obj->has(RESTAPI::Protocol::COMMAND)) { auto Command = Poco::toLower(Obj->get(RESTAPI::Protocol::COMMAND).toString()); if (Command == RESTAPI::Protocol::SETLOGLEVEL) { @@ -3495,7 +4399,7 @@ namespace OpenWifi { auto Value = GetS(RESTAPI::Protocol::VALUE, InnerObj); MicroService::instance().SetSubsystemLogLevel(Name, Value); Logger_.information( - Poco::format("Setting log level for %s at %s", Name, Value)); + fmt::format("Setting log level for {} at {}", Name, Value)); } } return OK(); @@ -3560,56 +4464,84 @@ namespace OpenWifi { void DoDelete() final {}; }; - inline int OpenAPIRequestGet::Do(Poco::JSON::Object::Ptr &ResponseObject) { + inline Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestGet::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) { try { auto Services = MicroService::instance().GetServices(Type_); for(auto const &Svc:Services) { Poco::URI URI(Svc.PrivateEndPoint); - Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + + auto Secure = (URI.getScheme() == "https"); URI.setPath(EndPoint_); for (const auto &qp : QueryData_) URI.addQueryParameter(qp.first, qp.second); std::string Path(URI.getPathAndQuery()); - Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000)); - Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET, Path, Poco::Net::HTTPMessage::HTTP_1_1); - Request.add("X-API-KEY", Svc.AccessKey); - Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); - Session.sendRequest(Request); - Poco::Net::HTTPResponse Response; - std::istream &is = Session.receiveResponse(Response); - if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { - Poco::JSON::Parser P; - ResponseObject = P.parse(is).extract(); + poco_debug(Poco::Logger::get("REST-CALLER-GET"),fmt::format(" {}", URI.toString())); + + if(BearerToken.empty()) { + Request.add("X-API-KEY", Svc.AccessKey); + Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); + } else { + // Authorization: Bearer ${token} + Request.add("Authorization", "Bearer " + BearerToken); + } + + if(Secure) { + Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + + Session.sendRequest(Request); + + Poco::Net::HTTPResponse Response; + std::istream &is = Session.receiveResponse(Response); + if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } + return Response.getStatus(); + } else { + Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + + Session.sendRequest(Request); + + Poco::Net::HTTPResponse Response; + std::istream &is = Session.receiveResponse(Response); + if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } + return Response.getStatus(); } - return Response.getStatus(); } } catch (const Poco::Exception &E) { - std::cerr << E.displayText() << std::endl; + Poco::Logger::get("REST-CALLER-GET").log(E); } - return -1; + return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT; } - inline int OpenAPIRequestPut::Do(Poco::JSON::Object::Ptr &ResponseObject) { + inline Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPut::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) { try { auto Services = MicroService::instance().GetServices(Type_); for(auto const &Svc:Services) { Poco::URI URI(Svc.PrivateEndPoint); - Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + + auto Secure = (URI.getScheme() == "https"); URI.setPath(EndPoint_); for (const auto &qp : QueryData_) URI.addQueryParameter(qp.first, qp.second); + poco_debug(Poco::Logger::get("REST-CALLER-PUT"),fmt::format("{}", URI.toString())); + std::string Path(URI.getPathAndQuery()); - Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000)); Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_PUT, Path, @@ -3620,44 +4552,75 @@ namespace OpenWifi { Request.setContentType("application/json"); Request.setContentLength(obody.str().size()); - Request.add("X-API-KEY", Svc.AccessKey); - Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); - - std::ostream & os = Session.sendRequest(Request); - os << obody.str(); - - Poco::Net::HTTPResponse Response; - std::istream &is = Session.receiveResponse(Response); - if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { - Poco::JSON::Parser P; - ResponseObject = P.parse(is).extract(); + if(BearerToken.empty()) { + Request.add("X-API-KEY", Svc.AccessKey); + Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); } else { - Poco::JSON::Parser P; - ResponseObject = P.parse(is).extract(); + // Authorization: Bearer ${token} + Request.add("Authorization", "Bearer " + BearerToken); + } + + if(Secure) { + Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + + std::ostream &os = Session.sendRequest(Request); + os << obody.str(); + + Poco::Net::HTTPResponse Response; + std::istream &is = Session.receiveResponse(Response); + if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } else { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } + return Response.getStatus(); + } else { + Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + + std::ostream &os = Session.sendRequest(Request); + os << obody.str(); + + Poco::Net::HTTPResponse Response; + std::istream &is = Session.receiveResponse(Response); + if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } else { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } + return Response.getStatus(); } - return Response.getStatus(); } } catch (const Poco::Exception &E) { - std::cerr << E.displayText() << std::endl; + Poco::Logger::get("REST-CALLER-PUT").log(E); } - return -1; + return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT; } - int OpenAPIRequestPost::Do(Poco::JSON::Object::Ptr &ResponseObject) { + inline Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPost::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) { try { auto Services = MicroService::instance().GetServices(Type_); + for(auto const &Svc:Services) { Poco::URI URI(Svc.PrivateEndPoint); - Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + + + auto Secure = (URI.getScheme() == "https"); URI.setPath(EndPoint_); for (const auto &qp : QueryData_) URI.addQueryParameter(qp.first, qp.second); + poco_debug(Poco::Logger::get("REST-CALLER-POST"),fmt::format(" {}", URI.toString())); + std::string Path(URI.getPathAndQuery()); - Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000)); Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST, Path, @@ -3668,31 +4631,107 @@ namespace OpenWifi { Request.setContentType("application/json"); Request.setContentLength(obody.str().size()); - Request.add("X-API-KEY", Svc.AccessKey); - Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); - - std::ostream & os = Session.sendRequest(Request); - os << obody.str(); - - Poco::Net::HTTPResponse Response; - std::istream &is = Session.receiveResponse(Response); - if(Response.getStatus()==Poco::Net::HTTPResponse::HTTP_OK) { - Poco::JSON::Parser P; - ResponseObject = P.parse(is).extract(); + if(BearerToken.empty()) { + Request.add("X-API-KEY", Svc.AccessKey); + Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); } else { - Poco::JSON::Parser P; - ResponseObject = P.parse(is).extract(); + // Authorization: Bearer ${token} + Request.add("Authorization", "Bearer " + BearerToken); + } + + if(Secure) { + Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + std::ostream &os = Session.sendRequest(Request); + os << obody.str(); + + Poco::Net::HTTPResponse Response; + std::istream &is = Session.receiveResponse(Response); + if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } else { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } + return Response.getStatus(); + } else { + Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + std::ostream &os = Session.sendRequest(Request); + os << obody.str(); + + Poco::Net::HTTPResponse Response; + std::istream &is = Session.receiveResponse(Response); + if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } else { + Poco::JSON::Parser P; + ResponseObject = P.parse(is).extract(); + } + return Response.getStatus(); } - return Response.getStatus(); } } catch (const Poco::Exception &E) { - std::cerr << E.displayText() << std::endl; + Poco::Logger::get("REST-CALLER-POST").log(E); } - return -1; + return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT; } + inline Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestDelete::Do(const std::string & BearerToken) { + try { + auto Services = MicroService::instance().GetServices(Type_); + + for(auto const &Svc:Services) { + Poco::URI URI(Svc.PrivateEndPoint); + + auto Secure = (URI.getScheme() == "https"); + + URI.setPath(EndPoint_); + for (const auto &qp : QueryData_) + URI.addQueryParameter(qp.first, qp.second); + + poco_debug(Poco::Logger::get("REST-CALLER-DELETE"),fmt::format(" {}", URI.toString())); + + std::string Path(URI.getPathAndQuery()); + + Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_DELETE, + Path, + Poco::Net::HTTPMessage::HTTP_1_1); + if(BearerToken.empty()) { + Request.add("X-API-KEY", Svc.AccessKey); + Request.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint()); + } else { + // Authorization: Bearer ${token} + Request.add("Authorization", "Bearer " + BearerToken); + } + + if(Secure) { + Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + Session.sendRequest(Request); + Poco::Net::HTTPResponse Response; + Session.receiveResponse(Response); + return Response.getStatus(); + } else { + Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort()); + Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000)); + Session.sendRequest(Request); + Poco::Net::HTTPResponse Response; + Session.receiveResponse(Response); + return Response.getStatus(); + } + } + } + catch (const Poco::Exception &E) + { + Poco::Logger::get("REST-CALLER-DELETE").log(E); + } + return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT; + } inline void RESTAPI_GenericServer::InitLogging() { std::string Public = MicroService::instance().ConfigGetString("apilogging.public.methods","PUT,POST,DELETE"); @@ -3707,21 +4746,23 @@ namespace OpenWifi { } #ifdef TIP_SECURITY_SERVICE - [[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired ); + [[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired , bool Sub ); #endif - inline bool RESTAPIHandler::IsAuthorized( bool & Expired ) { - if(Internal_) { + inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) { + if(Internal_ && Request->has("X-INTERNAL-NAME")) { auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); + Contacted = true; if(!Allowed) { if(Server_.LogBadTokens(false)) { - Logger_.debug(Poco::format("I-REQ-DENIED(%s): Method='%s' Path='%s", + Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}", Utils::FormatIPv6(Request->clientAddress().toString()), Request->getMethod(), Request->getURI())); } } else { auto Id = Request->get("X-INTERNAL-NAME", "unknown"); + REST_Requester_ = Id; if(Server_.LogIt(Request->getMethod(),true)) { - Logger_.debug(Poco::format("I-REQ-ALLOWED(%s): User='%s' Method='%s' Path='%s", + Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}", Utils::FormatIPv6(Request->clientAddress().toString()), Id, Request->getMethod(), Request->getURI())); } @@ -3739,12 +4780,13 @@ namespace OpenWifi { } } #ifdef TIP_SECURITY_SERVICE - if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired)) { + if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired, Sub)) { #else - if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired)) { + if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) { #endif + REST_Requester_ = UserInfo_.userinfo.email; if(Server_.LogIt(Request->getMethod(),true)) { - Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s", + Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}", UserInfo_.userinfo.email, Utils::FormatIPv6(Request->clientAddress().toString()), Request->clientAddress().toString(), @@ -3754,7 +4796,7 @@ namespace OpenWifi { return true; } else { if(Server_.LogBadTokens(true)) { - Logger_.debug(Poco::format("X-REQ-DENIED(%s): Method='%s' Path='%s", + Logger_.debug(fmt::format("X-REQ-DENIED({}): Method={} Path={}", Utils::FormatIPv6(Request->clientAddress().toString()), Request->getMethod(), Request->getURI())); } @@ -3764,6 +4806,445 @@ namespace OpenWifi { } inline MicroService * MicroService::instance_ = nullptr; + + template struct WebSocketNotification { + inline static uint64_t xid=1; + uint64_t notification_id=++xid; + std::string type; + ContentStruct content; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + template void WebSocketNotification::to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json(Obj,"notification_id",notification_id); + RESTAPI_utils::field_to_json(Obj,"type",type); + RESTAPI_utils::field_to_json(Obj,"content",content); + } + + template bool WebSocketNotification::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json(Obj,"notification_id",notification_id); + RESTAPI_utils::field_from_json(Obj,"content",content); + RESTAPI_utils::field_from_json(Obj,"type",type); + return true; + } catch(...) { + + } + return false; + } + + class WebSocketClientProcessor { + public: + virtual void Processor(const Poco::JSON::Object::Ptr &O, std::string &Answer, bool &Done ) = 0; + private: + }; + +/* class MyParallelSocketReactor { + public: + explicit MyParallelSocketReactor(uint32_t NumReactors = 8); + ~MyParallelSocketReactor(); + Poco::Net::SocketReactor &Reactor(); + private: + uint32_t NumReactors_; + Poco::Net::SocketReactor *Reactors_; + Poco::ThreadPool ReactorPool_; + }; +*/ + + class WebSocketClient; + + class WebSocketClientServer : public SubSystemServer, Poco::Runnable { + public: + static auto instance() { + static auto instance_ = new WebSocketClientServer; + return instance_; + } + + int Start() override; + void Stop() override; + void run() override; + // MyParallelSocketReactor &ReactorPool(); + Poco::Net::SocketReactor & Reactor() { return Reactor_; } + void NewClient(Poco::Net::WebSocket &WS, const std::string &Id); + bool Register(WebSocketClient *Client, const std::string &Id); + void SetProcessor(WebSocketClientProcessor *F); + void UnRegister(const std::string &Id); + void SetUser(const std::string &Id, const std::string &UserId); + [[nodiscard]] inline bool GeoCodeEnabled() const { return GeoCodeEnabled_; } + [[nodiscard]] inline std::string GoogleApiKey() const { return GoogleApiKey_; } + [[nodiscard]] bool Send(const std::string &Id, const std::string &Payload); + + template bool + SendUserNotification(const std::string &userName, const WebSocketNotification &Notification) { + + Poco::JSON::Object Payload; + Notification.to_json(Payload); + Poco::JSON::Object Msg; + Msg.set("notification",Payload); + std::ostringstream OO; + Msg.stringify(OO); + + return SendToUser(userName,OO.str()); + } + + template void SendNotification(const WebSocketNotification &Notification) { + Poco::JSON::Object Payload; + Notification.to_json(Payload); + Poco::JSON::Object Msg; + Msg.set("notification",Payload); + std::ostringstream OO; + Msg.stringify(OO); + SendToAll(OO.str()); + } + + [[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload); + void SendToAll(const std::string &Payload); + private: + mutable std::atomic_bool Running_ = false; + Poco::Thread Thr_; + // std::unique_ptr ReactorPool_; + Poco::Net::SocketReactor Reactor_; + Poco::Thread ReactorThread_; + bool GeoCodeEnabled_ = false; + std::string GoogleApiKey_; + std::map> Clients_; + WebSocketClientProcessor *Processor_ = nullptr; + WebSocketClientServer() noexcept; + }; + + inline auto WebSocketClientServer() { return WebSocketClientServer::instance(); } + + class WebSocketClient { + public: + explicit WebSocketClient(Poco::Net::WebSocket &WS, const std::string &Id, Poco::Logger &L, + WebSocketClientProcessor *Processor); + virtual ~WebSocketClient(); + [[nodiscard]] inline const std::string &Id(); + [[nodiscard]] Poco::Logger &Logger(); + inline bool Send(const std::string &Payload); + private: + std::unique_ptr WS_; + Poco::Net::SocketReactor &Reactor_; + std::string Id_; + Poco::Logger &Logger_; + bool Authenticated_ = false; + SecurityObjects::UserInfoAndPolicy UserInfo_; + WebSocketClientProcessor *Processor_ = nullptr; + void OnSocketReadable(const Poco::AutoPtr &pNf); + void OnSocketShutdown(const Poco::AutoPtr &pNf); + void OnSocketError(const Poco::AutoPtr &pNf); + }; + +/* inline MyParallelSocketReactor::MyParallelSocketReactor(uint32_t NumReactors) : + NumReactors_(NumReactors) + { + Reactors_ = new Poco::Net::SocketReactor[NumReactors_]; + for(uint32_t i=0;isecond.first,UserId); + } + } + + [[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload); + inline WebSocketClientServer::WebSocketClientServer() noexcept: + SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients") + { + } + + inline void WebSocketClientServer::run() { + Running_ = true ; + Utils::SetThreadName("ws:uiclnt-svr"); + while(Running_) { + Poco::Thread::trySleep(2000); + + if(!Running_) + break; + } + }; + + inline int WebSocketClientServer::Start() { + GoogleApiKey_ = MicroService::instance().ConfigGetString("google.apikey",""); + GeoCodeEnabled_ = !GoogleApiKey_.empty(); + // ReactorPool_ = std::make_unique(); + ReactorThread_.start(Reactor_); + Thr_.start(*this); + return 0; + }; + + inline void WebSocketClientServer::Stop() { + if(Running_) { + Reactor_.stop(); + ReactorThread_.join(); + Running_ = false; + Thr_.wakeUp(); + Thr_.join(); + } + }; + + + inline void WebSocketClient::OnSocketError([[maybe_unused]] const Poco::AutoPtr &pNf) { + delete this; + } + + inline bool WebSocketClientServer::Send(const std::string &Id, const std::string &Payload) { + std::lock_guard G(Mutex_); + + auto It = Clients_.find(Id); + if(It!=Clients_.end()) + return It->second.first->Send(Payload); + return false; + } + + inline bool WebSocketClientServer::SendToUser(const std::string &UserName, const std::string &Payload) { + std::lock_guard G(Mutex_); + uint64_t Sent=0; + + for(const auto &client:Clients_) { + if(client.second.second == UserName) { + try { + if (client.second.first->Send(Payload)) + Sent++; + } catch (...) { + return false; + } + } + } + return Sent>0; + } + + inline void WebSocketClientServer::SendToAll(const std::string &Payload) { + std::lock_guard G(Mutex_); + + for(const auto &client:Clients_) { + try { + client.second.first->Send(Payload); + } catch (...) { + + } + } + } + + inline void WebSocketClient::OnSocketReadable([[maybe_unused]] const Poco::AutoPtr &pNf) { + int flags; + int n; + bool Done=false; + try { + Poco::Buffer IncomingFrame(0); + n = WS_->receiveFrame(IncomingFrame, flags); + auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK; + + if (n == 0) { + return delete this; + } + + switch (Op) { + case Poco::Net::WebSocket::FRAME_OP_PING: { + WS_->sendFrame("", 0, + (int)Poco::Net::WebSocket::FRAME_OP_PONG | + (int)Poco::Net::WebSocket::FRAME_FLAG_FIN); + } break; + case Poco::Net::WebSocket::FRAME_OP_PONG: { + } break; + case Poco::Net::WebSocket::FRAME_OP_CLOSE: { + Logger().warning(Poco::format("CLOSE(%s): UI Client is closing its connection.", Id_)); + Done = true; + } break; + case Poco::Net::WebSocket::FRAME_OP_TEXT: { + IncomingFrame.append(0); + if (!Authenticated_) { + std::string Frame{IncomingFrame.begin()}; + auto Tokens = Utils::Split(Frame, ':'); + bool Expired = false, Contacted = false; + if (Tokens.size() == 2 && + AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { + Authenticated_ = true; + std::string S{"Welcome! Bienvenue! Bienvenidos!"}; + WS_->sendFrame(S.c_str(), S.size()); + WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email); + } else { + std::string S{"Invalid token. Closing connection."}; + WS_->sendFrame(S.c_str(), S.size()); + Done = true; + } + + } else { + try { + Poco::JSON::Parser P; + auto Obj = + P.parse(IncomingFrame.begin()).extract(); + std::string Answer; + if (Processor_ != nullptr) + Processor_->Processor(Obj, Answer, Done); + if (!Answer.empty()) + WS_->sendFrame(Answer.c_str(), (int)Answer.size()); + else { + WS_->sendFrame("{}", 2); + } + } catch (const Poco::JSON::JSONException &E) { + Logger().log(E); + Done=true; + } + } + } break; + default: { + } + } + } catch (...) { + Done=true; + } + + if(Done) { + delete this; + } + } + + inline void WebSocketClient::OnSocketShutdown([[maybe_unused]] const Poco::AutoPtr &pNf) { + delete this; + } + + + inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, Poco::Logger & L, WebSocketClientProcessor * Processor) : + Reactor_(WebSocketClientServer()->Reactor()), + Id_(Id), + Logger_(L), + Processor_(Processor) { + try { + WS_ = std::make_unique(WS); + Reactor_.addEventHandler(*WS_, + Poco::NObserver( + *this, &WebSocketClient::OnSocketReadable)); + Reactor_.addEventHandler(*WS_, + Poco::NObserver( + *this, &WebSocketClient::OnSocketShutdown)); + Reactor_.addEventHandler(*WS_, + Poco::NObserver( + *this, &WebSocketClient::OnSocketError)); + // WebSocketClientServer()->Register(this, Id_); + } catch (...) { + delete this; + } + } + + inline WebSocketClient::~WebSocketClient() { + try { + WebSocketClientServer()->UnRegister(Id_); + Reactor_.removeEventHandler(*WS_, + Poco::NObserver(*this,&WebSocketClient::OnSocketReadable)); + Reactor_.removeEventHandler(*WS_, + Poco::NObserver(*this,&WebSocketClient::OnSocketShutdown)); + Reactor_.removeEventHandler(*WS_, + Poco::NObserver(*this,&WebSocketClient::OnSocketError)); + (*WS_).shutdown(); + (*WS_).close(); + WebSocketClientServer()->UnRegister(Id_); + } catch(...) { + + } + } + + [[nodiscard]] inline const std::string & WebSocketClient::Id() { + return Id_; + }; + + [[nodiscard]] inline Poco::Logger & WebSocketClient::Logger() { + return Logger_; + } + + [[nodiscard]] inline bool WebSocketClient::Send(const std::string &Payload) { + try { + WS_->sendFrame(Payload.c_str(),Payload.size()); + return true; + } catch (...) { + + } + return false; + } + + class RESTAPI_webSocketServer : public RESTAPIHandler { + public: + inline RESTAPI_webSocketServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, uint64_t TransactionId, bool Internal) + : RESTAPIHandler(bindings, L, + std::vector{ Poco::Net::HTTPRequest::HTTP_GET, + Poco::Net::HTTPRequest::HTTP_OPTIONS}, + Server, TransactionId, Internal,false) {} + static auto PathName() { return std::list{"/api/v1/ws"};} + void DoGet() final; + void DoDelete() final {}; + void DoPost() final {}; + void DoPut() final {}; + private: + }; + + inline void RESTAPI_webSocketServer::DoGet() { + try + { + if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) { + try + { + Poco::Net::WebSocket WS(*Request, *Response); + Logger().information("UI-WebSocket connection established."); + auto Id = MicroService::CreateUUID(); + WebSocketClientServer()->NewClient(WS,Id); + } + catch (...) { + std::cout << "Cannot create websocket client..." << std::endl; + } + } + } catch(...) { + std::cout << "Cannot upgrade connection..." << std::endl; + } + } + + } namespace OpenWifi::Utils { diff --git a/microservice_sample/src/framework/OpenWifiTypes.h b/microservice_sample/src/framework/OpenWifiTypes.h index c5b3804..f49edc0 100644 --- a/microservice_sample/src/framework/OpenWifiTypes.h +++ b/microservice_sample/src/framework/OpenWifiTypes.h @@ -14,22 +14,24 @@ #include namespace OpenWifi::Types { - typedef std::pair StringPair; - typedef std::vector StringPairVec; - typedef std::queue StringPairQueue; - typedef std::vector StringVec; - typedef std::set StringSet; - typedef std::map> StringMapStringSet; - typedef std::function TopicNotifyFunction; - typedef std::list> TopicNotifyFunctionList; - typedef std::map NotifyTable; - typedef std::map CountedMap; - typedef std::vector TagList; - typedef std::string UUID_t; - typedef std::vector UUIDvec_t; + typedef std::pair StringPair; + typedef std::vector StringPairVec; + typedef std::queue StringPairQueue; + typedef std::vector StringVec; + typedef std::set StringSet; + typedef std::map> StringMapStringSet; + typedef std::function TopicNotifyFunction; + typedef std::list> TopicNotifyFunctionList; + typedef std::map NotifyTable; + typedef std::map CountedMap; + typedef std::vector TagList; + typedef std::string UUID_t; + typedef std::vector UUIDvec_t; + typedef std::map> Counted3DMapSII; } namespace OpenWifi { + inline void UpdateCountedMap(OpenWifi::Types::CountedMap &M, const std::string &S, uint64_t Increment=1) { auto it = M.find(S); if(it==M.end()) @@ -37,4 +39,22 @@ namespace OpenWifi { else it->second += Increment; } + + inline void UpdateCountedMap(OpenWifi::Types::Counted3DMapSII &M, const std::string &S, uint32_t Index, uint64_t Increment=1) { + auto it = M.find(S); + if(it==M.end()) { + std::map E; + E[Index] = Increment; + M[S] = E; + } + else { + std::map & IndexMap = it->second; + auto it_index = IndexMap.find(Index); + if(it_index == IndexMap.end()) { + IndexMap[Index] = Increment; + } else { + it_index->second += Increment; + } + } + } } diff --git a/microservice_sample/src/framework/RESTAPI_errors.h b/microservice_sample/src/framework/RESTAPI_errors.h deleted file mode 100644 index b203797..0000000 --- a/microservice_sample/src/framework/RESTAPI_errors.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Created by stephane bourque on 2021-09-12. -// - -#pragma once - -namespace OpenWifi::RESTAPI::Errors { - static const std::string MissingUUID{"Missing UUID."}; - static const std::string MissingSerialNumber{"Missing Serial Number."}; - static const std::string InternalError{"Internal error. Please try later."}; - static const std::string InvalidJSONDocument{"Invalid JSON document."}; - static const std::string UnsupportedHTTPMethod{"Unsupported HTTP Method"}; - static const std::string StillInUse{"Element still in use."}; - static const std::string CouldNotBeDeleted{"Element could not be deleted."}; - static const std::string NameMustBeSet{"The name property must be set."}; - static const std::string ConfigBlockInvalid{"Configuration block type invalid."}; - static const std::string UnknownId{"Unknown management policy."}; - static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."}; - static const std::string RecordNotCreated{"Record could not be created."}; - static const std::string RecordNotUpdated{"Record could not be updated."}; - static const std::string UnknownManagementPolicyUUID{"Unknown management policy UUID."}; - static const std::string CannotDeleteRoot{"Root Entity cannot be removed, only modified."}; - static const std::string MustCreateRootFirst{"Root entity must be created first."}; - static const std::string ParentUUIDMustExist{"Parent UUID must exist."}; - static const std::string ConfigurationMustExist{"Configuration must exist."}; - static const std::string MissingOrInvalidParameters{"Invalid or missing parameters."}; - static const std::string UnknownSerialNumber{"Unknown Serial Number."}; - static const std::string InvalidSerialNumber{"Invalid Serial Number."}; - static const std::string SerialNumberExists{"Serial Number already exists."}; - static const std::string ValidNonRootUUID{"Must be a non-root, and valid UUID."}; - static const std::string VenueMustExist{"Venue does not exist."}; - static const std::string NotBoth{"You cannot specify both Entity and Venue"}; - static const std::string EntityMustExist{"Entity must exist."}; - static const std::string ParentOrEntityMustBeSet{"Parent or Entity must be set."}; - static const std::string ContactMustExist{"Contact must exist."}; - static const std::string LocationMustExist{"Location must exist."}; - static const std::string OnlyWSSupported{"This endpoint only supports WebSocket."}; - static const std::string SerialNumberMismatch{"Serial Number mismatch."}; - static const std::string InvalidCommand{"Invalid command."}; - static const std::string NoRecordsDeleted{"No records deleted."}; - static const std::string DeviceNotConnected{"Device is not currently connected."}; - static const std::string CannotCreateWS{"Telemetry system could not create WS endpoint. Please try again."}; - static const std::string BothDeviceTypeRevision{"Both deviceType and revision must be set."}; - static const std::string IdOrSerialEmpty{"SerialNumber and Id must not be empty."}; - static const std::string MissingUserID{"Missing user ID."}; - static const std::string IdMustBe0{"To create a user, you must set the ID to 0"}; - static const std::string InvalidUserRole{"Invalid userRole."}; - static const std::string InvalidEmailAddress{"Invalid email address."}; - static const std::string PasswordRejected{"Password was rejected. This maybe an old password."}; - static const std::string InvalidIPRanges{"Invalid IP range specifications."}; - static const std::string InvalidLOrderBy{"Invalid orderBy specification."}; - static const std::string NeedMobileNumber{"You must provide at least one validated phone number."}; - static const std::string BadMFAMethod{"MFA only supports sms or email."}; - static const std::string InvalidCredentials{"Invalid credentials (username/password)."}; - static const std::string InvalidPassword{"Password does not conform to basic password rules."}; - static const std::string UserPendingVerification{"User access denied pending email verification."}; - static const std::string PasswordMustBeChanged{"Password must be changed."}; - static const std::string UnrecognizedRequest{"Ill-formed request. Please consult documentation."}; - static const std::string MissingAuthenticationInformation{"Missing authentication information."}; - static const std::string InsufficientAccessRights{"Insufficient access rights to complete the operation."}; - static const std::string ExpiredToken{"Token has expired, user must login."}; -} - diff --git a/microservice_sample/src/framework/RESTAPI_protocol.h b/microservice_sample/src/framework/RESTAPI_protocol.h deleted file mode 100644 index fdfe4b5..0000000 --- a/microservice_sample/src/framework/RESTAPI_protocol.h +++ /dev/null @@ -1,137 +0,0 @@ -// -// License type: BSD 3-Clause License -// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE -// -// Created by Stephane Bourque on 2021-03-04. -// Arilia Wireless Inc. -// - -#pragma once - -namespace OpenWifi::RESTAPI::Protocol { - static const char * CAPABILITIES = "capabilities"; - static const char * LOGS = "logs"; - static const char * HEALTHCHECKS = "healthchecks"; - static const char * STATISTICS = "statistics"; - static const char * STATUS = "status"; - static const char * SERIALNUMBER = "serialNumber"; - static const char * PERFORM = "perform"; - static const char * CONFIGURE = "configure"; - static const char * UPGRADE = "upgrade"; - static const char * REBOOT = "reboot"; - static const char * FACTORY = "factory"; - static const char * LEDS = "leds"; - static const char * TRACE = "trace"; - static const char * REQUEST = "request"; - static const char * WIFISCAN = "wifiscan"; - static const char * EVENTQUEUE = "eventqueue"; - static const char * RTTY = "rtty"; - static const char * COMMAND = "command"; - static const char * STARTDATE = "startDate"; - static const char * ENDDATE = "endDate"; - static const char * OFFSET = "offset"; - static const char * LIMIT = "limit"; - static const char * LIFETIME = "lifetime"; - static const char * UUID = "UUID"; - static const char * DATA = "data"; - static const char * CONFIGURATION = "configuration"; - static const char * WHEN = "when"; - static const char * URI = "uri"; - static const char * LOGTYPE = "logType"; - static const char * VALUES = "values"; - static const char * TYPES = "types"; - static const char * PAYLOAD = "payload"; - static const char * KEEPREDIRECTOR = "keepRedirector"; - static const char * NETWORK = "network"; - static const char * INTERFACE = "interface"; - static const char * BANDS = "bands"; - static const char * CHANNELS = "channels"; - static const char * VERBOSE = "verbose"; - static const char * MESSAGE = "message"; - static const char * STATE = "state"; - static const char * HEALTHCHECK = "healthcheck"; - static const char * PCAP_FILE_TYPE = "pcap"; - static const char * DURATION = "duration"; - static const char * NUMBEROFPACKETS = "numberOfPackets"; - static const char * FILTER = "filter"; - static const char * SELECT = "select"; - static const char * SERIALONLY = "serialOnly"; - static const char * COUNTONLY = "countOnly"; - static const char * DEVICEWITHSTATUS = "deviceWithStatus"; - static const char * DEVICESWITHSTATUS = "devicesWithStatus"; - static const char * DEVICES = "devices"; - static const char * COUNT = "count"; - static const char * SERIALNUMBERS = "serialNumbers"; - static const char * CONFIGURATIONS = "configurations"; - static const char * NAME = "name"; - static const char * COMMANDS = "commands"; - static const char * COMMANDUUID = "commandUUID"; - static const char * FIRMWARES = "firmwares"; - static const char * TOPIC = "topic"; - static const char * HOST = "host"; - static const char * OS = "os"; - static const char * HOSTNAME = "hostname"; - static const char * PROCESSORS = "processors"; - static const char * REASON = "reason"; - static const char * RELOAD = "reload"; - static const char * SUBSYSTEMS = "subsystems"; - static const char * FILEUUID = "uuid"; - static const char * USERID = "userId"; - static const char * PASSWORD = "password"; - static const char * TOKEN = "token"; - static const char * SETLOGLEVEL = "setloglevel"; - static const char * GETLOGLEVELS = "getloglevels"; - static const char * GETSUBSYSTEMNAMES = "getsubsystemnames"; - static const char * GETLOGLEVELNAMES = "getloglevelnames"; - static const char * STATS = "stats"; - static const char * PARAMETERS = "parameters"; - static const char * VALUE = "value"; - static const char * LASTONLY = "lastOnly"; - static const char * NEWEST = "newest"; - static const char * ACTIVESCAN = "activeScan"; - static const char * LIST = "list"; - static const char * TAG = "tag"; - static const char * TAGLIST = "tagList"; - static const char * DESCRIPTION = "description"; - static const char * NOTES = "notes"; - static const char * DEVICETYPE = "deviceType"; - static const char * REVISION = "revision"; - static const char * AGES = "ages"; - static const char * REVISIONS = "revisions"; - static const char * DEVICETYPES = "deviceTypes"; - static const char * LATESTONLY = "latestOnly"; - static const char * IDONLY = "idOnly"; - static const char * REVISIONSET = "revisionSet"; - static const char * DEVICESET = "deviceSet"; - static const char * HISTORY = "history"; - static const char * ID = "id"; - static const char * VERSION = "version"; - static const char * TIMES = "times"; - static const char * UPTIME = "uptime"; - static const char * START = "start"; - - static const char * NEWPASSWORD = "newPassword"; - static const char * USERS = "users"; - static const char * WITHEXTENDEDINFO = "withExtendedInfo"; - - static const char * ERRORTEXT = "errorText"; - static const char * ERRORCODE = "errorCode"; - static const char * AVATARID = "avatarId"; - static const char * UNNAMED = "(unnamed)"; - static const char * UNSPECIFIED = "(unspecified)"; - static const char * CONTENTDISPOSITION = "Content-Disposition"; - static const char * CONTENTTYPE = "Content-Type"; - - static const char * REQUIREMENTS = "requirements"; - static const char * PASSWORDPATTERN = "passwordPattern"; - static const char * ACCESSPOLICY = "accessPolicy"; - static const char * PASSWORDPOLICY = "passwordPolicy"; - static const char * FORGOTPASSWORD = "forgotPassword"; - static const char * RESENDMFACODE = "resendMFACode"; - static const char * COMPLETEMFACHALLENGE = "completeMFAChallenge"; - static const char * ME = "me"; - static const char * TELEMETRY = "telemetry"; - static const char * INTERVAL = "interval"; - static const char * UI = "UI"; - -} diff --git a/microservice_sample/src/framework/StorageClass.h b/microservice_sample/src/framework/StorageClass.h index 95dba62..34ecc2f 100644 --- a/microservice_sample/src/framework/StorageClass.h +++ b/microservice_sample/src/framework/StorageClass.h @@ -33,8 +33,8 @@ namespace OpenWifi { int Start() override { std::lock_guard Guard(Mutex_); - Logger_.setLevel(Poco::Message::PRIO_NOTICE); - Logger_.notice("Starting."); + Logger().setLevel(Poco::Message::PRIO_INFORMATION); + Logger().notice("Starting."); std::string DBType = MicroService::instance().ConfigGetString("storage.type"); if (DBType == "sqlite") { @@ -51,44 +51,14 @@ namespace OpenWifi { Pool_->shutdown(); } - [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { - if(dbType_==sqlite) { - return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " "; - } else if(dbType_==pgsql) { - return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; - } else if(dbType_==mysql) { - return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; - } - return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; - } - - inline std::string ConvertParams(const std::string & S) const { - std::string R; - R.reserve(S.size()*2+1); - if(dbType_==pgsql) { - auto Idx=1; - for(auto const & i:S) - { - if(i=='?') { - R += '$'; - R.append(std::to_string(Idx++)); - } else { - R += i; - } - } - } else { - R = S; - } - return R; - } - + DBType Type() const { return dbType_; }; private: inline int Setup_SQLite(); inline int Setup_MySQL(); inline int Setup_PostgreSQL(); protected: - Poco::SharedPtr Pool_; + std::unique_ptr Pool_; Poco::Data::SQLite::Connector SQLiteConn_; Poco::Data::PostgreSQL::Connector PostgresConn_; Poco::Data::MySQL::Connector MySQLConn_; @@ -101,21 +71,25 @@ namespace OpenWifi { #else inline int StorageClass::Setup_SQLite() { - Logger_.notice("SQLite StorageClass enabled."); + Logger().notice("SQLite StorageClass enabled."); dbType_ = sqlite; auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db"); - auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); - auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60); - SQLiteConn_.registerConnector(); - Pool_ = Poco::SharedPtr(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 4, NumSessions, IdleTime)); + int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64); + int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60); + + Poco::Data::SQLite::Connector::registerConnector(); +// Pool_ = std::make_unique(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8, +// (int)NumSessions, (int)IdleTime)); + Pool_ = std::make_unique(SQLiteConn_.name(), DBName, 8, + (int)NumSessions, (int)IdleTime); return 0; } inline int StorageClass::Setup_MySQL() { - Logger_.notice("MySQL StorageClass enabled."); + Logger().notice("MySQL StorageClass enabled."); dbType_ = mysql; - auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64); - auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60); + int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64); + int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60); auto Host = MicroService::instance().ConfigGetString("storage.type.mysql.host"); auto Username = MicroService::instance().ConfigGetString("storage.type.mysql.username"); auto Password = MicroService::instance().ConfigGetString("storage.type.mysql.password"); @@ -130,17 +104,17 @@ namespace OpenWifi { ";port=" + Port + ";compress=true;auto-reconnect=true"; - MySQLConn_.registerConnector(); - Pool_ = Poco::SharedPtr(new Poco::Data::SessionPool(MySQLConn_.name(), ConnectionStr, 4, NumSessions, IdleTime)); + Poco::Data::MySQL::Connector::registerConnector(); + Pool_ = std::make_unique(MySQLConn_.name(), ConnectionStr, 8, NumSessions, IdleTime); return 0; } inline int StorageClass::Setup_PostgreSQL() { - Logger_.notice("PostgreSQL StorageClass enabled."); + Logger().notice("PostgreSQL StorageClass enabled."); dbType_ = pgsql; - auto NumSessions = MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64); - auto IdleTime = MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60); + int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64); + int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60); auto Host = MicroService::instance().ConfigGetString("storage.type.postgresql.host"); auto Username = MicroService::instance().ConfigGetString("storage.type.postgresql.username"); auto Password = MicroService::instance().ConfigGetString("storage.type.postgresql.password"); @@ -156,8 +130,8 @@ namespace OpenWifi { " port=" + Port + " connect_timeout=" + ConnectionTimeout; - PostgresConn_.registerConnector(); - Pool_ = Poco::SharedPtr(new Poco::Data::SessionPool(PostgresConn_.name(), ConnectionStr, 4, NumSessions, IdleTime)); + Poco::Data::PostgreSQL::Connector::registerConnector(); + Pool_ = std::make_unique(PostgresConn_.name(), ConnectionStr, 8, NumSessions, IdleTime); return 0; } diff --git a/microservice_sample/src/framework/WebSocketClientNotifications.h b/microservice_sample/src/framework/WebSocketClientNotifications.h new file mode 100644 index 0000000..a0c3a02 --- /dev/null +++ b/microservice_sample/src/framework/WebSocketClientNotifications.h @@ -0,0 +1,193 @@ +// +// Created by stephane bourque on 2022-05-05. +// + +#pragma once + +#include "framework/MicroService.h" + +namespace OpenWifi { + + struct WebNotificationSingleDevice { + std::string serialNumber; + inline void to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber); + } + + inline bool from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber); + return true; + } catch (...) { + + } + return false; + } + }; + + struct WebNotificationSingleDeviceConfigurationChange { + std::string serialNumber; + uint64_t oldUUID; + uint64_t newUUID; + + inline void to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber); + RESTAPI_utils::field_to_json(Obj,"oldUUID", oldUUID); + RESTAPI_utils::field_to_json(Obj,"newUUID", newUUID); + } + + inline bool from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber); + RESTAPI_utils::field_from_json(Obj,"oldUUID", oldUUID); + RESTAPI_utils::field_from_json(Obj,"newUUID", newUUID); + return true; + } catch (...) { + + } + return false; + } + }; + + struct WebNotificationSingleDeviceFirmwareChange { + std::string serialNumber; + std::string newFirmware; + inline void to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json(Obj,"serialNumber", serialNumber); + RESTAPI_utils::field_to_json(Obj,"newFirmware", newFirmware); + } + + inline bool from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json(Obj,"serialNumber", serialNumber); + RESTAPI_utils::field_from_json(Obj,"newFirmware", newFirmware); + return true; + } catch (...) { + + } + return false; + } + }; + + inline void WebSocketClientNotificationDeviceConfigurationChange(const std::string &SerialNumber, uint64_t oldUUID, uint64_t newUUID) { + WebSocketNotification N; + N.content.serialNumber = SerialNumber; + N.content.oldUUID = oldUUID; + N.content.newUUID = newUUID; + N.type = "device_configuration_upgrade"; + WebSocketClientServer()->SendNotification(N); + } + + inline void WebSocketClientNotificationDeviceFirmwareUpdated(const std::string &SerialNumber, const std::string &Firmware) { + WebSocketNotification N; + N.content.serialNumber = SerialNumber; + N.content.newFirmware = Firmware; + N.type = "device_firmware_upgrade"; + WebSocketClientServer()->SendNotification(N); + } + + inline void WebSocketClientNotificationDeviceConnected(const std::string &SerialNumber) { + WebSocketNotification N; + N.content.serialNumber = SerialNumber; + N.type = "device_connection"; + WebSocketClientServer()->SendNotification(N); + } + + inline void WebSocketClientNotificationDeviceDisconnected(const std::string & SerialNumber) { + WebSocketNotification N; + N.content.serialNumber = SerialNumber; + N.type = "device_disconnection"; + WebSocketClientServer()->SendNotification(N); + } + + struct WebSocketNotificationJobContent { + std::string title, + details, + jobId; + std::vector success, + error, + warning; + uint64_t timeStamp=OpenWifi::Now(); + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + inline void WebSocketNotificationJobContent::to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json(Obj,"title",title); + RESTAPI_utils::field_to_json(Obj,"jobId",jobId); + RESTAPI_utils::field_to_json(Obj,"success",success); + RESTAPI_utils::field_to_json(Obj,"error",error); + RESTAPI_utils::field_to_json(Obj,"warning",warning); + RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp); + RESTAPI_utils::field_to_json(Obj,"details",details); + } + + inline bool WebSocketNotificationJobContent::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json(Obj,"title",title); + RESTAPI_utils::field_from_json(Obj,"jobId",jobId); + RESTAPI_utils::field_from_json(Obj,"success",success); + RESTAPI_utils::field_from_json(Obj,"error",error); + RESTAPI_utils::field_from_json(Obj,"warning",warning); + RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp); + RESTAPI_utils::field_from_json(Obj,"details",details); + return true; + } catch(...) { + + } + return false; + } + + typedef WebSocketNotification WebSocketClientNotificationVenueUpdateJob_t; + + inline void WebSocketClientNotificationVenueUpdateJobCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpdateJob_t &N) { + N.type = "venue_configuration_update"; + WebSocketClientServer()->SendUserNotification(User,N); + } + + struct WebSocketNotificationRebootList { + std::string title, + details, + jobId; + std::vector success, + warning; + uint64_t timeStamp=OpenWifi::Now(); + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + typedef WebSocketNotification WebSocketClientNotificationVenueRebootList_t; + + inline void WebSocketNotificationRebootList::to_json(Poco::JSON::Object &Obj) const { + RESTAPI_utils::field_to_json(Obj,"title",title); + RESTAPI_utils::field_to_json(Obj,"jobId",jobId); + RESTAPI_utils::field_to_json(Obj,"success",success); + RESTAPI_utils::field_to_json(Obj,"warning",warning); + RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp); + RESTAPI_utils::field_to_json(Obj,"details",details); + } + + inline bool WebSocketNotificationRebootList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + RESTAPI_utils::field_from_json(Obj,"title",title); + RESTAPI_utils::field_from_json(Obj,"jobId",jobId); + RESTAPI_utils::field_from_json(Obj,"success",success); + RESTAPI_utils::field_from_json(Obj,"warning",warning); + RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp); + RESTAPI_utils::field_from_json(Obj,"details",details); + return true; + } catch(...) { + + } + return false; + } + + inline void WebSocketClientNotificationVenueRebootCompletionToUser( const std::string & User, WebSocketClientNotificationVenueRebootList_t &N) { + N.type = "venue_rebooter"; + WebSocketClientServer()->SendUserNotification(User,N); + } + +} // namespace OpenWifi + diff --git a/microservice_sample/src/framework/orm.h b/microservice_sample/src/framework/orm.h index f2d1ddb..4fc8a15 100644 --- a/microservice_sample/src/framework/orm.h +++ b/microservice_sample/src/framework/orm.h @@ -32,7 +32,9 @@ namespace ORM { FT_BIGINT, FT_TEXT, FT_VARCHAR, - FT_BLOB + FT_BLOB, + FT_BOOLEAN, + FT_REAL }; enum Indextype { @@ -80,14 +82,14 @@ namespace ORM { typedef std::vector FieldVec; struct IndexEntry { - std::string FieldName; - Indextype Type; + std::string FieldName; + Indextype Type; }; typedef std::vector IndexEntryVec; struct Index { std::string Name; - IndexEntryVec Entries; + IndexEntryVec Entries; }; typedef std::vector IndexVec; @@ -96,21 +98,24 @@ namespace ORM { case FT_INT: return "INT"; case FT_BIGINT: return "BIGINT"; case FT_TEXT: return "TEXT"; + case FT_BOOLEAN: return "BOOLEAN"; case FT_VARCHAR: if(Size) return std::string("VARCHAR(") + std::to_string(Size) + std::string(")"); else return "TEXT"; - case FT_BLOB: - if(Type==OpenWifi::DBType::mysql) - return "LONGBLOB"; - else if(Type==OpenWifi::DBType::pgsql) - return "BYTEA"; - else if(Type==OpenWifi::DBType::sqlite) - return "BLOB"; - default: - assert(false); - return ""; + case FT_BLOB: + if(Type==OpenWifi::DBType::mysql) + return "LONGBLOB"; + else if(Type==OpenWifi::DBType::pgsql) + return "BYTEA"; + else + return "BLOB"; + case FT_REAL: + return "REAL"; + default: + assert(false); + } assert(false); return ""; @@ -119,12 +124,44 @@ namespace ORM { inline std::string Escape(const std::string &S) { std::string R; - for(const auto &i:S) - if(i=='\'') + for(const auto &i:S) { + if (i == '\'') R += "''"; else R += i; - return R; + } + return R; + } + + inline std::string WHERE_AND_(std::string Result) { + return Result; + } + + template std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) { + if constexpr(std::is_same_v) + { + if(!Value.empty()) { + if(!Result.empty()) + Result += " and "; + Result += fieldName; + Result += '='; + Result += "'"; + Result += Escape(Value); + Result += "'"; + } + } else { + if(!Result.empty()) + Result += " and "; + Result += fieldName ; + Result += '='; + Result += std::to_string(Value); + } + return WHERE_AND_(Result,args...); + } + + template std::string WHERE_AND(Args... args) { + std::string Result; + return WHERE_AND_(Result, args...); } enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE }; @@ -149,33 +186,61 @@ namespace ORM { return S; } + inline std::string to_string(const Poco::Data::BLOB &blob) { + std::string result; + result.assign(blob.begin(),blob.end()); + return result; + } + inline std::string to_string(const char * S) { return S; } + template class DBCache { + public: + DBCache(unsigned Size, unsigned Timeout) : + Size_(Size), + Timeout_(Timeout) + { + + } + virtual void Create(const RecordType &R)=0; + virtual bool GetFromCache(const std::string &FieldName, const std::string &Value, RecordType &R)=0; + virtual void UpdateCache(const RecordType &R)=0; + virtual void Delete(const std::string &FieldName, const std::string &Value)=0; + private: + size_t Size_=0; + uint64_t Timeout_=0; + }; + template class DB { public: + + typedef const char * field_name_t; + DB( OpenWifi::DBType dbtype, const char *TableName, const FieldVec & Fields, const IndexVec & Indexes, Poco::Data::SessionPool & Pool, - Poco::Logger &L, - const char *Prefix): - Type(dbtype), - DBName(TableName), + Poco::Logger &L, + const char *Prefix, + DBCache * Cache=nullptr): + TableName_(TableName), + Type_(dbtype), Pool_(Pool), Logger_(L), - Prefix_(Prefix) + Prefix_(Prefix), + Cache_(Cache) { + assert(RecordTuple::length == Fields.size()); + bool first = true; int Place=0; - assert( RecordTuple::length == Fields.size()); - for(const auto &i:Fields) { - - FieldNames_[i.Name] = Place; + std::string FieldName = Poco::toLower(i.Name); + FieldNames_[FieldName] = Place; if(!first) { CreateFields_ += ", "; SelectFields_ += ", "; @@ -185,9 +250,9 @@ namespace ORM { SelectList_ += "("; } - CreateFields_ += i.Name + " " + FieldTypeToChar(Type, i.Type,i.Size) + (i.Index ? " unique primary key" : ""); - SelectFields_ += i.Name ; - UpdateFields_ += i.Name + "=?"; + CreateFields_ += FieldName + " " + FieldTypeToChar(Type_, i.Type,i.Size) + (i.Index ? " unique primary key" : ""); + SelectFields_ += FieldName ; + UpdateFields_ += FieldName + "=?"; SelectList_ += "?"; first = false; Place++; @@ -195,24 +260,25 @@ namespace ORM { SelectList_ += ")"; if(!Indexes.empty()) { - if(Type==OpenWifi::DBType::sqlite || Type==OpenWifi::DBType::pgsql) { + if(Type_==OpenWifi::DBType::sqlite || Type_==OpenWifi::DBType::pgsql) { for(const auto &j:Indexes) { std::string IndexLine; - IndexLine = std::string("CREATE INDEX IF NOT EXISTS ") + j.Name + std::string(" ON ") + DBName + " ("; + IndexLine = std::string("CREATE INDEX IF NOT EXISTS ") + j.Name + std::string(" ON ") + TableName_+ " ("; bool first_entry=true; for(const auto &k:j.Entries) { - assert(FieldNames_.find(k.FieldName) != FieldNames_.end()); + auto IndexFieldName = Poco::toLower(k.FieldName); + assert(ValidFieldName(IndexFieldName)); if(!first_entry) { IndexLine += " , "; } first_entry = false; - IndexLine += k.FieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ; + IndexLine += IndexFieldName + std::string(" ") + std::string(k.Type == Indextype::ASC ? "ASC" : "DESC") ; } - IndexLine += " );"; - IndexCreation += IndexLine; + IndexLine += " )"; + IndexCreation_.template emplace_back(IndexLine); } - } else if(Type==OpenWifi::DBType::mysql) { + } else if(Type_==OpenWifi::DBType::mysql) { bool firstIndex = true; std::string IndexLine; for(const auto &j:Indexes) { @@ -222,16 +288,17 @@ namespace ORM { IndexLine += " INDEX " + j.Name + " ( " ; bool first_entry=true; for(const auto &k:j.Entries) { - assert(FieldNames_.find(k.FieldName) != FieldNames_.end()); + auto IndexFieldName = Poco::toLower(k.FieldName); + assert(FieldNames_.find(IndexFieldName) != FieldNames_.end()); if(!first_entry) { IndexLine += " ,"; } first_entry = false; - IndexLine += k.FieldName + std::string(k.Type == Indextype::ASC ? " ASC" : " DESC"); + IndexLine += IndexFieldName + std::string(k.Type == Indextype::ASC ? " ASC" : " DESC"); } IndexLine += " ) "; } - IndexCreation = IndexLine; + IndexCreation_.template emplace_back(IndexLine); } } } @@ -241,23 +308,28 @@ namespace ORM { [[nodiscard]] const std::string & SelectList() const { return SelectList_; }; [[nodiscard]] const std::string & UpdateFields() const { return UpdateFields_; }; - inline std::string OP(const char *F, SqlComparison O , int V) { - assert( FieldNames_.find(F) != FieldNames_.end() ); + inline std::string OP(field_name_t F, SqlComparison O , bool V) { + assert(ValidFieldName(F)); + return std::string{"("} + F + SQLCOMPS[O] + (V ? "true" : "false") + ")" ; + } + + inline std::string OP(field_name_t F, SqlComparison O , int V) { + assert(ValidFieldName(F)); return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ; } - inline std::string OP(const char *F, SqlComparison O , uint64_t V) { - assert( FieldNames_.find(F) != FieldNames_.end() ); + inline std::string OP(field_name_t F, SqlComparison O , uint64_t V) { + assert(ValidFieldName(F)); return std::string{"("} + F + SQLCOMPS[O] + std::to_string(V) + ")" ; } - std::string OP(const char *F, SqlComparison O , const std::string & V) { - assert( FieldNames_.find(F) != FieldNames_.end() ); + std::string OP(field_name_t F, SqlComparison O , const std::string & V) { + assert(ValidFieldName(F)); return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ; } - std::string OP(const char *F, SqlComparison O , const char * V) { - assert( FieldNames_.find(F) != FieldNames_.end() ); + std::string OP(field_name_t F, SqlComparison O , const char * V) { + assert(ValidFieldName(F)); return std::string{"("} + F + SQLCOMPS[O] + "'" + Escape(V) + "')" ; } @@ -265,7 +337,7 @@ namespace ORM { return std::string("(")+P1 + BOPS[BOP] + P2 +")"; } - std::string OP( bool Paran, const std::string &P1, SqlBinaryOp BOP , const std::string &P2) { + std::string OP( [[maybe_unused]] bool Paran, const std::string &P1, SqlBinaryOp BOP , const std::string &P2) { return P1 + BOPS[BOP] + P2 +")"; } @@ -277,35 +349,61 @@ namespace ORM { return std::string{"("} + P1 + BOPS[BOP] + OP(true, P2, More...); } + bool Upgrade() { + uint32_t To; + return Upgrade(0, To); + } + inline bool Create() { - std::string S; + switch(Type_) { + case OpenWifi::DBType::mysql: { + try { + Poco::Data::Session Session = Pool_.get(); + std::string Statement = IndexCreation_.empty() ? "create table if not exists " + TableName_ +" ( " + CreateFields_ + " )" : + "create table if not exists " + TableName_ +" ( " + CreateFields_ + " ), " + IndexCreation_[0] + " )"; + Session << Statement , Poco::Data::Keywords::now; + } catch (const Poco::Exception &E) { + Logger_.error("Failure to create MySQL DB resources."); + Logger_.log(E); + } + } + break; - if(Type==OpenWifi::DBType::mysql) { - if(IndexCreation.empty()) - S = "create table if not exists " + DBName +" ( " + CreateFields_ + " )" ; - else - S = "create table if not exists " + DBName +" ( " + CreateFields_ + " ), " + IndexCreation + " )"; - } else if (Type==OpenWifi::DBType::pgsql || Type==OpenWifi::DBType::sqlite) { - S = "create table if not exists " + DBName + " ( " + CreateFields_ + " ); " + IndexCreation ; + case OpenWifi::DBType::sqlite: { + try { + Poco::Data::Session Session = Pool_.get(); + std::string Statement = "create table if not exists " + TableName_ + " ( " + CreateFields_ + " )"; + Session << Statement , Poco::Data::Keywords::now; + for(const auto &i:IndexCreation_) { + Session << i , Poco::Data::Keywords::now; + } + } catch (const Poco::Exception &E) { + Logger_.error("Failure to create SQLITE DB resources."); + Logger_.log(E); + } + } + break; + + case OpenWifi::DBType::pgsql: { + try { + Poco::Data::Session Session = Pool_.get(); + std::string Statement = "create table if not exists " + TableName_ + " ( " + CreateFields_ + " )"; + Session << Statement , Poco::Data::Keywords::now; + for(const auto &i:IndexCreation_) { + Session << i , Poco::Data::Keywords::now; + } + } catch (const Poco::Exception &E) { + Logger_.error("Failure to create POSTGRESQL DB resources."); + Logger_.log(E); + } + } + break; } - - // std::cout << "CREATE-DB: " << S << std::endl; - - try { - Poco::Data::Session Session = Pool_.get(); - Poco::Data::Statement CreateStatement(Session); - - CreateStatement << S; - CreateStatement.execute(); - return true; - } catch (const Poco::Exception &E) { - std::cout << "Exception while creating DB: " << E.name() << std::endl; - } - return false; + return Upgrade(); } [[nodiscard]] std::string ConvertParams(const std::string & S) const { - if(Type!=OpenWifi::DBType::pgsql) + if(Type_!=OpenWifi::DBType::pgsql) return S; std::string R; @@ -324,48 +422,61 @@ namespace ORM { return R; } - void Convert( RecordTuple &in , RecordType &out); - void Convert( RecordType &in , RecordTuple &out); + void Convert( const RecordTuple &in , RecordType &out); + void Convert( const RecordType &in , RecordTuple &out); inline const std::string & Prefix() { return Prefix_; }; - bool CreateRecord( RecordType & R) { + bool CreateRecord( const RecordType & R) { try { Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Insert(Session); RecordTuple RT; Convert(R, RT); - std::string St = "insert into " + DBName + " ( " + SelectFields_ + " ) values " + SelectList_; + std::string St = "insert into " + TableName_ + " ( " + SelectFields_ + " ) values " + SelectList_; Insert << ConvertParams(St) , Poco::Data::Keywords::use(RT); Insert.execute(); + + if(Cache_) + Cache_->Create(R); return true; + } catch (const Poco::Exception &E) { Logger_.log(E); } return false; } - template bool GetRecord( const char * FieldName, T Value, RecordType & R) { + template bool GetRecord(field_name_t FieldName, const T & Value, RecordType & R) { try { + assert(ValidFieldName(FieldName)); - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + if(Cache_) { + if(Cache_->GetFromCache(FieldName, Value, R)) + return true; + } Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Select(Session); RecordTuple RT; - std::string St = "select " + SelectFields_ + " from " + DBName + " where " + FieldName + "=?" ; + std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName + "=?" + " limit 1"; + + auto tValue{Value}; Select << ConvertParams(St) , Poco::Data::Keywords::into(RT), - Poco::Data::Keywords::use(Value); + Poco::Data::Keywords::use(tValue); + Select.execute(); + if(Select.execute()==1) { Convert(RT,R); + if(Cache_) + Cache_->UpdateCache(R); return true; } - return false; } catch (const Poco::Exception &E) { Logger_.log(E); } @@ -375,16 +486,16 @@ namespace ORM { typedef std::vector StringVec; template < typename T, - typename T0, typename T1> bool GR(const char *FieldName, T & R,T0 &V0, T1 &V1) { + typename T0, typename T1> bool GR(field_name_t FieldName, T & R,T0 &V0, T1 &V1) { try { - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + assert( ValidFieldName(FieldName) ); Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Select(Session); RecordTuple RT; - std::string St = "select " + SelectFields_ + " from " + DBName + std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName[0] + "=? and " + FieldName[1] + "=?" ; Select << ConvertParams(St) , Poco::Data::Keywords::into(RT), @@ -402,21 +513,24 @@ namespace ORM { return false; } - typedef std::vector RecordList; + typedef std::vector RecordList; + typedef std::vector RecordVec; + typedef RecordType RecordName; - bool GetRecords( uint64_t Offset, uint64_t HowMany, std::vector & Records, const std::string & Where = "", const std::string & OrderBy = "") { + bool GetRecords( uint64_t Offset, uint64_t HowMany, RecordVec & Records, const std::string & Where = "", const std::string & OrderBy = "") { try { Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Select(Session); RecordList RL; - std::string St = "select " + SelectFields_ + " from " + DBName + + std::string St = "select " + SelectFields_ + " from " + TableName_ + (Where.empty() ? "" : " where " + Where) + OrderBy + ComputeRange(Offset, HowMany) ; Select << St , Poco::Data::Keywords::into(RL); + Select.execute(); - if(Select.execute()>0) { + if(Select.rowsExtracted()>0) { for(auto &i:RL) { RecordType R; Convert(i, R); @@ -431,9 +545,9 @@ namespace ORM { return false; } - template bool UpdateRecord( const char *FieldName, T & Value, RecordType & R) { + template bool UpdateRecord(field_name_t FieldName, const T & Value, const RecordType & R) { try { - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + assert( ValidFieldName(FieldName) ); Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Update(Session); @@ -442,11 +556,15 @@ namespace ORM { Convert(R, RT); - std::string St = "update " + DBName + " set " + UpdateFields_ + " where " + FieldName + "=?" ; + auto tValue(Value); + + std::string St = "update " + TableName_ + " set " + UpdateFields_ + " where " + FieldName + "=?" ; Update << ConvertParams(St) , Poco::Data::Keywords::use(RT), - Poco::Data::Keywords::use(Value); + Poco::Data::Keywords::use(tValue); Update.execute(); + if(Cache_) + Cache_->UpdateCache(R); return true; } catch (const Poco::Exception &E) { Logger_.log(E); @@ -454,18 +572,47 @@ namespace ORM { return false; } - template bool GetNameAndDescription(const char *FieldName, T & Value, std::string & Name, std::string & Description ) { + bool RunStatement(const std::string &St) { try { - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + Poco::Data::Session Session = Pool_.get(); + Poco::Data::Statement Command(Session); + + Command << St ; + Command.execute(); + + return true; + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + return false; + } + + template bool ReplaceRecord(field_name_t FieldName, const T & Value, RecordType & R) { + try { + if(Exists(FieldName, Value)) { + return UpdateRecord(FieldName,Value,R); + } + return CreateRecord(R); + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + return false; + } + + template bool GetNameAndDescription(field_name_t FieldName, const T & Value, std::string & Name, std::string & Description ) { + try { + assert( ValidFieldName(FieldName) ); Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Select(Session); RecordTuple RT; - std::string St = "select " + SelectFields_ + " from " + DBName + " where " + FieldName + "=?" ; + std::string St = "select " + SelectFields_ + " from " + TableName_ + " where " + FieldName + "=?" ; RecordType R; + auto tValue{Value}; Select << ConvertParams(St) , - Poco::Data::Keywords::into(RT), - Poco::Data::Keywords::use(Value); + Poco::Data::Keywords::into(RT), + Poco::Data::Keywords::use(tValue); + if(Select.execute()==1) { Convert(RT,R); Name = R.info.name; @@ -479,17 +626,21 @@ namespace ORM { return false; } - template bool DeleteRecord( const char *FieldName, T Value) { + template bool DeleteRecord(field_name_t FieldName, const T & Value) { try { - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + assert( ValidFieldName(FieldName) ); Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Delete(Session); - std::string St = "delete from " + DBName + " where " + FieldName + "=?" ; + std::string St = "delete from " + TableName_ + " where " + FieldName + "=?" ; + auto tValue{Value}; + Delete << ConvertParams(St) , - Poco::Data::Keywords::use(Value); + Poco::Data::Keywords::use(tValue); Delete.execute(); + if(Cache_) + Cache_->Delete(FieldName, Value); return true; } catch (const Poco::Exception &E) { Logger_.log(E); @@ -503,7 +654,7 @@ namespace ORM { Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Delete(Session); - std::string St = "delete from " + DBName + " where " + WhereClause; + std::string St = "delete from " + TableName_ + " where " + WhereClause; Delete << St; Delete.execute(); return true; @@ -513,9 +664,9 @@ namespace ORM { return false; } - bool Exists(const char *FieldName, std::string & Value) { + bool Exists(field_name_t FieldName, const std::string & Value) { try { - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + assert( ValidFieldName(FieldName) ); RecordType R; if(GetRecord(FieldName,Value,R)) @@ -527,15 +678,15 @@ namespace ORM { return false; } - bool Iterate( std::function F) { + bool Iterate( std::function F, const std::string & WhereClause = "" ) { try { - uint64_t Offset=1; + uint64_t Offset=0; uint64_t Batch=50; bool Done=false; while(!Done) { std::vector Records; - if(GetRecords(Offset,Batch,Records)) { + if(GetRecords(Offset,Batch,Records, WhereClause)) { for(const auto &i:Records) { if(!F(i)) return true; @@ -568,7 +719,7 @@ namespace ORM { } if(!ItemList.empty()) ItemList += " , "; - auto hint = FieldNames_.find(T[0]); + auto hint = FieldNames_.find(Poco::toLower(T[0])); if(hint==FieldNames_.end()) { return false; } @@ -578,9 +729,6 @@ namespace ORM { if(!ItemList.empty()) { OrderByString = " ORDER BY " + ItemList; } - - std::cout << OrderByString << std::endl; - return true; } @@ -591,7 +739,7 @@ namespace ORM { Poco::Data::Session Session = Pool_.get(); Poco::Data::Statement Select(Session); - std::string st{"SELECT COUNT(*) FROM " + DBName + " " + (Where.empty() ? "" : (" where " + Where)) }; + std::string st{"SELECT COUNT(*) FROM " + TableName_ + " " + (Where.empty() ? "" : (" where " + Where)) }; Select << st , Poco::Data::Keywords::into(Cnt); @@ -605,9 +753,9 @@ namespace ORM { return 0; } - template bool ManipulateVectorMember( X T, const char *FieldName, std::string & ParentUUID, std::string & ChildUUID, bool Add) { + template bool ManipulateVectorMember( X T, field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID, bool Add) { try { - assert( FieldNames_.find(FieldName) != FieldNames_.end() ); + assert( ValidFieldName(FieldName) ); RecordType R; if(GetRecord(FieldName, ParentUUID, R)) { @@ -632,89 +780,122 @@ namespace ORM { return false; } - inline bool AddChild( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + bool RunScript(const std::vector & Statements, bool IgnoreExceptions=true) { + try { + Poco::Data::Session Session = Pool_.get(); + Poco::Data::Statement Command(Session); + + for(const auto &i:Statements) { + try { + Command << i, Poco::Data::Keywords::now; + } catch (const Poco::Exception &E) { + // Logger_.log(E); + // Logger_.error(Poco::format("The following statement '%s' generated an exception during a table upgrade. This may or may not be a problem.", i)); + if(!IgnoreExceptions) { + return false; + } + } + Command.reset(Session); + } + return true; + } catch (const Poco::Exception &E) { + Logger_.log(E); + } + return false; + } + + virtual uint32_t Version() { + return 0; + } + + virtual bool Upgrade(uint32_t from, uint32_t &to) { + to = from; + return true; + } + + inline bool AddChild(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::children, FieldName, ParentUUID, ChildUUID, true); } - inline bool DeleteChild( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DeleteChild(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::children, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddLocation( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool AddLocation(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::locations, FieldName, ParentUUID, ChildUUID, true); } - inline bool DeleteLocation( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DeleteLocation(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::locations, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddContact( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool AddContact(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::contacts, FieldName, ParentUUID, ChildUUID, true); } - inline bool DeleteContact( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DeleteContact(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::contacts, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddVenue( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool AddVenue(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::venues, FieldName, ParentUUID, ChildUUID, true); } - inline bool DeleteVenue( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DeleteVenue(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::venues, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddDevice( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool AddDevice(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::devices, FieldName, ParentUUID, ChildUUID, true); } - inline bool DeleteDevice( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DeleteDevice(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::devices, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddEntity( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool AddEntity(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::entities, FieldName, ParentUUID, ChildUUID, true); } - inline bool DeleteEntity( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DeleteEntity(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::entities, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddUser( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool AddUser(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, true); } - inline bool DelUser( const char *FieldName, std::string & ParentUUID, std::string & ChildUUID) { + inline bool DelUser(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { return ManipulateVectorMember(&RecordType::users, FieldName, ParentUUID, ChildUUID, false); } - inline bool AddInUse(const char *FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { + inline bool AddConfiguration(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { + return ManipulateVectorMember(&RecordType::deviceConfiguration, FieldName, ParentUUID, ChildUUID, true); + } + + inline bool DelConfiguration(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { + return ManipulateVectorMember(&RecordType::deviceConfiguration, FieldName, ParentUUID, ChildUUID, false); + } + + inline bool AddVariable(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { + return ManipulateVectorMember(&RecordType::variables, FieldName, ParentUUID, ChildUUID, true); + } + + inline bool DelVariable(field_name_t FieldName, const std::string & ParentUUID, const std::string & ChildUUID) { + return ManipulateVectorMember(&RecordType::variables, FieldName, ParentUUID, ChildUUID, false); + } + + inline bool AddInUse(field_name_t FieldName, const std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { std::string FakeUUID{ Prefix + ":" + ChildUUID}; return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, true); } - inline bool DeleteInUse(const char *FieldName, std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { + inline bool DeleteInUse(field_name_t FieldName, const std::string & ParentUUID, const std::string & Prefix, const std::string & ChildUUID) { std::string FakeUUID{ Prefix + ":" + ChildUUID}; return ManipulateVectorMember(&RecordType::inUse,FieldName, ParentUUID, FakeUUID, false); } - inline bool DeleteContact(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { - return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, false); - } - - inline bool AddContact(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { - return ManipulateVectorMember(&RecordType::contacts,FieldName, ParentUUID, ChildUUID, true); - } - - inline bool DeleteLocation(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { - return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, false); - } - - inline bool AddLocation(const char *FieldName, std::string & ParentUUID, const std::string & ChildUUID) { - return ManipulateVectorMember(&RecordType::locations,FieldName, ParentUUID, ChildUUID, true); - } - - inline bool GetInUse(const char *FieldName, std::string & UUID, std::vector & UUIDs ) { + inline bool GetInUse(field_name_t FieldName, const std::string & UUID, std::vector & UUIDs ) { RecordType R; if(GetRecord(FieldName,UUID,R)) { UUIDs = R.inUse; @@ -723,34 +904,56 @@ namespace ORM { return false; } + inline bool ValidFieldName(const std::string &FieldName) { + return FieldNames_.find(Poco::toLower(FieldName)) != FieldNames_.end(); + } + + inline bool ValidFieldName(const char *FieldName) { + std::string Field{FieldName}; + return ValidFieldName(Field); + } + [[nodiscard]] inline std::string ComputeRange(uint64_t From, uint64_t HowMany) { - if(From<1) From=1; - switch(Type) { + if(From<1) From=0; + switch(Type_) { case OpenWifi::DBType::sqlite: - return " LIMIT " + std::to_string(From-1) + ", " + std::to_string(HowMany) + " "; + return " LIMIT " + std::to_string(From) + ", " + std::to_string(HowMany) + " "; case OpenWifi::DBType::pgsql: - return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; + return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; case OpenWifi::DBType::mysql: - return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; + return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; default: - return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From-1) + " "; + return " LIMIT " + std::to_string(HowMany) + " OFFSET " + std::to_string(From) + " "; } } Poco::Logger & Logger() { return Logger_; } + inline bool DeleteRecordsFromCache(const char *FieldName, const std::string &Value ) { + if(Cache_) + Cache_->Delete(FieldName, Value); + return true; + } + + inline void GetFieldNames( OpenWifi::Types::StringVec & F) { + for(const auto &[field,_]:FieldNames_) + F.push_back(field); + } + + protected: + std::string TableName_; + OpenWifi::DBType Type_; + Poco::Data::SessionPool &Pool_; + Poco::Logger &Logger_; + std::string Prefix_; + DBCache *Cache_= nullptr; private: - OpenWifi::DBType Type; - std::string DBName; std::string CreateFields_; std::string SelectFields_; std::string SelectList_; std::string UpdateFields_; - std::string IndexCreation; + std::vector IndexCreation_; std::map FieldNames_; - Poco::Data::SessionPool &Pool_; - Poco::Logger &Logger_; - std::string Prefix_; }; } diff --git a/microservice_sample/src/framework/ow_constants.h b/microservice_sample/src/framework/ow_constants.h new file mode 100644 index 0000000..7a0e739 --- /dev/null +++ b/microservice_sample/src/framework/ow_constants.h @@ -0,0 +1,515 @@ +// +// Created by stephane bourque on 2022-02-21. +// + +#pragma once + +#include +#include +#include "Poco/String.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" +#endif + +namespace OpenWifi::RESTAPI::Errors { + struct msg { uint64_t err_num; std::string err_txt; }; + static const struct msg Error404{404,"Resource does not exist."}; + + static const struct msg SUCCESS{0,"No error."}; + static const struct msg PASSWORD_CHANGE_REQUIRED{1,"Password change required"}; + static const struct msg INVALID_CREDENTIALS{2,"Invalid credentials."}; + static const struct msg PASSWORD_ALREADY_USED{3,"Password already used."}; + static const struct msg USERNAME_PENDING_VERIFICATION{4,"Username pending verification."}; + static const struct msg PASSWORD_INVALID{5,"Password is invalid"}; + static const struct msg INTERNAL_ERROR{6,"Internal error."}; + static const struct msg ACCESS_DENIED{7,"Access denied."}; + static const struct msg INVALID_TOKEN{8,"Invalid token."}; + static const struct msg EXPIRED_TOKEN{9,"Expired token."}; + static const struct msg RATE_LIMIT_EXCEEDED{10,"Rate limit exceeded."}; + static const struct msg BAD_MFA_TRANSACTION{11,"Bad MFA transaction."}; + static const struct msg MFA_FAILURE{12,"MFA failure."}; + static const struct msg SECURITY_SERVICE_UNREACHABLE{13,"Security service is unreachable, try again later."}; + static const struct msg CANNOT_REFRESH_TOKEN{14,"Cannot refresh token."}; + + static const struct msg MissingUUID{1000,"Missing UUID."}; + static const struct msg MissingSerialNumber{1001,"Missing Serial Number."}; + static const struct msg InternalError{1002,"Internal error. Please try later."}; + static const struct msg InvalidJSONDocument{1003,"Invalid JSON document."}; + static const struct msg UnsupportedHTTPMethod{1004,"Unsupported HTTP Method"}; + static const struct msg StillInUse{1005,"Element still in use."}; + static const struct msg CouldNotBeDeleted{1006,"Element could not be deleted."}; + static const struct msg NameMustBeSet{1007,"The name property must be set."}; + static const struct msg ConfigBlockInvalid{1008,"Configuration block type invalid."}; + static const struct msg UnknownId{1009,"Unknown UUID."}; + static const struct msg InvalidDeviceTypes{1010,"Unknown or invalid device type(s)."}; + static const struct msg RecordNotCreated{1011,"Record could not be created."}; + static const struct msg RecordNotUpdated{1012,"Record could not be updated."}; + static const struct msg UnknownManagementPolicyUUID{1013,"Unknown management policy UUID."}; + static const struct msg CannotDeleteRoot{1014,"Root Entity cannot be removed, only modified."}; + static const struct msg MustCreateRootFirst{1015,"Root entity must be created first."}; + static const struct msg ParentUUIDMustExist{1016,"Parent UUID must exist."}; + static const struct msg ConfigurationMustExist{1017,"Configuration must exist."}; + static const struct msg MissingOrInvalidParameters{1018,"Invalid or missing parameters."}; + static const struct msg UnknownSerialNumber{1019,"Unknown Serial Number."}; + static const struct msg InvalidSerialNumber{1020,"Invalid Serial Number."}; + static const struct msg SerialNumberExists{1021,"Serial Number already exists."}; + static const struct msg ValidNonRootUUID{1022,"Must be a non-root, and valid UUID."}; + static const struct msg VenueMustExist{1023,"Venue does not exist."}; + static const struct msg NotBoth{1024,"You cannot specify both Entity and Venue"}; + static const struct msg EntityMustExist{1025,"Entity must exist."}; + static const struct msg ParentOrEntityMustBeSet{1026,"Parent or Entity must be set."}; + static const struct msg ContactMustExist{1027,"Contact must exist."}; + static const struct msg LocationMustExist{1028,"Location must exist."}; + static const struct msg OnlyWSSupported{1029,"This endpoint only supports WebSocket."}; + static const struct msg SerialNumberMismatch{1030,"Serial Number mismatch."}; + static const struct msg InvalidCommand{1031,"Invalid command."}; + static const struct msg NoRecordsDeleted{1032,"No records deleted."}; + static const struct msg DeviceNotConnected{1033,"Device is not currently connected."}; + static const struct msg CannotCreateWS{1034,"Telemetry system could not create WS endpoint. Please try again."}; + static const struct msg BothDeviceTypeRevision{1035,"Both deviceType and revision must be set."}; + static const struct msg IdOrSerialEmpty{1036,"SerialNumber and Id must not be empty."}; + static const struct msg MissingUserID{1037,"Missing user ID."}; + static const struct msg IdMustBe0{1038,"To create a user, you must set the ID to 0"}; + static const struct msg InvalidUserRole{1039,"Invalid userRole."}; + static const struct msg InvalidEmailAddress{1040,"Invalid email address."}; + static const struct msg PasswordRejected{1041,"Password was rejected. This maybe an old password."}; + static const struct msg InvalidIPRanges{1042,"Invalid IP range specifications."}; + static const struct msg InvalidLOrderBy{1043,"Invalid orderBy specification."}; + static const struct msg NeedMobileNumber{1044,"You must provide at least one validated phone number."}; + static const struct msg BadMFAMethod{1045,"MFA only supports sms or email."}; + static const struct msg InvalidCredentials{1046,"Invalid credentials (username/password)."}; + static const struct msg InvalidPassword{1047,"Password does not conform to basic password rules."}; + static const struct msg UserPendingVerification{1048,"User access denied pending email verification."}; + static const struct msg PasswordMustBeChanged{1049,"Password must be changed."}; + static const struct msg UnrecognizedRequest{1050,"Ill-formed request. Please consult documentation."}; + static const struct msg MissingAuthenticationInformation{1051,"Missing authentication information."}; + static const struct msg InsufficientAccessRights{1052,"Insufficient access rights to complete the operation."}; + static const struct msg ExpiredToken{1053,"Token has expired, user must login."}; + static const struct msg SubscriberMustExist{1054,"Subscriber must exist."}; + static const struct msg AuthenticatorVerificationIncomplete{1055,"Authenticator validation is not complete."}; + static const struct msg SMSCouldNotBeSentRetry{1056,"SMS could not be sent to validate device, try later or change the phone number."}; + static const struct msg SMSCouldNotValidate{1057,"Code and number could not be validated"}; + static const struct msg InvalidDeviceClass{1058,"Invalid device class. Must be: any, venue, entity, or subscriber"}; + static const struct msg SerialNumberAlreadyProvisioned{1059,"This device has already been provisioned to a subscriber."}; + static const struct msg SerialNumberNotTheProperClass{1060,"Device is not available to subscribers. It ahs been assigned to another class of devices."}; + static const struct msg UserAlreadyExists{1061,"Username already exists."}; + static const struct msg NotImplemented{1062,"Function not implemented."}; + static const struct msg VariableMustExist{1063,"Specified variable does not exist."}; + static const struct msg InvalidEntityType{1064,"Invalid entity type."}; + static const struct msg CannotDeleteSubEntity{1065,"Cannot delete the default subscriber entity."}; + static const struct msg OperatorIdMustExist{1066,"Missing or bad Operator ID"}; + static const struct msg CannotDeleteDefaultOperator{1067,"Cannot delete the default operator."}; + static const struct msg CannotCreateDefaultOperator{1068,"Cannot create the default operator."}; + static const struct msg InvalidRRM{1069,"Invalid RRM value."}; + static const struct msg InvalidIPAddresses{1070,"Invalid IP addresses."}; + static const struct msg InvalidBillingCode{1071,"Empty of invalid billing code."}; + static const struct msg InvalidBillingPeriod{1072,"Invalid billing period."}; + static const struct msg InvalidSubscriberId{1073,"Invalid subscriber ID."}; + static const struct msg InvalidContactId{1074,"Invalid contact ID."}; + static const struct msg InvalidLocationId{1075,"Invalid location ID."}; + static const struct msg InvalidContactType{1076,"Invalid contact type."}; + static const struct msg InvalidLocationType{1077,"Invalid location type."}; + static const struct msg InvalidOperatorId{1078,"Invalid operator ID."}; + static const struct msg InvalidServiceClassId{1079,"Invalid service class ID."}; + static const struct msg InvalidSubscriberDeviceId{1080,"Invalid subscriber device ID."}; + static const struct msg InvalidRegistrationOperatorId{1081,"Invalid registration operator ID."}; + static const struct msg InvalidRegistrationOperatorName{1082,"Invalid registration operator name."}; + static const struct msg RegistrationNameDuplicate{1083,"Registration name must be unique."}; + static const struct msg SMSMFANotEnabled{1084,"SMS is not enabled in the security service."}; + static const struct msg EMailMFANotEnabled{1085,"email is not enabled in the security service."}; + + static const struct msg TOTInvalidCode{1086,"Invalid code."}; + static const struct msg TOTInvalidIndex{1087,"Invalid index."}; + static const struct msg TOTRepeatedCode{1088,"Code is repeated. Must be new code."}; + static const struct msg TOTInvalidProtocol{1089,"Invalid protocol sequence."}; + static const struct msg TOTNoSession{1090,"No validation session present."}; + + static const struct msg SignupAlreadySigned{1091,"Code is repeated. Must be new code."}; + static const struct msg SignupEmailCheck{1092,"Waiting for email check completion."}; + static const struct msg SignupWaitingForDevice{1093,"Waiting for device."}; + + static const struct msg SMSMissingPhoneNumber{1094,"Missing phone number"}; + static const struct msg SMSTryLater{1095,"SMS could not be sent. Verify the number or try again later."}; + static const struct msg SMSMissingChallenge{1096,"Missing 'challengeCode'"}; + static const struct msg MustHaveConfigElement{1097,"Must have 'configuration' element."}; + + static const struct msg ModelIDListCannotBeEmpty{1098,"Model ID list cannot be empty."}; + static const struct msg DefConfigNameExists{1099,"Configuration name already exists."}; + + static const struct msg SubNoDeviceActivated{1100,"No devices activated yet."}; + static const struct msg SubConfigNotRefreshed{1101,"Configuration could not be refreshed."}; + + static const struct msg ProvServiceNotAvailable{1102,"Provisioning service not available yet."}; + static const struct msg SSIDInvalidPassword{1103,"Invalid password length. Must be 8 characters or greater, and a maximum of 32 characters."}; + static const struct msg InvalidStartingIPAddress{1104,"Invalid starting/ending IP address."}; + static const struct msg SubnetFormatError{1105,"Subnet must be in format like 192.168.1.1/24."}; + static const struct msg DeviceModeError{1106,"Device mode subnet must be of the form 192.168.1.1/24."}; + + static const struct msg BadDeviceMode{1107,"Mode must be bridge, nat, or manual."}; + static const struct msg DefaultGatewayFormat{1108,"Default gateway must be in format like 192.168.1.1."}; + static const struct msg PrimaryDNSFormat{1109,"Primary DNS must be an IP address i.e. 192.168.1.1."}; + + static const struct msg SecondaryDNSFormat{1110,"Secondary DNS must be an IP address i.e. 192.168.1.1."}; + static const struct msg BadConnectionType{1111,"Internet Connection must be automatic, bridge, pppoe, or manual."}; + static const struct msg InvalidDeviceID{1112,"Invalid deviceID."}; + static const struct msg InvalidVisibilityAttribute{1113,"Invalid visibility attribute."}; + static const struct msg UnknownConfigurationSection{1114,"Unknown section."}; + + static const struct msg CannotValidatePhoneNumber{1115,"Phone number could not be validated."}; + static const struct msg RootUsersNoOwners{1116,"ROOT users may not have owners."}; + static const struct msg PartnerMustHaveEntity{1118,"Partner user must belong to an entity."}; + static const struct msg RootCannotModifyUsers{1119,"ROOT may not modify user roles."}; + + static const struct msg CertificateNotIssued{1120,"Certificate was not issued."}; + static const struct msg IncompleteCertificate{1121,"Incomplete certificate information. Cannot be downloaded. You must delete and recreate."}; + static const struct msg InvalidCertificateType{1122,"Invalid certificate type."}; + static const struct msg InvalidDeviceName{1123,"Invalid device name."}; + + static const struct msg InvalidRedirectorName{1124,"Invalid redirector name"}; + static const struct msg CommonNameAlreadyExists{1125,"A device/server of this name already exists"}; + static const struct msg CertificateAlreadyExists{1126,"A certificate for this device already exists."}; + static const struct msg CannotCreateCertTryAgain{1127,"Device certificate could not be created. Please try later."}; + static const struct msg CouldNotRevoke{1128,"Certificate could not be revoked."}; + + static const struct msg CouldNotModifyCert{1129,"Certificate could not me modified. Please verify the information you supplied."}; + static const struct msg BatchCertNoCreated{1130,"Certificates have not been created for this batch."}; + static const struct msg BatchTooBig{1131,"Illegal number of MAC Addresses: must be between 1 and 1000."}; + + static const struct msg OutstandingJobs{1132,"Batch has running outstanding jobs. Please wait until job is finished."}; + static const struct msg InvalidSMSNotificationList{1133,"Invalid SMS Notification list."}; + static const struct msg InvalidEMailNotificationList{1134,"Invalid email Notification list."}; + static const struct msg CannotChangeCommanNames{1135,"You cannot provide new/modified common names after jobs have been run for a batch."}; + static const struct msg FailedToVerifyDigicert{1136,"Failed to verify the DigiCert information provided."}; + static const struct msg CouldNotPerformCommand{1137,"Could not perform command."}; + + static const struct msg PoolNameInvalid{1138,"Pool name is invalid."}; + static const struct msg InvalidRadiusProxyStrategy{1139,"Strategy name must be: random, round_robin, weighted."}; + static const struct msg InvalidRadiusProxyMonitorMethod{1140,"monitorMethod must be: none, https, radius."}; + static const struct msg MustHaveAtLeastOneRadiusServer{1141,"Must have at least one RADIUS server."}; + static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."}; + static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."}; + + static const struct msg MaximumRTTYSessionsReached{1144,"Too many RTTY sessions currently active"}; +} + + + +namespace OpenWifi::RESTAPI::Protocol { + static const char * CAPABILITIES = "capabilities"; + static const char * LOGS = "logs"; + static const char * HEALTHCHECKS = "healthchecks"; + static const char * STATISTICS = "statistics"; + static const char * STATUS = "status"; + static const char * SERIALNUMBER = "serialNumber"; + static const char * PERFORM = "perform"; + static const char * CONFIGURE = "configure"; + static const char * UPGRADE = "upgrade"; + static const char * REBOOT = "reboot"; + static const char * FACTORY = "factory"; + static const char * LEDS = "leds"; + static const char * TRACE = "trace"; + static const char * REQUEST = "request"; + static const char * WIFISCAN = "wifiscan"; + static const char * EVENTQUEUE = "eventqueue"; + static const char * RTTY = "rtty"; + static const char * COMMAND = "command"; + static const char * STARTDATE = "startDate"; + static const char * ENDDATE = "endDate"; + static const char * OFFSET = "offset"; + static const char * LIMIT = "limit"; + static const char * LIFETIME = "lifetime"; + static const char * UUID = "UUID"; + static const char * DATA = "data"; + static const char * CONFIGURATION = "configuration"; + static const char * WHEN = "when"; + static const char * URI = "uri"; + static const char * LOGTYPE = "logType"; + static const char * VALUES = "values"; + static const char * TYPES = "types"; + static const char * PAYLOAD = "payload"; + static const char * KEEPREDIRECTOR = "keepRedirector"; + static const char * NETWORK = "network"; + static const char * INTERFACE = "interface"; + static const char * BANDS = "bands"; + static const char * CHANNELS = "channels"; + static const char * VERBOSE = "verbose"; + static const char * MESSAGE = "message"; + static const char * STATE = "state"; + static const char * HEALTHCHECK = "healthcheck"; + static const char * PCAP_FILE_TYPE = "pcap"; + static const char * DURATION = "duration"; + static const char * NUMBEROFPACKETS = "numberOfPackets"; + static const char * FILTER = "filter"; + static const char * SELECT = "select"; + static const char * SERIALONLY = "serialOnly"; + static const char * COUNTONLY = "countOnly"; + static const char * DEVICEWITHSTATUS = "deviceWithStatus"; + static const char * DEVICESWITHSTATUS = "devicesWithStatus"; + static const char * DEVICES = "devices"; + static const char * COUNT = "count"; + static const char * SERIALNUMBERS = "serialNumbers"; + static const char * CONFIGURATIONS = "configurations"; + static const char * NAME = "name"; + static const char * COMMANDS = "commands"; + static const char * COMMANDUUID = "commandUUID"; + static const char * FIRMWARES = "firmwares"; + static const char * TOPIC = "topic"; + static const char * HOST = "host"; + static const char * OS = "os"; + static const char * HOSTNAME = "hostname"; + static const char * PROCESSORS = "processors"; + static const char * REASON = "reason"; + static const char * RELOAD = "reload"; + static const char * SUBSYSTEMS = "subsystems"; + static const char * FILEUUID = "uuid"; + static const char * USERID = "userId"; + static const char * PASSWORD = "password"; + static const char * TOKEN = "token"; + static const char * SETLOGLEVEL = "setloglevel"; + static const char * GETLOGLEVELS = "getloglevels"; + static const char * GETSUBSYSTEMNAMES = "getsubsystemnames"; + static const char * GETLOGLEVELNAMES = "getloglevelnames"; + static const char * STATS = "stats"; + static const char * PING = "ping"; + static const char * PARAMETERS = "parameters"; + static const char * VALUE = "value"; + static const char * LASTONLY = "lastOnly"; + static const char * NEWEST = "newest"; + static const char * ACTIVESCAN = "activeScan"; + static const char * OVERRIDEDFS = "override_dfs"; + static const char * LIST = "list"; + static const char * TAG = "tag"; + static const char * TAGLIST = "tagList"; + static const char * DESCRIPTION = "description"; + static const char * NOTES = "notes"; + static const char * DEVICETYPE = "deviceType"; + static const char * REVISION = "revision"; + static const char * AGES = "ages"; + static const char * REVISIONS = "revisions"; + static const char * DEVICETYPES = "deviceTypes"; + static const char * LATESTONLY = "latestOnly"; + static const char * IDONLY = "idOnly"; + static const char * REVISIONSET = "revisionSet"; + static const char * DEVICESET = "deviceSet"; + static const char * HISTORY = "history"; + static const char * ID = "id"; + static const char * VERSION = "version"; + static const char * TIMES = "times"; + static const char * UPTIME = "uptime"; + static const char * START = "start"; + static const char * DEBUG = "debug"; + static const char * SCRIPT = "script"; + static const char * TIMEOUT = "timeout"; + + static const char * NEWPASSWORD = "newPassword"; + static const char * USERS = "users"; + static const char * WITHEXTENDEDINFO = "withExtendedInfo"; + + static const char * ERRORTEXT = "errorText"; + static const char * ERRORCODE = "errorCode"; + static const char * AVATARID = "avatarId"; + static const char * UNNAMED = "(unnamed)"; + static const char * UNSPECIFIED = "(unspecified)"; + static const char * CONTENTDISPOSITION = "Content-Disposition"; + static const char * CONTENTTYPE = "Content-Type"; + + static const char * REQUIREMENTS = "requirements"; + static const char * PASSWORDPATTERN = "passwordPattern"; + static const char * ACCESSPOLICY = "accessPolicy"; + static const char * PASSWORDPOLICY = "passwordPolicy"; + static const char * FORGOTPASSWORD = "forgotPassword"; + static const char * RESENDMFACODE = "resendMFACode"; + static const char * COMPLETEMFACHALLENGE = "completeMFAChallenge"; + static const char * ME = "me"; + static const char * TELEMETRY = "telemetry"; + static const char * INTERVAL = "interval"; + static const char * UI = "UI"; + static const char * BANDWIDTH = "bandwidth"; +} + +namespace OpenWifi::uCentralProtocol { + + const int SERIAL_NUMBER_LENGTH = 30; + + // vocabulary used in the PROTOCOL.md file + static const char *JSONRPC = "jsonrpc"; + static const char *ID = "id"; + static const char *UUID = "uuid"; + static const char *JSONRPC_VERSION = "2.0"; + static const char *METHOD = "method"; + static const char *PARAMS = "params"; + static const char *SERIAL = "serial"; + static const char *FIRMWARE = "firmware"; + static const char *CONNECT = "connect"; + static const char *STATE = "state"; + static const char *STATUS = "status"; + static const char *ERROR = "error"; + static const char *TEXT = "text"; + static const char *HEALTHCHECK = "healthcheck"; + static const char *LOG = "log"; + static const char *CRASHLOG = "crashlog"; + static const char *PING = "ping"; + static const char *CFGPENDING = "cfgpending"; + static const char *RECOVERY = "recovery"; + static const char *COMPRESS_64 = "compress_64"; + static const char *CAPABILITIES = "capabilities"; + static const char *REQUEST_UUID = "request_uuid"; + static const char *SANITY = "sanity"; + static const char *DATA = "data"; + static const char *LOGLINES = "loglines"; + static const char *SEVERITY = "severity"; + static const char *ACTIVE = "active"; + static const char *OVERRIDEDFS = "override_dfs"; + static const char *REBOOT = "reboot"; + static const char *WHEN = "when"; + static const char *CONFIG = "config"; + static const char *EMPTY_JSON_DOC = "{}"; + static const char *RESULT = "result"; + static const char *RESULT_64 = "result_64"; + static const char *RESULT_SZ = "result_sz"; + static const char *REQUEST = "request"; + static const char *PERFORM = "perform"; + static const char *CONFIGURE = "configure"; + static const char *PENDING = "pending"; + static const char *SUBMITTED_BY_SYSTEM = "*system"; + static const char *URI = "uri"; + static const char *COMMAND = "command"; + static const char *PAYLOAD = "payload"; + static const char *KEEP_REDIRECTOR = "keep_redirector"; + static const char *DURATION = "duration"; + static const char *PATTERN = "pattern"; + static const char *LEDS = "leds"; + static const char *DEBUG = "debug"; + static const char *ON = "on"; + static const char *OFF = "off"; + static const char *BLINK = "blink"; + static const char *PACKETS = "packets"; + static const char *NETWORK = "network"; + static const char *INTERFACE = "interface"; + static const char *TRACE = "trace"; + static const char *WIFISCAN = "wifiscan"; + static const char *TYPES = "types"; + static const char *EVENT = "event"; + static const char *MESSAGE = "message"; + static const char *RTTY = "rtty"; + static const char *TOKEN = "token"; + static const char *SERVER = "server"; + static const char *PORT = "port"; + static const char *USER = "user"; + static const char *TIMEOUT = "timeout"; + static const char *UPGRADE = "upgrade"; + static const char *FACTORY = "factory"; + static const char *VERBOSE = "verbose"; + static const char *BANDS = "bands"; + static const char *CHANNELS = "channels"; + static const char *PASSWORD = "password"; + static const char *DEVICEUPDATE = "deviceupdate"; + + static const char *SERIALNUMBER = "serialNumber"; + static const char *COMPATIBLE = "compatible"; + static const char *DISCONNECTION = "disconnection"; + static const char *TIMESTAMP = "timestamp"; + static const char *SYSTEM = "system"; + static const char *HOST = "host"; + static const char *CONNECTIONIP = "connectionIp"; + static const char *TELEMETRY = "telemetry"; + static const char *BANDWIDTH = "bandwidth"; + + static const char *SCRIPT = "script"; + static const char *TYPE = "type"; + + static const char *RADIUS = "radius"; + static const char *RADIUSDATA = "data"; + static const char *RADIUSACCT = "acct"; + static const char *RADIUSAUTH = "auth"; + static const char *RADIUSCOA = "coa"; + static const char *RADIUSDST = "dst"; + static const char *IES = "ies"; + } + +namespace OpenWifi::uCentralProtocol::Events { + + static const char *CONNECT = "connect"; + static const char *STATE = "state"; + static const char *HEALTHCHECK = "healthcheck"; + static const char *LOG = "log"; + static const char *CRASHLOG = "crashlog"; + static const char *PING = "ping"; + static const char *CFGPENDING = "cfgpending"; + static const char *RECOVERY = "recovery"; + static const char *TELEMETRY = "telemetry"; + static const char *DEVICEUPDATE = "deviceupdate"; + static const char *VENUE_BROADCAST = "venue_broadcast"; + + enum EVENT_MSG { + ET_UNKNOWN, + ET_CONNECT, + ET_STATE, + ET_HEALTHCHECK, + ET_LOG, + ET_CRASHLOG, + ET_PING, + ET_CFGPENDING, + ET_RECOVERY, + ET_DEVICEUPDATE, + ET_TELEMETRY, + ET_VENUEBROADCAST + }; + + inline EVENT_MSG EventFromString(const std::string & Method) { + if(strcmp(STATE,Method.c_str())==0) + return ET_STATE; + else if(strcmp(HEALTHCHECK,Method.c_str())==0) + return ET_HEALTHCHECK; + else if(strcmp(CONNECT,Method.c_str())==0) + return ET_CONNECT; + else if(strcmp(CFGPENDING,Method.c_str())==0) + return ET_CFGPENDING; + else if(strcmp(CRASHLOG,Method.c_str())==0) + return ET_CRASHLOG; + else if(strcmp(DEVICEUPDATE,Method.c_str())==0) + return ET_DEVICEUPDATE; + else if(strcmp(LOG,Method.c_str())==0) + return ET_LOG; + else if(strcmp(PING,Method.c_str())==0) + return ET_PING; + else if(strcmp(RECOVERY,Method.c_str())==0) + return ET_RECOVERY; + else if(strcmp(TELEMETRY,Method.c_str())==0) + return ET_TELEMETRY; + else if(strcmp(VENUE_BROADCAST,Method.c_str())==0) + return ET_VENUEBROADCAST; + return ET_UNKNOWN; + }; +} + +namespace OpenWifi::Provisioning::DeviceClass { + + static const char * ANY = "any"; + static const char * SUBSCRIBER = "subscriber"; + static const char * VENUE = "venue"; + static const char * ENTITY = "entity"; + + inline bool Validate(const char *s) { + static std::vector Values{ ANY, ENTITY, SUBSCRIBER, VENUE }; + return std::find(cbegin(Values), cend(Values), s) != cend(Values); + } + +} + +#if defined(__GNUC__ ) +#pragma GCC diagnostic pop +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + + diff --git a/microservice_sample/src/framework/uCentral_Protocol.h b/microservice_sample/src/framework/uCentral_Protocol.h deleted file mode 100644 index 8a6094a..0000000 --- a/microservice_sample/src/framework/uCentral_Protocol.h +++ /dev/null @@ -1,130 +0,0 @@ -// -// License type: BSD 3-Clause License -// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE -// -// Created by Stephane Bourque on 2021-03-04. -// Arilia Wireless Inc. -// -#pragma once - -#include "Poco/String.h" - -namespace OpenWifi::uCentralProtocol { - - const int SERIAL_NUMBER_LENGTH = 30; - - // vocabulary used in the PROTOCOL.md file - static const char * JSONRPC = "jsonrpc"; - static const char * ID = "id"; - static const char * UUID = "uuid"; - static const char * JSONRPC_VERSION = "2.0"; - static const char * METHOD = "method"; - static const char * PARAMS = "params"; - static const char * SERIAL = "serial"; - static const char * FIRMWARE = "firmware"; - static const char * CONNECT = "connect"; - static const char * STATE = "state"; - static const char * HEALTHCHECK = "healthcheck"; - static const char * LOG = "log"; - static const char * CRASHLOG = "crashlog"; - static const char * PING = "ping"; - static const char * CFGPENDING = "cfgpending"; - static const char * RECOVERY = "recovery"; - static const char * COMPRESS_64 = "compress_64"; - static const char * CAPABILITIES = "capabilities"; - static const char * REQUEST_UUID = "request_uuid"; - static const char * SANITY = "sanity"; - static const char * DATA = "data"; - static const char * LOGLINES = "loglines"; - static const char * SEVERITY = "severity"; - static const char * ACTIVE = "active"; - static const char * REBOOT = "reboot"; - static const char * WHEN = "when"; - static const char * CONFIG = "config"; - static const char * EMPTY_JSON_DOC = "{}"; - static const char * RESULT = "result"; - static const char * REQUEST = "request"; - static const char * PERFORM = "perform"; - static const char * CONFIGURE = "configure"; - static const char * PENDING = "pending"; - static const char * SUBMITTED_BY_SYSTEM = "*system"; - static const char * URI = "uri"; - static const char * COMMAND = "command"; - static const char * PAYLOAD = "payload"; - static const char * KEEP_REDIRECTOR = "keep_redirector"; - static const char * DURATION = "duration"; - static const char * PATTERN = "pattern"; - static const char * LEDS = "leds"; - static const char * ON = "on"; - static const char * OFF = "off"; - static const char * BLINK = "blink"; - static const char * PACKETS = "packets"; - static const char * NETWORK = "network"; - static const char * INTERFACE = "interface"; - static const char * TRACE = "trace"; - static const char * WIFISCAN = "wifiscan"; - static const char * TYPES = "types"; - static const char * EVENT = "event"; - static const char * MESSAGE = "message"; - static const char * RTTY = "rtty"; - static const char * TOKEN = "token"; - static const char * SERVER = "server"; - static const char * PORT = "port"; - static const char * USER = "user"; - static const char * TIMEOUT = "timeout"; - static const char * UPGRADE = "upgrade"; - static const char * FACTORY = "factory"; - static const char * VERBOSE = "verbose"; - static const char * BANDS = "bands"; - static const char * CHANNELS = "channels"; - static const char * PASSWORD = "password"; - static const char * DEVICEUPDATE = "deviceupdate"; - - static const char * SERIALNUMBER = "serialNumber"; - static const char * COMPATIBLE = "compatible"; - static const char * DISCONNECTION = "disconnection"; - static const char * TIMESTAMP = "timestamp"; - static const char * SYSTEM = "system"; - static const char * HOST = "host"; - static const char * CONNECTIONIP = "connectionIp"; - static const char * TELEMETRY = "telemetry"; - - enum EVENT_MSG { - ET_UNKNOWN, - ET_CONNECT, - ET_STATE, - ET_HEALTHCHECK, - ET_LOG, - ET_CRASHLOG, - ET_PING, - ET_CFGPENDING, - ET_RECOVERY, - ET_DEVICEUPDATE, - ET_TELEMETRY - }; - - inline static EVENT_MSG EventFromString(const std::string & Method) { - if (!Poco::icompare(Method, CONNECT)) { - return ET_CONNECT; - } else if (!Poco::icompare(Method, STATE)) { - return ET_STATE; - } else if (!Poco::icompare(Method, HEALTHCHECK)) { - return ET_HEALTHCHECK; - } else if (!Poco::icompare(Method, LOG)) { - return ET_LOG; - } else if (!Poco::icompare(Method, CRASHLOG)) { - return ET_CRASHLOG; - } else if (!Poco::icompare(Method, PING)) { - return ET_PING; - } else if (!Poco::icompare(Method, CFGPENDING)) { - return ET_CFGPENDING; - } else if (!Poco::icompare(Method, RECOVERY)) { - return ET_RECOVERY; - } else if (!Poco::icompare(Method, DEVICEUPDATE)) { - return ET_DEVICEUPDATE; - } else if (!Poco::icompare(Method, TELEMETRY)) { - return ET_TELEMETRY; - } else - return ET_UNKNOWN; - }; -} diff --git a/microservice_sample/src/ow_version.h.in b/microservice_sample/src/ow_version.h.in new file mode 100644 index 0000000..f61c19e --- /dev/null +++ b/microservice_sample/src/ow_version.h.in @@ -0,0 +1,13 @@ +// +// Created by stephane bourque on 2021-12-06. +// + +#pragma once + +#include + +namespace OW_VERSION { + inline static const std::string VERSION{"@CMAKE_PROJECT_VERSION@"}; + inline static const std::string BUILD{"@BUILD_NUM@"}; + inline static const std::string HASH{"@GIT_HASH@"}; +} \ No newline at end of file