Adding time point recording.

This commit is contained in:
stephb9959
2022-03-21 22:36:21 -07:00
parent f96a9502be
commit d6a9138e4b
21 changed files with 888 additions and 126 deletions

1
.idea/.name generated Normal file
View File

@@ -0,0 +1 @@
owanalytics

7
.idea/dictionaries/stephb.xml generated Normal file
View File

@@ -0,0 +1,7 @@
<component name="ProjectDictionaryState">
<dictionary name="stephb">
<words>
<w>bourque</w>
</words>
</dictionary>
</component>

View File

@@ -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}

2
build
View File

@@ -1 +1 @@
12
20

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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<AnalyticsObjects::DeviceTimePoint> DTP_;
uint64_t mac_=0;
std::string boardId_;
AnalyticsObjects::DeviceInfo DI_;
std::vector<AnalyticsObjects::DeviceTimePoint> DTP_;
};
}

View File

@@ -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);
}
}

View File

@@ -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<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal){}
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/board/{id}/timepoint"}; };
private:
TimePointDB & DB_=StorageService()->TimePointsDB();
void DoGet() final;
void DoPost() final {};
void DoPut() final {};
void DoDelete() final {};
};
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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<VenueInfo> 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<DeviceInfo> 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<msdu_entry> msdus;
UE_rate tx_rate,
rx_rate;
std::vector<MSDU_entry> 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<UETimePoint> 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<SSIDTimePoint> ssid_data;
std::string id;
std::string boardId;
uint64_t timestamp = 0;
APTimePoint ap_data;
std::vector<SSIDTimePoint> ssid_data;
std::vector<RadioTimePoint> 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<DeviceTimePoint> 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);
};
}
}

View File

@@ -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;

View File

@@ -18,6 +18,8 @@ namespace OpenWifi {
BoardsDB_ = std::make_unique<OpenWifi::BoardsDB>(dbType_,*Pool_, Logger());
BoardsDB_->Create();
TimePointsDB_ = std::make_unique<OpenWifi::TimePointDB>(dbType_,*Pool_, Logger());
TimePointsDB_->Create();
Updater_.start(*this);

View File

@@ -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<OpenWifi::BoardsDB> BoardsDB_;
std::unique_ptr<OpenWifi::TimePointDB> TimePointsDB_;
Poco::Thread Updater_;
std::atomic_bool Running_=false;
Poco::Timer Timer_;

View File

@@ -11,7 +11,7 @@ namespace OpenWifi {
void VenueWatcher::Start() {
for(const auto &mac:SerialNumbers_) {
auto ap = std::make_shared<AP>(mac);
auto ap = std::make_shared<AP>(mac, boardId_);
APs_[mac ] = ap;
}

View File

@@ -35,11 +35,10 @@ namespace OpenWifi {
class VenueWatcher : public Poco::Runnable {
public:
explicit VenueWatcher(const std::string &id, Poco::Logger &L, const std::vector<uint64_t> & SerialNumbers) :
Id_(id),
Logger_(L),
SerialNumbers_(SerialNumbers) {
explicit VenueWatcher(const std::string &boardId, Poco::Logger &L, const std::vector<uint64_t> & 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<uint64_t> &SerialNumbers);
void GetDevices(std::vector<AnalyticsObjects::DeviceInfo> & 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<uint64_t> SerialNumbers_;
std::map<uint64_t, std::shared_ptr<AP>> APs_;
std::recursive_mutex Mutex_;
std::string boardId_;
Poco::NotificationQueue Queue_;
Poco::Logger &Logger_;
Poco::Thread Worker_;
std::atomic_bool Running_=false;
std::vector<uint64_t> SerialNumbers_;
std::map<uint64_t, std::shared_ptr<AP>> APs_;
};
}

View File

@@ -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<class T> 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<Poco::Net::HTTPServer>(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<Poco::Net::HTTPServer>(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<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
// [[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & 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<Poco::Crypto::RSAKey>(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<Poco::Crypto::RSAKey>(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<Poco::Net::HTTPServer>(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<Poco::Net::HTTPServer>(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);

View File

@@ -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"

View File

@@ -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<std::string> 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<AnalyticsObjects::DeviceTimePoint> & 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<OpenWifi::TimePointDBRecordType, OpenWifi::AnalyticsObjects::DeviceTimePoint>::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<OpenWifi::AnalyticsObjects::APTimePoint>(In.get<3>());
Out.ssid_data = OpenWifi::RESTAPI_utils::to_object_array<OpenWifi::AnalyticsObjects::SSIDTimePoint>(In.get<4>());
Out.radio_data = OpenWifi::RESTAPI_utils::to_object_array<OpenWifi::AnalyticsObjects::RadioTimePoint>(In.get<5>());
Out.device_info = OpenWifi::RESTAPI_utils::to_object<OpenWifi::AnalyticsObjects::DeviceInfo>(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));
}

View File

@@ -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<TimePointDBRecordType, AnalyticsObjects::DeviceTimePoint> {
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;
};
}