diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..850af89 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +owanalytics \ No newline at end of file diff --git a/.idea/dictionaries/stephb.xml b/.idea/dictionaries/stephb.xml new file mode 100644 index 0000000..d141969 --- /dev/null +++ b/.idea/dictionaries/stephb.xml @@ -0,0 +1,7 @@ + + + + bourque + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 528bb8d..b6983ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,7 +84,7 @@ add_executable(owanalytics src/RESTAPI/RESTAPI_routers.cpp src/Daemon.cpp src/Daemon.h src/Dashboard.h src/Dashboard.cpp - src/StorageService.cpp src/StorageService.h src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h src/StateReceiver.cpp src/StateReceiver.h src/VenueWatcher.cpp src/VenueWatcher.h src/VenueCoordinator.cpp src/VenueCoordinator.h src/sdks/SDK_prov.cpp src/sdks/SDK_prov.h src/storage/storage_boards.cpp src/storage/storage_boards.h src/RESTAPI/RESTAPI_board_list_handler.cpp src/RESTAPI/RESTAPI_board_list_handler.h src/RESTAPI/RESTAPI_board_handler.cpp src/RESTAPI/RESTAPI_board_handler.h src/RESTAPI/RESTAPI_analytics_db_helpers.h src/APStats.cpp src/APStats.h src/dict_ssid.h src/dict_ue.h src/dict_bssid.h src/DeviceStatusReceiver.cpp src/DeviceStatusReceiver.h src/RESTAPI/RESTAPI_board_devices_handler.cpp src/RESTAPI/RESTAPI_board_devices_handler.h src/HealthReceiver.cpp src/HealthReceiver.h src/StatFunc.h) + src/StorageService.cpp src/StorageService.h src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h src/StateReceiver.cpp src/StateReceiver.h src/VenueWatcher.cpp src/VenueWatcher.h src/VenueCoordinator.cpp src/VenueCoordinator.h src/sdks/SDK_prov.cpp src/sdks/SDK_prov.h src/storage/storage_boards.cpp src/storage/storage_boards.h src/RESTAPI/RESTAPI_board_list_handler.cpp src/RESTAPI/RESTAPI_board_list_handler.h src/RESTAPI/RESTAPI_board_handler.cpp src/RESTAPI/RESTAPI_board_handler.h src/RESTAPI/RESTAPI_analytics_db_helpers.h src/APStats.cpp src/APStats.h src/dict_ssid.h src/dict_ue.h src/dict_bssid.h src/DeviceStatusReceiver.cpp src/DeviceStatusReceiver.h src/RESTAPI/RESTAPI_board_devices_handler.cpp src/RESTAPI/RESTAPI_board_devices_handler.h src/HealthReceiver.cpp src/HealthReceiver.h src/StatFunc.h src/RESTAPI/RESTAPI_board_timepoint_handler.cpp src/RESTAPI/RESTAPI_board_timepoint_handler.h src/storage/storage_timepoints.cpp src/storage/storage_timepoints.h) target_link_libraries(owanalytics PUBLIC ${Poco_LIBRARIES} ${MySQL_LIBRARIES} diff --git a/build b/build index 3cacc0b..2edeafb 100644 --- a/build +++ b/build @@ -1 +1 @@ -12 \ No newline at end of file +20 \ No newline at end of file diff --git a/openapi/owanalytics.yaml b/openapi/owanalytics.yaml index 8fcccfd..3d822d0 100644 --- a/openapi/owanalytics.yaml +++ b/openapi/owanalytics.yaml @@ -230,6 +230,213 @@ components: items: $ref: '#/components/schemas/DeviceInfo' + MSDU_entry: + type: object + properties: + rx_msdu: + type: integer + format: int64 + tx_msdu: + type: integer + format: int64 + tx_msdu_failed: + type: integer + format: int64 + tx_msdu_retries: + type: integer + format: int64 + + UE_rate: + type: object + properties: + bitrate: + type: integer + format: int64 + mcs: + type: integer + format: int64 + nss: + type: integer + format: int64 + chwidth: + type: integer + format: int64 + ht: + type: boolean + sgi: + type: + boolean + + UETimePoint: + type: object + properties: + association_bssid: + type: integer + format: int64 + station: + type: integer + format: int64 + rssi: + type: integer + format: int64 + tx_bytes: + type: integer + format: int64 + rx_bytes: + type: integer + format: int64 + tx_duration: + type: integer + format: int64 + rx_packets: + type: integer + format: int64 + tx_packets: + type: integer + format: int64 + tx_retries: + type: integer + format: int64 + tx_failed: + type: integer + format: int64 + connected: + type: integer + format: int64 + inactive: + type: integer + format: int64 + tx_rate: + $ref: '#/components/schemas/UE_rate' + rx_rate: + $ref: '#/components/schemas/UE_rate' + msdus: + type: array + items: + $ref: '#/components/schemas/MSDU_entry' + + SSIDTimePoint: + type: object + properties: + bssid: + type: string + mode: + type: string + ssid: + type: string + associations: + type: array + items: + $ref: '#/components/schemas/UETimePoint' + + APTimePoint: + type: object + properties: + collisions: + type: integer + format: int64 + multicast: + type: integer + format: int64 + rx_bytes: + type: integer + format: int64 + rx_dropped: + type: integer + format: int64 + rx_errors: + type: integer + format: int64 + rx_packets: + type: integer + format: int64 + tx_bytes: + type: integer + format: int64 + tx_dropped: + type: integer + format: int64 + tx_errors: + type: integer + format: int64 + tx_packets: + type: integer + format: int64 + + RadioTimePoint: + type: object + properties: + band: + type: integer + format: int64 + radio_channel: + type: integer + format: int64 + active_ms: + type: integer + format: int64 + busy_ms: + type: integer + format: int64 + receive_ms: + type: integer + format: int64 + transmit_ms: + type: integer + format: int64 + tx_power: + type: integer + format: int64 + channel: + type: integer + format: int64 + temperature: + type: integer + format: int64 + noise: + type: integer + format: int64 + + DeviceTimePoint: + type: object + properties: + timestamp: + type: integer + format: int64 + ap_data: + $ref: '#/components/schemas/APTimePoint' + ssid_data: + type: array + items: + $ref: '#/components/schemas/SSIDTimePoint' + radio_data: + type: array + items: + $ref: '#/components/schemas/RadioTimePoint' + device_info: + $ref: '#/components/schemas/DeviceInfo' + + DeviceTimePointList: + type: object + properties: + points: + type: array + items: + $ref: '#/components/schemas/DeviceTimePoint' + + DeviceTimePointStats: + type: object + properties: + firstPoint: + type: integer + format: int64 + lastPoint: + type: integer + format: int64 + count: + type: integer + format: int64 + ######################################################################################### ## ## These are endpoints that all services in the OPenWiFI stack must provide @@ -603,6 +810,59 @@ paths: 404: $ref: '#/components/responses/NotFound' + /board/{id}/timepoint: + get: + tags: + - Board data + summary: retrieve board data for a given time period. + operationId: getBoardTimepoint + parameters: + - in: path + name: id + schema: + type: string + format: uuid + required: true + - in: query + name: fromDate + schema: + type: integer + required: false + - in: query + name: endDate + schema: + type: integer + required: false + - in: query + name: maxRecords + schema: + type: integer + default: 100 + required: false + + - in: query + name: stats + schema: + type: boolean + required: false + + responses: + 200: + description: Successfull retrieval of timepoints + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/DeviceTimePointList' + - $ref: '#/components/schemas/DeviceTimePointStats' + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Unauthorized' + 404: + $ref: '#/components/responses/NotFound' + + /iptocountry: get: tags: diff --git a/src/APStats.cpp b/src/APStats.cpp index 4811326..d511863 100644 --- a/src/APStats.cpp +++ b/src/APStats.cpp @@ -4,6 +4,7 @@ #include "APStats.h" #include "dict_ssid.h" +#include "StorageService.h" namespace OpenWifi { @@ -94,16 +95,12 @@ namespace OpenWifi { auto ref = radio["$ref"]; auto radio_parts = Poco::StringTokenizer(ref, "/"); if(radio_parts.count()==3) - radio_location = std::atoi(radio_parts[2].c_str()); + radio_location = std::strtol(radio_parts[2].c_str(), nullptr,10); } } - std::string bssid, mode, ssid_name; - GetJSON("bssid",ssid,bssid, std::string{""}); - SSIDTP.bssid = Utils::MACToInt(bssid); - GetJSON("mode",ssid,mode, std::string{""} ); - SSIDTP.mode = AnalyticsObjects::SSID_Mode(mode); - GetJSON("ssid",ssid,ssid_name, std::string{""} ); - SSIDTP.ssid = SSID_DICT()->Add(ssid_name); + GetJSON("bssid",ssid,SSIDTP.bssid, std::string{""}); + GetJSON("mode",ssid,SSIDTP.mode, std::string{""} ); + GetJSON("ssid",ssid,SSIDTP.ssid, std::string{""} ); if (ssid.contains("associations") && ssid["associations"].is_array()) { auto associations = ssid["associations"]; auto it = radio_band.find(radio_location); @@ -118,11 +115,7 @@ namespace OpenWifi { } for(const auto &association:associations) { AnalyticsObjects::UETimePoint TP; - std::string association_bssid,station; - GetJSON("bssid",association,association_bssid, std::string{""} ); - GetJSON("station",association,station, std::string{} ); - TP.association_bssid = Utils::MACToInt(association_bssid); - TP.station = Utils::MACToInt(station); + GetJSON("station",association,TP.station, std::string{} ); GetJSON("rssi",association,TP.rssi, (int64_t)0 ); GetJSON("tx_bytes",association,TP.tx_bytes, (uint64_t)0 ); GetJSON("rx_bytes",association,TP.rx_bytes, (uint64_t)0 ); @@ -137,7 +130,7 @@ namespace OpenWifi { if(association.contains("msdu") && association["msdu"].is_array()) { auto msdus = association["msdu"]; for(const auto &msdu:msdus) { - AnalyticsObjects::msdu_entry E; + AnalyticsObjects::MSDU_entry E; GetJSON("rx_msdu",msdu,E.rx_msdu, (uint64_t)0 ); GetJSON("tx_msdu",msdu,E.tx_msdu, (uint64_t)0 ); GetJSON("tx_msdu_failed",msdu,E.tx_msdu_failed, (uint64_t)0 ); @@ -146,6 +139,26 @@ namespace OpenWifi { } } + if(association.contains("tx_rate")) { + auto tx_rate = association["tx_rate"]; + GetJSON("bitrate",tx_rate,TP.tx_rate.bitrate, (uint64_t)0 ); + GetJSON("mcs",tx_rate,TP.tx_rate.mcs, (uint64_t)0 ); + GetJSON("nss",tx_rate,TP.tx_rate.nss, (uint64_t)0 ); + GetJSON("chwidth",tx_rate,TP.tx_rate.chwidth, (uint64_t)0 ); + GetJSON("ht",tx_rate,TP.tx_rate.ht, false ); + GetJSON("sgi",tx_rate,TP.tx_rate.sgi, false ); + } + + if(association.contains("rx_rate")) { + auto rx_rate = association["rx_rate"]; + GetJSON("bitrate",rx_rate,TP.rx_rate.bitrate, (uint64_t)0 ); + GetJSON("mcs",rx_rate,TP.rx_rate.mcs, (uint64_t)0 ); + GetJSON("nss",rx_rate,TP.rx_rate.nss, (uint64_t)0 ); + GetJSON("chwidth",rx_rate,TP.rx_rate.chwidth, (uint64_t)0 ); + GetJSON("ht",rx_rate,TP.rx_rate.ht, false ); + GetJSON("sgi",rx_rate,TP.rx_rate.sgi, false ); + } + SSIDTP.associations.push_back(TP); } } @@ -161,11 +174,17 @@ namespace OpenWifi { std::cout << Utils::IntToSerialNumber(mac_) << ": stats failed parsing." ; std::cout << *State << std::endl; } + + DTP.id = MicroService::instance().CreateUUID(); + DTP.boardId = boardId_; + StorageService()->TimePointsDB().CreateRecord(DTP); + DTP_.push_back(DTP); if(DTP_.size()>1000) { DTP_.erase(DTP_.begin()); } + std::cout << "Serial: " << Utils::IntToSerialNumber(mac_) << " points: " << DTP_.size() << std::endl; } diff --git a/src/APStats.h b/src/APStats.h index fc61455..1554c9d 100644 --- a/src/APStats.h +++ b/src/APStats.h @@ -18,7 +18,10 @@ namespace OpenWifi { class AP { public: - explicit AP(uint64_t mac) : mac_(mac) { + explicit AP(uint64_t mac, const std::string &BoardId) : + mac_(mac), + boardId_(BoardId) + { DI_.serialNumber = Utils::IntToSerialNumber(mac); } @@ -28,8 +31,9 @@ namespace OpenWifi { const AnalyticsObjects::DeviceInfo & Info() const { return DI_; } private: - uint64_t mac_=0; - AnalyticsObjects::DeviceInfo DI_; - std::vector DTP_; + uint64_t mac_=0; + std::string boardId_; + AnalyticsObjects::DeviceInfo DI_; + std::vector DTP_; }; } diff --git a/src/RESTAPI/RESTAPI_board_timepoint_handler.cpp b/src/RESTAPI/RESTAPI_board_timepoint_handler.cpp new file mode 100644 index 0000000..1f168cb --- /dev/null +++ b/src/RESTAPI/RESTAPI_board_timepoint_handler.cpp @@ -0,0 +1,39 @@ +// +// Created by stephane bourque on 2022-03-21. +// + +#include "RESTAPI_board_timepoint_handler.h" +#include "StorageService.h" + +namespace OpenWifi { + void RESTAPI_board_timepoint_handler::DoGet() { + auto id = GetBinding("id",""); + if(id.empty()) { + return BadRequest(RESTAPI::Errors::MissingUUID); + } + + AnalyticsObjects::BoardInfo B; + if(!StorageService()->BoardsDB().GetRecord("id",id,B)) { + return NotFound(); + } + + auto fromDate = GetParameter("fromDate",0); + auto endDate = GetParameter("endDate",0); + auto maxRecords = GetParameter("maxRecords",100); + auto stats = GetBoolParameter("stats"); + + if(stats) { + AnalyticsObjects::DeviceTimePointStats DTPS; + Poco::JSON::Object Answer; + DB_.GetStats(id,DTPS); + DTPS.to_json(Answer); + return ReturnObject(Answer); + } + + AnalyticsObjects::DeviceTimePointList Points; + StorageService()->TimePointsDB().SelectRecords(fromDate, endDate, maxRecords, Points.points); + Poco::JSON::Object Answer; + Points.to_json(Answer); + return ReturnObject(Answer); + } +} \ No newline at end of file diff --git a/src/RESTAPI/RESTAPI_board_timepoint_handler.h b/src/RESTAPI/RESTAPI_board_timepoint_handler.h new file mode 100644 index 0000000..8169128 --- /dev/null +++ b/src/RESTAPI/RESTAPI_board_timepoint_handler.h @@ -0,0 +1,32 @@ +// +// Created by stephane bourque on 2022-03-21. +// + +#pragma once + +#include "framework/MicroService.h" +#include "StorageService.h" + +namespace OpenWifi { + + class RESTAPI_board_timepoint_handler : public RESTAPIHandler { + public: + RESTAPI_board_timepoint_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, + TransactionId, + Internal){} + + static const std::list PathName() { return std::list{"/api/v1/board/{id}/timepoint"}; }; + + private: + TimePointDB & DB_=StorageService()->TimePointsDB(); + void DoGet() final; + void DoPost() final {}; + void DoPut() final {}; + void DoDelete() final {}; + }; +} diff --git a/src/RESTAPI/RESTAPI_routers.cpp b/src/RESTAPI/RESTAPI_routers.cpp index 8863bf7..aed6dc3 100644 --- a/src/RESTAPI/RESTAPI_routers.cpp +++ b/src/RESTAPI/RESTAPI_routers.cpp @@ -6,26 +6,31 @@ #include "RESTAPI/RESTAPI_board_list_handler.h" #include "RESTAPI/RESTAPI_board_handler.h" #include "RESTAPI/RESTAPI_board_devices_handler.h" +#include "RESTAPI/RESTAPI_board_timepoint_handler.h" namespace OpenWifi { Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings, - Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { + Poco::Logger & L, RESTAPI_GenericServer & S, + uint64_t TransactionId) { return RESTAPI_Router< RESTAPI_system_command, RESTAPI_board_devices_handler, RESTAPI_board_handler, - RESTAPI_board_list_handler + RESTAPI_board_list_handler, + RESTAPI_board_timepoint_handler >(Path,Bindings,L, S, TransactionId); } Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const char *Path, RESTAPIHandler::BindingMap &Bindings, - Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) { + Poco::Logger & L, RESTAPI_GenericServer & S, + uint64_t TransactionId) { return RESTAPI_Router_I< RESTAPI_system_command, RESTAPI_board_devices_handler, RESTAPI_board_handler, - RESTAPI_board_list_handler + RESTAPI_board_list_handler, + RESTAPI_board_timepoint_handler >(Path, Bindings, L, S, TransactionId); } diff --git a/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp b/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp index afadf6f..ff7ce40 100644 --- a/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp +++ b/src/RESTObjects/RESTAPI_AnalyticsObjects.cpp @@ -129,8 +129,31 @@ namespace OpenWifi::AnalyticsObjects { 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,"association_bssid",association_bssid); field_to_json(Obj,"station",station); field_to_json(Obj,"rssi",rssi); field_to_json(Obj,"tx_bytes",tx_bytes); @@ -142,6 +165,30 @@ namespace OpenWifi::AnalyticsObjects { 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); + } + + 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); + return true; + } catch(...) { + + } + return false; } void APTimePoint::to_json(Poco::JSON::Object &Obj) const { @@ -158,13 +205,46 @@ namespace OpenWifi::AnalyticsObjects { field_to_json(Obj,"tx_packets",tx_packets); } - void msdu_entry::to_json(Poco::JSON::Object &Obj) const { + 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); + return true; + } catch(...) { + + } + return false; + } + + void MSDU_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 MSDU_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,"radio_channel",radio_channel); @@ -178,6 +258,25 @@ namespace OpenWifi::AnalyticsObjects { field_to_json(Obj,"noise",noise); } + bool RadioTimePoint::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"band",band); + field_from_json(Obj,"radio_channel",radio_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,"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); + 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); @@ -185,11 +284,75 @@ namespace OpenWifi::AnalyticsObjects { field_to_json(Obj,"associations",associations); } + 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,"associations",associations); + 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); } + + 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); + return true; + } catch(...) { + + } + return false; + } + + void DeviceTimePointList::to_json(Poco::JSON::Object &Obj) const { + field_to_json(Obj,"points",points); + } + + bool DeviceTimePointList::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj,"points",points); + 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; + } + } \ No newline at end of file diff --git a/src/RESTObjects/RESTAPI_AnalyticsObjects.h b/src/RESTObjects/RESTAPI_AnalyticsObjects.h index a066dbe..819526d 100644 --- a/src/RESTObjects/RESTAPI_AnalyticsObjects.h +++ b/src/RESTObjects/RESTAPI_AnalyticsObjects.h @@ -28,7 +28,6 @@ namespace OpenWifi { bool monitorSubVenues = false; void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); }; @@ -37,7 +36,6 @@ namespace OpenWifi { 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 { @@ -75,7 +73,6 @@ namespace OpenWifi { double memory; void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); }; @@ -83,7 +80,6 @@ namespace OpenWifi { std::vector devices; void to_json(Poco::JSON::Object &Obj) const; - bool from_json(const Poco::JSON::Object::Ptr &Obj); }; @@ -91,18 +87,30 @@ namespace OpenWifi { band_2g = 0, band_5g = 1, band_6g = 2 }; - struct msdu_entry { + struct MSDU_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 UETimePoint { - uint64_t association_bssid = 0, - station = 0; + std::string station; int64_t rssi = 0; uint64_t tx_bytes = 0, rx_bytes = 0, @@ -113,9 +121,12 @@ namespace OpenWifi { tx_failed = 0, connected = 0, inactive = 0; - std::vector msdus; + UE_rate tx_rate, + rx_rate; + std::vector msdus; void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; enum SSID_MODES { @@ -145,12 +156,13 @@ namespace OpenWifi { } struct SSIDTimePoint { - uint64_t bssid = 0, - mode = 0, - ssid = 0; + std::string bssid, + mode, + ssid; std::vector associations; void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; @@ -167,11 +179,12 @@ namespace OpenWifi { tx_packets = 0; void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; struct RadioTimePoint { - uint band = 0, - radio_channel = 0; + uint64_t band = 0, + radio_channel = 0; uint64_t active_ms = 0, busy_ms = 0, receive_ms = 0, @@ -182,17 +195,63 @@ namespace OpenWifi { noise = 0; void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; struct DeviceTimePoint { - uint64_t timestamp = 0; - APTimePoint ap_data; - std::vector ssid_data; + 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; void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct DeviceTimePointList { + std::vector points; + + void to_json(Poco::JSON::Object &Obj) const; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + + struct BandwidthAnalysisEntry { + uint64_t timestamp; + + }; + + 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); }; } } \ No newline at end of file diff --git a/src/StatFunc.h b/src/StatFunc.h index a3de1ac..45adcc1 100644 --- a/src/StatFunc.h +++ b/src/StatFunc.h @@ -68,6 +68,7 @@ namespace OpenWifi { bool inited = false; uint64_t LastValue=0; }; + std::ostream & operator<<(std::ostream &os, const RelativeCounter &rc) { os << rc.get() ; return os; diff --git a/src/StorageService.cpp b/src/StorageService.cpp index 4f900d5..79cf624 100644 --- a/src/StorageService.cpp +++ b/src/StorageService.cpp @@ -18,6 +18,8 @@ namespace OpenWifi { BoardsDB_ = std::make_unique(dbType_,*Pool_, Logger()); BoardsDB_->Create(); + TimePointsDB_ = std::make_unique(dbType_,*Pool_, Logger()); + TimePointsDB_->Create(); Updater_.start(*this); diff --git a/src/StorageService.h b/src/StorageService.h index 048b3bd..aee81d1 100644 --- a/src/StorageService.h +++ b/src/StorageService.h @@ -11,6 +11,7 @@ #include "framework/MicroService.h" #include "framework/StorageClass.h" #include "storage/storage_boards.h" +#include "storage/storage_timepoints.h" namespace OpenWifi { class Storage : public StorageClass, Poco::Runnable { @@ -25,10 +26,12 @@ namespace OpenWifi { void run() final; OpenWifi::BoardsDB & BoardsDB() { return *BoardsDB_; }; + OpenWifi::TimePointDB & TimePointsDB() { return *TimePointsDB_; }; void onTimer(Poco::Timer & timer); private: std::unique_ptr BoardsDB_; + std::unique_ptr TimePointsDB_; Poco::Thread Updater_; std::atomic_bool Running_=false; Poco::Timer Timer_; diff --git a/src/VenueWatcher.cpp b/src/VenueWatcher.cpp index 3798b96..e4be5b3 100644 --- a/src/VenueWatcher.cpp +++ b/src/VenueWatcher.cpp @@ -11,7 +11,7 @@ namespace OpenWifi { void VenueWatcher::Start() { for(const auto &mac:SerialNumbers_) { - auto ap = std::make_shared(mac); + auto ap = std::make_shared(mac, boardId_); APs_[mac ] = ap; } diff --git a/src/VenueWatcher.h b/src/VenueWatcher.h index 1d42218..e09c9f7 100644 --- a/src/VenueWatcher.h +++ b/src/VenueWatcher.h @@ -35,11 +35,10 @@ namespace OpenWifi { class VenueWatcher : public Poco::Runnable { public: - explicit VenueWatcher(const std::string &id, Poco::Logger &L, const std::vector & SerialNumbers) : - Id_(id), - Logger_(L), - SerialNumbers_(SerialNumbers) { - + explicit VenueWatcher(const std::string &boardId, Poco::Logger &L, const std::vector & SerialNumbers) : + boardId_(boardId), + Logger_(L), + SerialNumbers_(SerialNumbers) { std::sort(SerialNumbers_.begin(),SerialNumbers_.end()); auto last = std::unique(SerialNumbers_.begin(),SerialNumbers_.end()); SerialNumbers_.erase(last,SerialNumbers_.end()); @@ -68,15 +67,17 @@ namespace OpenWifi { void ModifySerialNumbers(const std::vector &SerialNumbers); void GetDevices(std::vector & DI); + void GetBandwidth(uint64_t start, uint64_t end, uint64_t interval , AnalyticsObjects::BandwidthAnalysis & BW); + private: - std::recursive_mutex Mutex_; - std::string Id_; - Poco::NotificationQueue Queue_; - Poco::Logger &Logger_; - Poco::Thread Worker_; - std::atomic_bool Running_=false; - std::vector SerialNumbers_; - std::map> APs_; + std::recursive_mutex Mutex_; + std::string boardId_; + Poco::NotificationQueue Queue_; + Poco::Logger &Logger_; + Poco::Thread Worker_; + std::atomic_bool Running_=false; + std::vector SerialNumbers_; + std::map> APs_; }; } \ No newline at end of file diff --git a/src/framework/MicroService.h b/src/framework/MicroService.h index 969382f..cc75328 100644 --- a/src/framework/MicroService.h +++ b/src/framework/MicroService.h @@ -71,6 +71,7 @@ using namespace std::chrono_literals; #include "Poco/SimpleFileChannel.h" #include "Poco/Util/PropertyFileConfiguration.h" #include "Poco/SplitterChannel.h" +#include "Poco/JWT/Signer.h" #include "cppkafka/cppkafka.h" @@ -379,6 +380,12 @@ namespace OpenWifi::RESTAPI_utils { } } + inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int64_t &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)) { Poco::JSON::Object::Ptr A = Obj->getObject(Field); @@ -1350,6 +1357,22 @@ namespace OpenWifi { } } + [[nodiscard]] inline Poco::Net::ServerSocket CreateSocket(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())); @@ -2863,33 +2886,6 @@ namespace OpenWifi { RESTAPI_GenericServer &Server_; }; - inline int RESTAPI_ExtServer::Start() { - 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()); - - Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams; - Params->setMaxThreads(50); - Params->setMaxQueued(200); - Params->setKeepAlive(true); - - auto NewServer = std::make_unique(new ExtRequestHandlerFactory(Server_), Pool_, Sock, Params); - NewServer->start(); - RESTServers_.push_back(std::move(NewServer)); - } - - return 0; - } - - class LogMuxer : public Poco::Channel { public: @@ -3021,32 +3017,6 @@ namespace OpenWifi { RESTAPI_GenericServer &Server_; }; - inline int RESTAPI_IntServer::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 IntRequestHandlerFactory(Server_), Pool_, Sock, Params); - NewServer->start(); - RESTServers_.push_back(std::move(NewServer)); - } - - return 0; - } - struct MicroServiceMeta { uint64_t Id=0; std::string Type; @@ -3081,7 +3051,7 @@ namespace OpenWifi { } [[nodiscard]] std::string Version() { return Version_; } - [[nodiscard]] const Poco::SharedPtr & Key() { return AppKey_; } + // [[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_; } @@ -3171,6 +3141,14 @@ namespace OpenWifi { } } + } + 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); + } } private: static MicroService * instance_; @@ -3197,12 +3175,15 @@ namespace OpenWifi { std::recursive_mutex InfraMutex_; std::default_random_engine RandomEngine_; 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; - }; + 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; + bool NoAPISecurity_=false; + bool NoBuiltInCrypto_=false; + Poco::JWT::Signer Signer_; + }; inline void MicroService::Exit(int Reason) { std::exit(Reason); @@ -3325,10 +3306,19 @@ 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); @@ -3658,10 +3648,14 @@ 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);; } @@ -3713,7 +3707,68 @@ namespace OpenWifi { SubSystemConfigPrefix_(std::move(SubSystemConfigPrefix)) { } - inline int MicroService::main(const ArgVec &args) { + inline int RESTAPI_ExtServer::Start() { + 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{ MicroService::instance().NoAPISecurity() ? Svr.CreateSocket(Logger()) : Svr.CreateSecureSocket(Logger())}; + + if(MicroService::instance().NoAPISecurity()) { + Logger().information("Security has been disabled for APIs."); + } else { + 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); + + auto NewServer = std::make_unique(new ExtRequestHandlerFactory(Server_), 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_) { + Logger().information(Poco::format("Starting: %s:%s Keyfile:%s CertFile: %s", Svr.Address(), std::to_string(Svr.Port()), + Svr.KeyFile(),Svr.CertFile())); + + auto Sock{ MicroService::instance().NoAPISecurity() ? Svr.CreateSocket(Logger()) : Svr.CreateSecureSocket(Logger())}; + + if(MicroService::instance().NoAPISecurity()) { + Logger().information("Security has been disabled for APIs."); + } else { + 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 IntRequestHandlerFactory(Server_), Pool_, Sock, Params); + NewServer->start(); + RESTServers_.push_back(std::move(NewServer)); + } + + return 0; + } + + inline int MicroService::main(const ArgVec &args) { MyErrorHandler ErrorHandler(*this); Poco::ErrorHandler::set(&ErrorHandler); diff --git a/src/storage/storage_boards.cpp b/src/storage/storage_boards.cpp index 5173ce6..7310db2 100644 --- a/src/storage/storage_boards.cpp +++ b/src/storage/storage_boards.cpp @@ -61,8 +61,3 @@ template<> void ORM::DB< OpenWifi::BoardDBRecordType, OpenWifi::AnalyticsObje Out.set<5>(In.info.modified); Out.set<6>(OpenWifi::RESTAPI_utils::to_string(In.venueList)); } -// -// Created by stephane bourque on 2022-03-11. -// - -#include "storage_boards.h" diff --git a/src/storage/storage_timepoints.cpp b/src/storage/storage_timepoints.cpp new file mode 100644 index 0000000..dc68107 --- /dev/null +++ b/src/storage/storage_timepoints.cpp @@ -0,0 +1,87 @@ +// +// Created by stephane bourque on 2022-03-21. +// + +#include "storage_timepoints.h" +#include "framework/MicroService.h" +#include "framework/OpenWifiTypes.h" + +namespace OpenWifi { + + static ORM::FieldVec TimePoint_Fields{ + // object info + ORM::Field{"id",64, true}, + ORM::Field{"boardId",ORM::FieldType::FT_TEXT}, + ORM::Field{"timestamp",ORM::FieldType::FT_BIGINT}, + ORM::Field{"ap_data",ORM::FieldType::FT_TEXT}, + ORM::Field{"ssid_data",ORM::FieldType::FT_TEXT}, + ORM::Field{"radio_data",ORM::FieldType::FT_TEXT}, + ORM::Field{"device_info",ORM::FieldType::FT_BIGINT} + }; + + static ORM::IndexVec TimePointDB_Indexes{ + { std::string("timepoint_board_index"), + ORM::IndexEntryVec{ + {std::string("boardId"), + ORM::Indextype::ASC}, + {std::string("timestamp"), + ORM::Indextype::ASC}} } + }; + + TimePointDB::TimePointDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : + DB(T, "timepoints", TimePoint_Fields, TimePointDB_Indexes, P, L, "tpo") {} + + bool TimePointDB::Upgrade(uint32_t from, uint32_t &to) { + std::vector Statements{ + }; + RunScript(Statements); + to = 2; + return true; + } + + bool TimePointDB::GetStats(const std::string &id, AnalyticsObjects::DeviceTimePointStats &S) { + S.count = S.firstPoint = S.lastPoint = 0 ; + auto F = [&](const DB::RecordName &R) -> bool { + S.count++; + if(S.firstPoint==0) S.firstPoint=R.timestamp; + S.lastPoint=R.timestamp; + return true; + }; + Iterate(F," boardId='" + id + "'"); + return true; + } + + bool TimePointDB::SelectRecords(uint64_t FromDate, uint64_t LastDate, uint64_t MaxRecords, std::vector & Recs ) { + std::string WhereClause; + + if(FromDate && LastDate) { + WhereClause = " (timestamp >= " + std::to_string(FromDate) + ") and ( timestamp <= " + std::to_string(LastDate) + " ) "; + } else if (FromDate) { + WhereClause = " (timestamp >= " + std::to_string(FromDate) + ") "; + } else if (LastDate) { + WhereClause = " ( timestamp <= " + std::to_string(LastDate) + " ) "; + } + GetRecords(0,MaxRecords,Recs,WhereClause," timestamp ASC "); + return true; + } +} + +template<> void ORM::DB::Convert(const OpenWifi::TimePointDBRecordType &In, OpenWifi::AnalyticsObjects::DeviceTimePoint &Out) { + Out.id = In.get<0>(); + Out.boardId = In.get<1>(); + Out.timestamp = In.get<2>(); + Out.ap_data = OpenWifi::RESTAPI_utils::to_object(In.get<3>()); + Out.ssid_data = OpenWifi::RESTAPI_utils::to_object_array(In.get<4>()); + Out.radio_data = OpenWifi::RESTAPI_utils::to_object_array(In.get<5>()); + Out.device_info = OpenWifi::RESTAPI_utils::to_object(In.get<6>()); +} + +template<> void ORM::DB< OpenWifi::TimePointDBRecordType, OpenWifi::AnalyticsObjects::DeviceTimePoint>::Convert(const OpenWifi::AnalyticsObjects::DeviceTimePoint &In, OpenWifi::TimePointDBRecordType &Out) { + Out.set<0>(In.id); + Out.set<1>(In.boardId); + Out.set<2>(In.timestamp); + Out.set<3>(OpenWifi::RESTAPI_utils::to_string(In.ap_data)); + Out.set<4>(OpenWifi::RESTAPI_utils::to_string(In.ssid_data)); + Out.set<5>(OpenWifi::RESTAPI_utils::to_string(In.radio_data)); + Out.set<6>(OpenWifi::RESTAPI_utils::to_string(In.device_info)); +} diff --git a/src/storage/storage_timepoints.h b/src/storage/storage_timepoints.h new file mode 100644 index 0000000..2fe5ffa --- /dev/null +++ b/src/storage/storage_timepoints.h @@ -0,0 +1,29 @@ +// +// Created by stephane bourque on 2022-03-21. +// + +#pragma once + +#include "framework/orm.h" +#include "RESTObjects/RESTAPI_AnalyticsObjects.h" + +namespace OpenWifi { + typedef Poco::Tuple< + std::string, + std::string, + uint64_t, + std::string, + std::string, + std::string, + std::string + > TimePointDBRecordType; + + class TimePointDB : public ORM::DB { + public: + TimePointDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L); + bool GetStats(const std::string &id, AnalyticsObjects::DeviceTimePointStats &S); + bool SelectRecords(uint64_t FromDate, uint64_t LastDate, uint64_t MaxRecords, DB::RecordVec & Recs); + private: + bool Upgrade(uint32_t from, uint32_t &to) override; + }; +}