mirror of
https://github.com/Telecominfraproject/wlan-cloud-analytics.git
synced 2026-03-20 03:39:59 +00:00
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
This commit is contained in:
@@ -8,227 +8,246 @@
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenWifi {
|
||||
typedef std::vector<std::pair<std::uint64_t , std::uint64_t >> bucket_timespans;
|
||||
typedef std::vector< std::vector<AnalyticsObjects::DeviceTimePoint>> split_points;
|
||||
typedef std::vector<std::pair<std::uint64_t, std::uint64_t>> bucket_timespans;
|
||||
typedef std::vector<std::vector<AnalyticsObjects::DeviceTimePoint>> split_points;
|
||||
|
||||
template <typename X, typename M> void AverageAPData( X T, const std::vector<M> &Values, AnalyticsObjects::AveragePoint &P) {
|
||||
if(Values.empty())
|
||||
return;
|
||||
double sum = 0.0;
|
||||
for(const auto &v:Values) {
|
||||
sum += (v.ap_data.*T);
|
||||
if((v.ap_data.*T)!=0) {
|
||||
P.min = std::min(P.min, (v.ap_data.*T));
|
||||
}
|
||||
P.max = std::min(P.max,(v.ap_data.*T));
|
||||
}
|
||||
P.avg = sum / (double) Values.size();
|
||||
}
|
||||
template <typename X, typename M>
|
||||
void AverageAPData(X T, const std::vector<M> &Values, AnalyticsObjects::AveragePoint &P) {
|
||||
if (Values.empty())
|
||||
return;
|
||||
double sum = 0.0;
|
||||
for (const auto &v : Values) {
|
||||
sum += (v.ap_data.*T);
|
||||
if ((v.ap_data.*T) != 0) {
|
||||
P.min = std::min(P.min, (v.ap_data.*T));
|
||||
}
|
||||
P.max = std::min(P.max, (v.ap_data.*T));
|
||||
}
|
||||
P.avg = sum / (double)Values.size();
|
||||
}
|
||||
|
||||
template <typename X, typename M> void AverageRadioData( X T, const std::vector<M> &Values, AnalyticsObjects::AveragePoint &P) {
|
||||
if(Values.empty())
|
||||
return;
|
||||
double sum = 0.0;
|
||||
uint32_t num_values = 0;
|
||||
for(const auto &value:Values) {
|
||||
for(const auto &radio:value.radio_data) {
|
||||
num_values++;
|
||||
sum += (radio.*T);
|
||||
if((radio.*T)!=0) {
|
||||
P.min = std::min((double) P.min, (double) (radio.*T));
|
||||
}
|
||||
P.max = std::max((double)P.max, (double)(radio.*T));
|
||||
}
|
||||
}
|
||||
if(num_values)
|
||||
P.avg = sum / (double) num_values;
|
||||
else
|
||||
P.avg = 0.0;
|
||||
}
|
||||
template <typename X, typename M>
|
||||
void AverageRadioData(X T, const std::vector<M> &Values, AnalyticsObjects::AveragePoint &P) {
|
||||
if (Values.empty())
|
||||
return;
|
||||
double sum = 0.0;
|
||||
uint32_t num_values = 0;
|
||||
for (const auto &value : Values) {
|
||||
for (const auto &radio : value.radio_data) {
|
||||
num_values++;
|
||||
sum += (radio.*T);
|
||||
if ((radio.*T) != 0) {
|
||||
P.min = std::min((double)P.min, (double)(radio.*T));
|
||||
}
|
||||
P.max = std::max((double)P.max, (double)(radio.*T));
|
||||
}
|
||||
}
|
||||
if (num_values)
|
||||
P.avg = sum / (double)num_values;
|
||||
else
|
||||
P.avg = 0.0;
|
||||
}
|
||||
|
||||
static void NewSort(const AnalyticsObjects::DeviceTimePointList &l,split_points &sp) {
|
||||
static void NewSort(const AnalyticsObjects::DeviceTimePointList &l, split_points &sp) {
|
||||
|
||||
struct {
|
||||
bool operator()(const AnalyticsObjects::DeviceTimePoint &lhs, const AnalyticsObjects::DeviceTimePoint &rhs) const {
|
||||
if (lhs.device_info.serialNumber < rhs.device_info.serialNumber) return true;
|
||||
if (lhs.device_info.serialNumber > rhs.device_info.serialNumber) return false;
|
||||
return lhs.timestamp < rhs.timestamp;
|
||||
}
|
||||
} sort_serial_ts;
|
||||
struct {
|
||||
bool operator()(const AnalyticsObjects::DeviceTimePoint &lhs,
|
||||
const AnalyticsObjects::DeviceTimePoint &rhs) const {
|
||||
if (lhs.device_info.serialNumber < rhs.device_info.serialNumber)
|
||||
return true;
|
||||
if (lhs.device_info.serialNumber > rhs.device_info.serialNumber)
|
||||
return false;
|
||||
return lhs.timestamp < rhs.timestamp;
|
||||
}
|
||||
} sort_serial_ts;
|
||||
|
||||
// attempt at finding an interval
|
||||
AnalyticsObjects::DeviceTimePointList tmp{l};
|
||||
std::sort(tmp.points.begin(),tmp.points.end(),sort_serial_ts);
|
||||
// attempt at finding an interval
|
||||
AnalyticsObjects::DeviceTimePointList tmp{l};
|
||||
std::sort(tmp.points.begin(), tmp.points.end(), sort_serial_ts);
|
||||
|
||||
std::string cur_ser;
|
||||
std::uint64_t cur_int=0,start_val, last_val, first_val = 0;
|
||||
for(const auto &point:tmp.points) {
|
||||
if(cur_ser.empty()) {
|
||||
start_val = point.timestamp;
|
||||
cur_ser = point.serialNumber;
|
||||
first_val = point.timestamp;
|
||||
continue;
|
||||
}
|
||||
std::string cur_ser;
|
||||
std::uint64_t cur_int = 0, start_val, last_val, first_val = 0;
|
||||
for (const auto &point : tmp.points) {
|
||||
if (cur_ser.empty()) {
|
||||
start_val = point.timestamp;
|
||||
cur_ser = point.serialNumber;
|
||||
first_val = point.timestamp;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(cur_ser==point.serialNumber) {
|
||||
auto this_int = point.timestamp - start_val;
|
||||
if(cur_int) {
|
||||
if(this_int<cur_int) {
|
||||
cur_int = this_int;
|
||||
}
|
||||
} else {
|
||||
cur_int = this_int;
|
||||
}
|
||||
start_val = point.timestamp;
|
||||
} else {
|
||||
cur_ser = point.serialNumber;
|
||||
start_val = point.timestamp;
|
||||
}
|
||||
last_val = point.timestamp;
|
||||
}
|
||||
if (cur_ser == point.serialNumber) {
|
||||
auto this_int = point.timestamp - start_val;
|
||||
if (cur_int) {
|
||||
if (this_int < cur_int) {
|
||||
cur_int = this_int;
|
||||
}
|
||||
} else {
|
||||
cur_int = this_int;
|
||||
}
|
||||
start_val = point.timestamp;
|
||||
} else {
|
||||
cur_ser = point.serialNumber;
|
||||
start_val = point.timestamp;
|
||||
}
|
||||
last_val = point.timestamp;
|
||||
}
|
||||
|
||||
// std::cout << "Intervals: " << cur_int << std::endl;
|
||||
// std::cout << "Intervals: " << cur_int << std::endl;
|
||||
|
||||
std::vector<std::pair<std::uint64_t,std::uint64_t>> time_slots; // timeslot 0 has <t1,t2>
|
||||
std::vector<std::set<std::string>> serial_numbers; // serial number already in a timeslot.
|
||||
std::vector<std::pair<std::uint64_t, std::uint64_t>> time_slots; // timeslot 0 has <t1,t2>
|
||||
std::vector<std::set<std::string>> serial_numbers; // serial number already in a timeslot.
|
||||
|
||||
std::uint64_t cur_first = first_val, cur_end = 0;
|
||||
sp.clear();
|
||||
while (cur_end < last_val) {
|
||||
std::pair<std::uint64_t, std::uint64_t> e;
|
||||
e.first = cur_first;
|
||||
e.second = e.first + cur_int - 1;
|
||||
cur_first = e.second + 1;
|
||||
cur_end = e.second;
|
||||
time_slots.emplace_back(e);
|
||||
std::set<std::string> q;
|
||||
serial_numbers.emplace_back(q);
|
||||
std::vector<AnalyticsObjects::DeviceTimePoint> qq;
|
||||
sp.emplace_back(qq);
|
||||
}
|
||||
|
||||
std::uint64_t cur_first=first_val,cur_end=0;
|
||||
sp.clear();
|
||||
while(cur_end<last_val) {
|
||||
std::pair<std::uint64_t,std::uint64_t> e;
|
||||
e.first = cur_first;
|
||||
e.second = e.first + cur_int-1;
|
||||
cur_first = e.second+1;
|
||||
cur_end = e.second;
|
||||
time_slots.emplace_back(e);
|
||||
std::set<std::string> q;
|
||||
serial_numbers.emplace_back(q);
|
||||
std::vector<AnalyticsObjects::DeviceTimePoint> qq;
|
||||
sp.emplace_back(qq);
|
||||
}
|
||||
for (const auto &point : tmp.points) {
|
||||
std::uint64_t slot_index = 0;
|
||||
for (const auto &slot : time_slots) {
|
||||
if (point.timestamp >= slot.first && point.timestamp <= slot.second) {
|
||||
serial_numbers[slot_index].insert(point.serialNumber);
|
||||
sp[slot_index].emplace_back(point);
|
||||
}
|
||||
slot_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto &point:tmp.points) {
|
||||
std::uint64_t slot_index=0;
|
||||
for(const auto &slot:time_slots) {
|
||||
if(point.timestamp >= slot.first && point.timestamp <= slot.second) {
|
||||
serial_numbers[slot_index].insert(point.serialNumber);
|
||||
sp[slot_index].emplace_back(point);
|
||||
}
|
||||
slot_index++;
|
||||
}
|
||||
}
|
||||
void RESTAPI_board_timepoint_handler::DoGet() {
|
||||
auto id = GetBinding("id", "");
|
||||
if (id.empty() || !Utils::ValidUUID(id)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUUID);
|
||||
}
|
||||
|
||||
}
|
||||
AnalyticsObjects::BoardInfo B;
|
||||
if (!StorageService()->BoardsDB().GetRecord("id", id, B)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_board_timepoint_handler::DoGet() {
|
||||
auto id = GetBinding("id","");
|
||||
if(id.empty() || !Utils::ValidUUID(id)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUUID);
|
||||
}
|
||||
auto fromDate = GetParameter("fromDate", 0);
|
||||
auto endDate = GetParameter("endDate", 0);
|
||||
std::uint64_t maxRecords;
|
||||
if (Request->has("limit"))
|
||||
maxRecords = QB_.Limit;
|
||||
else
|
||||
maxRecords = GetParameter("maxRecords", 1000);
|
||||
|
||||
AnalyticsObjects::BoardInfo B;
|
||||
if(!StorageService()->BoardsDB().GetRecord("id",id,B)) {
|
||||
return NotFound();
|
||||
}
|
||||
auto statsOnly = GetBoolParameter("statsOnly");
|
||||
auto pointsOnly = GetBoolParameter("pointsOnly");
|
||||
auto pointsStatsOnly = GetBoolParameter("pointsStatsOnly");
|
||||
|
||||
auto fromDate = GetParameter("fromDate",0);
|
||||
auto endDate = GetParameter("endDate",0);
|
||||
std::uint64_t maxRecords;
|
||||
if(Request->has("limit"))
|
||||
maxRecords = QB_.Limit;
|
||||
else
|
||||
maxRecords = GetParameter("maxRecords",1000);
|
||||
if (statsOnly) {
|
||||
AnalyticsObjects::DeviceTimePointStats DTPS;
|
||||
Poco::JSON::Object Answer;
|
||||
DB_.GetStats(id, DTPS);
|
||||
DTPS.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
auto statsOnly = GetBoolParameter("statsOnly");
|
||||
auto pointsOnly = GetBoolParameter("pointsOnly");
|
||||
auto pointsStatsOnly = GetBoolParameter("pointsStatsOnly");
|
||||
AnalyticsObjects::DeviceTimePointList Points;
|
||||
StorageService()->TimePointsDB().SelectRecords(id, fromDate, endDate, maxRecords,
|
||||
Points.points);
|
||||
std::cout << "1 MaxRecords=" << maxRecords << " retrieved=" << Points.points.size()
|
||||
<< std::endl;
|
||||
|
||||
if(statsOnly) {
|
||||
AnalyticsObjects::DeviceTimePointStats DTPS;
|
||||
Poco::JSON::Object Answer;
|
||||
DB_.GetStats(id,DTPS);
|
||||
DTPS.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
split_points sp;
|
||||
|
||||
AnalyticsObjects::DeviceTimePointList Points;
|
||||
StorageService()->TimePointsDB().SelectRecords(id,fromDate, endDate, maxRecords, Points.points);
|
||||
std::cout << "1 MaxRecords=" << maxRecords << " retrieved=" << Points.points.size() << std::endl;
|
||||
NewSort(Points, sp);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
split_points sp;
|
||||
Poco::JSON::Object Answer;
|
||||
if (!pointsStatsOnly) {
|
||||
Poco::JSON::Array Points_OuterArray;
|
||||
for (const auto &point_list : sp) {
|
||||
Poco::JSON::Array Points_InnerArray;
|
||||
for (const auto &point : point_list) {
|
||||
Poco::JSON::Object O;
|
||||
point.to_json(O);
|
||||
Points_InnerArray.add(O);
|
||||
}
|
||||
Points_OuterArray.add(Points_InnerArray);
|
||||
}
|
||||
Answer.set("points", Points_OuterArray);
|
||||
}
|
||||
|
||||
NewSort(Points,sp);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
// calculate the stats for each time slot
|
||||
if (!pointsOnly) {
|
||||
Poco::JSON::Array Stats_Array;
|
||||
for (const auto &point_list : sp) {
|
||||
AnalyticsObjects::DeviceTimePointAnalysis DTPA;
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
if(!pointsStatsOnly) {
|
||||
Poco::JSON::Array Points_OuterArray;
|
||||
for (const auto &point_list:sp) {
|
||||
Poco::JSON::Array Points_InnerArray;
|
||||
for (const auto &point: point_list) {
|
||||
Poco::JSON::Object O;
|
||||
point.to_json(O);
|
||||
Points_InnerArray.add(O);
|
||||
}
|
||||
Points_OuterArray.add(Points_InnerArray);
|
||||
}
|
||||
Answer.set("points",Points_OuterArray);
|
||||
}
|
||||
if (point_list.empty())
|
||||
continue;
|
||||
|
||||
// calculate the stats for each time slot
|
||||
if(!pointsOnly) {
|
||||
Poco::JSON::Array Stats_Array;
|
||||
for (const auto &point_list:sp) {
|
||||
AnalyticsObjects::DeviceTimePointAnalysis DTPA;
|
||||
DTPA.timestamp = point_list[0].timestamp;
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_bytes_bw, point_list,
|
||||
DTPA.tx_bytes_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_bytes_bw, point_list,
|
||||
DTPA.rx_bytes_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_dropped_pct, point_list,
|
||||
DTPA.rx_dropped_pct);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_dropped_pct, point_list,
|
||||
DTPA.tx_dropped_pct);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_packets_bw, point_list,
|
||||
DTPA.rx_packets_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_packets_bw, point_list,
|
||||
DTPA.tx_packets_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_errors_pct, point_list,
|
||||
DTPA.rx_errors_pct);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_errors_pct, point_list,
|
||||
DTPA.tx_errors_pct);
|
||||
|
||||
if(point_list.empty())
|
||||
continue;
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::noise, point_list, DTPA.noise);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::temperature, point_list,
|
||||
DTPA.temperature);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::tx_power, point_list,
|
||||
DTPA.tx_power);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::active_pct, point_list,
|
||||
DTPA.active_pct);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::busy_pct, point_list,
|
||||
DTPA.busy_pct);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::receive_pct, point_list,
|
||||
DTPA.receive_pct);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::transmit_pct, point_list,
|
||||
DTPA.transmit_pct);
|
||||
|
||||
DTPA.timestamp = point_list[0].timestamp;
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_bytes_bw, point_list, DTPA.tx_bytes_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_bytes_bw, point_list, DTPA.rx_bytes_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_dropped_pct, point_list, DTPA.rx_dropped_pct);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_dropped_pct, point_list, DTPA.tx_dropped_pct);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_packets_bw, point_list, DTPA.rx_packets_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_packets_bw, point_list, DTPA.tx_packets_bw);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::rx_errors_pct, point_list, DTPA.rx_errors_pct);
|
||||
AverageAPData(&AnalyticsObjects::APTimePoint::tx_errors_pct, point_list, DTPA.tx_errors_pct);
|
||||
Poco::JSON::Object Stats_point;
|
||||
DTPA.to_json(Stats_point);
|
||||
Stats_Array.add(Stats_point);
|
||||
}
|
||||
Answer.set("stats", Stats_Array);
|
||||
}
|
||||
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::noise, point_list, DTPA.noise);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::temperature, point_list, DTPA.temperature);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::tx_power, point_list, DTPA.tx_power);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::active_pct, point_list, DTPA.active_pct);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::busy_pct, point_list, DTPA.busy_pct);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::receive_pct, point_list, DTPA.receive_pct);
|
||||
AverageRadioData(&AnalyticsObjects::RadioTimePoint::transmit_pct, point_list, DTPA.transmit_pct);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
Poco::JSON::Object Stats_point;
|
||||
DTPA.to_json(Stats_point);
|
||||
Stats_Array.add(Stats_point);
|
||||
}
|
||||
Answer.set("stats", Stats_Array);
|
||||
}
|
||||
void RESTAPI_board_timepoint_handler::DoDelete() {
|
||||
auto id = GetBinding("id", "");
|
||||
if (id.empty() || !Utils::ValidUUID(id)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUUID);
|
||||
}
|
||||
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
AnalyticsObjects::BoardInfo B;
|
||||
if (!StorageService()->BoardsDB().GetRecord("id", id, B)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_board_timepoint_handler::DoDelete() {
|
||||
auto id = GetBinding("id","");
|
||||
if(id.empty() || !Utils::ValidUUID(id)) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUUID);
|
||||
}
|
||||
auto fromDate = GetParameter("fromDate", 0);
|
||||
auto endDate = GetParameter("endDate", 0);
|
||||
|
||||
AnalyticsObjects::BoardInfo B;
|
||||
if(!StorageService()->BoardsDB().GetRecord("id",id,B)) {
|
||||
return NotFound();
|
||||
}
|
||||
StorageService()->TimePointsDB().DeleteTimeLine(id, fromDate, endDate);
|
||||
return OK();
|
||||
}
|
||||
|
||||
auto fromDate = GetParameter("fromDate",0);
|
||||
auto endDate = GetParameter("endDate",0);
|
||||
|
||||
StorageService()->TimePointsDB().DeleteTimeLine(id,fromDate,endDate);
|
||||
return OK();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace OpenWifi
|
||||
Reference in New Issue
Block a user