mirror of
https://github.com/Telecominfraproject/wlan-cloud-analytics.git
synced 2026-03-20 03:39:59 +00:00
Compare commits
57 Commits
release/v2
...
v2.7.0-RC1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a568fce901 | ||
|
|
6e2a21c831 | ||
|
|
da8a9e14cf | ||
|
|
075b83a7d5 | ||
|
|
3c35ec1523 | ||
|
|
b65f33c975 | ||
|
|
cbd5b09cdf | ||
|
|
0a145c8501 | ||
|
|
2ed88569d0 | ||
|
|
58c2269893 | ||
|
|
a708cc2be0 | ||
|
|
9c8f7ed6f9 | ||
|
|
b79a3b6c12 | ||
|
|
2c3b7711b3 | ||
|
|
831e144869 | ||
|
|
67910c982a | ||
|
|
9be196ce40 | ||
|
|
222afe2858 | ||
|
|
40a02c4752 | ||
|
|
7f1577503f | ||
|
|
7ab2e6c96e | ||
|
|
639db8631e | ||
|
|
9fe9b74dea | ||
|
|
20c025f994 | ||
|
|
ee78155b68 | ||
|
|
9f9a866ad3 | ||
|
|
adbd852ccd | ||
|
|
4bb5ee0b86 | ||
|
|
06bb8cebbe | ||
|
|
dde46ce6b2 | ||
|
|
515f8a4fea | ||
|
|
8dcfe04310 | ||
|
|
5db6fc3027 | ||
|
|
8049291138 | ||
|
|
613fa2e2bb | ||
|
|
eb9a748836 | ||
|
|
6ee3cae1db | ||
|
|
33e4f8abd8 | ||
|
|
d5b4d15307 | ||
|
|
e01f985974 | ||
|
|
8dc3e53fc0 | ||
|
|
52e1bf8817 | ||
|
|
a8b0028af6 | ||
|
|
7976602d17 | ||
|
|
55b0075c0c | ||
|
|
1da468e52c | ||
|
|
fa434f79c3 | ||
|
|
d396a104ff | ||
|
|
61837a8975 | ||
|
|
c1f06ec784 | ||
|
|
10ffba95b5 | ||
|
|
fd3a6be11a | ||
|
|
ec2874748f | ||
|
|
432d0ed52b | ||
|
|
fe247c6093 | ||
|
|
4c1daf84cf | ||
|
|
1d4aa80205 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -32,6 +32,7 @@
|
||||
*.app
|
||||
|
||||
test_scripts/curl/token.json
|
||||
test_scripts/curl/result.json
|
||||
.vscode/c_cpp_properties.json
|
||||
test_scripts/curl/result.json
|
||||
*.swp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owanalytics VERSION 2.6.0)
|
||||
project(owanalytics VERSION 2.7.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_GENERATOR "Unix Makefiles")
|
||||
|
||||
54
Dockerfile
54
Dockerfile
@@ -1,4 +1,10 @@
|
||||
FROM alpine:3.15 AS build-base
|
||||
ARG ALPINE_VERSION=3.16.2
|
||||
ARG POCO_VERSION=poco-tip-v1
|
||||
ARG FMTLIB_VERSION=9.0.0
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||
|
||||
FROM alpine:$ALPINE_VERSION AS build-base
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
make cmake g++ git \
|
||||
@@ -9,8 +15,10 @@ RUN apk add --update --no-cache \
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -19,10 +27,26 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ARG FMTLIB_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS cppkafka-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -33,8 +57,10 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
@@ -43,18 +69,6 @@ RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS owanalytics-build
|
||||
|
||||
ADD CMakeLists.txt build /owanalytics/
|
||||
@@ -77,7 +91,7 @@ WORKDIR /owanalytics/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine:3.15
|
||||
FROM alpine:$ALPINE_VERSION
|
||||
|
||||
ENV OWANALYTICS_USER=owanalytics \
|
||||
OWANALYTICS_ROOT=/owanalytics-data \
|
||||
|
||||
2
helm/.gitignore
vendored
2
helm/.gitignore
vendored
@@ -1 +1,3 @@
|
||||
*.swp
|
||||
Chart.lock
|
||||
charts/
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -46,6 +47,39 @@ spec:
|
||||
- -timeout
|
||||
- 600s
|
||||
|
||||
{{- if eq $storageType "postgresql" }}
|
||||
- name: wait-postgres
|
||||
image: "{{ .Values.images.owanalytics.repository }}:{{ .Values.images.owanalytics.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owanalytics.pullPolicy }}
|
||||
command:
|
||||
- /wait-for-postgres.sh
|
||||
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
|
||||
- echo
|
||||
- "PostgreSQL is ready"
|
||||
env:
|
||||
- name: KUBERNETES_DEPLOYED
|
||||
value: "{{ now }}"
|
||||
{{- range $key, $value := .Values.public_env_variables }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := .Values.secret_env_variables }}
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "owanalytics.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owanalytics }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
subPath: {{ .subPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
containers:
|
||||
|
||||
- name: owanalytics
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owanalytics:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owanalytics
|
||||
tag: v2.6.0
|
||||
tag: v2.7.0-RC1
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
|
||||
@@ -27,71 +27,13 @@ components:
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||
Unauthorized:
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||
Success:
|
||||
description: The requested operation was performed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
Operation:
|
||||
type: string
|
||||
Details:
|
||||
type: string
|
||||
Code:
|
||||
type: integer
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||
BadRequest:
|
||||
description: The requested operation failed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: integer
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||
|
||||
schemas:
|
||||
ObjectInfo:
|
||||
@@ -1134,42 +1076,6 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
|
||||
/iptocountry:
|
||||
get:
|
||||
tags:
|
||||
- Utility
|
||||
summary: Get the country code for an IP address
|
||||
operationId: getIpToCountry
|
||||
parameters:
|
||||
- in: query
|
||||
name: iplist
|
||||
schema:
|
||||
type: string
|
||||
example:
|
||||
10.2.2.2,10.3.4.3
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
description: List of country codes.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
countryCodes:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/wifiClientHistory:
|
||||
get:
|
||||
tags:
|
||||
|
||||
@@ -158,6 +158,7 @@ namespace OpenWifi {
|
||||
auto interfaces = (*State)["interfaces"];
|
||||
DI_.associations_2g = DI_.associations_5g = DI_.associations_6g = 0;
|
||||
for(const auto &interface:interfaces) {
|
||||
std::string InterfaceName = fmt::format("{}: {}", DI_.serialNumber, interface.contains("name") ? to_string(interface["name"]) : "unknown");
|
||||
if(interface.contains("counters")) {
|
||||
auto counters = interface["counters"];
|
||||
GetJSON("collisions", counters, DTP.ap_data.collisions, (uint64_t) 0);
|
||||
@@ -172,6 +173,34 @@ namespace OpenWifi {
|
||||
GetJSON("tx_packets", counters, DTP.ap_data.tx_packets, (uint64_t) 0);
|
||||
}
|
||||
|
||||
InterfaceClientEntryMap_t ICEM;
|
||||
if(interface.contains("clients") && interface["clients"].is_array()) {
|
||||
try {
|
||||
auto Clients = interface["clients"];
|
||||
for(const auto & client: Clients) {
|
||||
if(client.contains("mac") && client["mac"].is_string()) {
|
||||
InterfaceClientEntry E;
|
||||
if(client.contains("ipv4_addresses") && client["ipv4_addresses"].is_array()) {
|
||||
for(const auto &ip:client["ipv4_addresses"]) {
|
||||
E.ipv4_addresses.push_back(ip);
|
||||
}
|
||||
}
|
||||
if(client.contains("ipv6_addresses") && client["ipv6_addresses"].is_array()) {
|
||||
for(const auto &ip:client["ipv6_addresses"]) {
|
||||
E.ipv6_addresses.push_back(ip);
|
||||
}
|
||||
}
|
||||
auto M = mac_filter(client["mac"]);
|
||||
ICEM[M] = E;
|
||||
}
|
||||
}
|
||||
} catch(...) {
|
||||
std::cout << "Exception will parsing clients: " << InterfaceName << std::endl;
|
||||
}
|
||||
} else {
|
||||
// std::cout <<"Interface: No clients: " << InterfaceName << std::endl;
|
||||
}
|
||||
|
||||
if(interface.contains("ssids")) {
|
||||
auto ssids = interface["ssids"];
|
||||
for (const auto &ssid: ssids) {
|
||||
@@ -243,8 +272,19 @@ namespace OpenWifi {
|
||||
GetJSON("rx_packets",association,WFH.rx_packets,(uint64_t)0);
|
||||
GetJSON("tx_packets",association,WFH.tx_packets,(uint64_t)0);
|
||||
|
||||
WFH.ipv4 = "---";
|
||||
WFH.ipv6 = "----";
|
||||
// try to locate the IP addresses
|
||||
auto ClientInfo = ICEM.find(WFH.station_id);
|
||||
if(ClientInfo!=end(ICEM)) {
|
||||
if(!ClientInfo->second.ipv4_addresses.empty()) {
|
||||
WFH.ipv4 = ClientInfo->second.ipv4_addresses[0];
|
||||
}
|
||||
if(!ClientInfo->second.ipv6_addresses.empty()) {
|
||||
WFH.ipv6 = ClientInfo->second.ipv6_addresses[0];
|
||||
}
|
||||
std::cout << __LINE__ << ": " << InterfaceName << " Mac Found: " << ICEM.size() << " entries. " << WFH.station_id << std::endl;
|
||||
} else {
|
||||
std::cout << __LINE__ << ": " << InterfaceName << " Mac NOT found: " << ICEM.size() << " entries. " << WFH.station_id << std::endl;
|
||||
}
|
||||
|
||||
for(const auto &rd:DTP.radio_data) {
|
||||
if(rd.band == SSIDTP.band) {
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
struct InterfaceClientEntry {
|
||||
std::vector<std::string> ipv4_addresses;
|
||||
std::vector<std::string> ipv6_addresses;
|
||||
};
|
||||
|
||||
using InterfaceClientEntryMap_t = std::map<std::string,InterfaceClientEntry>;
|
||||
|
||||
class AP {
|
||||
public:
|
||||
explicit AP(uint64_t mac, const std::string &venue_id, const std::string &BoardId, Poco::Logger &L) :
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if(StorageService()->BoardsDB().UpdateRecord("id",Existing.info.id,Existing)) {
|
||||
VenueCoordinator()->ModifyBoard(Existing.info.id);
|
||||
VenueCoordinator()->UpdateBoard(Existing.info.id);
|
||||
AnalyticsObjects::BoardInfo NewBoard;
|
||||
StorageService()->BoardsDB().GetRecord("id",Existing.info.id,NewBoard);
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
@@ -5,54 +5,11 @@
|
||||
#include "RESTAPI_board_timepoint_handler.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenWifi {
|
||||
static auto find_number_of_buckets(std::vector<AnalyticsObjects::DeviceTimePoint> &p) {
|
||||
uint32_t buckets=0,cur_buckets=0;
|
||||
std::string current_serialNumber;
|
||||
for(const auto &i:p) {
|
||||
if(current_serialNumber.empty()) {
|
||||
current_serialNumber = i.device_info.serialNumber;
|
||||
cur_buckets=0;
|
||||
}
|
||||
if(current_serialNumber==i.device_info.serialNumber) {
|
||||
cur_buckets++;
|
||||
} else {
|
||||
buckets = std::max(buckets,cur_buckets);
|
||||
current_serialNumber=i.device_info.serialNumber;
|
||||
cur_buckets=1;
|
||||
}
|
||||
}
|
||||
return std::max(buckets,cur_buckets);
|
||||
}
|
||||
|
||||
typedef std::vector< std::vector<AnalyticsObjects::DeviceTimePoint>> split_points;
|
||||
|
||||
static void split_in_buckets([[maybe_unused]] uint32_t buckets,std::vector<AnalyticsObjects::DeviceTimePoint> &p,split_points &sp) {
|
||||
std::string cur_sn;
|
||||
uint32_t cur_bucket=0;
|
||||
for(const auto &i:p) {
|
||||
if(cur_sn.empty()) {
|
||||
cur_bucket=1;
|
||||
cur_sn=i.device_info.serialNumber;
|
||||
}
|
||||
if(cur_sn==i.device_info.serialNumber) {
|
||||
if (cur_bucket>sp.size()) {
|
||||
std::vector<AnalyticsObjects::DeviceTimePoint> tmp_p;
|
||||
tmp_p.push_back(i);
|
||||
sp.push_back(tmp_p);
|
||||
cur_bucket++;
|
||||
} else {
|
||||
sp[cur_bucket-1].push_back(i);
|
||||
cur_bucket++;
|
||||
}
|
||||
} else {
|
||||
cur_bucket=1;
|
||||
sp[cur_bucket-1].push_back(i);
|
||||
cur_bucket++;
|
||||
cur_sn=i.device_info.serialNumber;
|
||||
}
|
||||
}
|
||||
}
|
||||
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())
|
||||
@@ -89,6 +46,81 @@ namespace OpenWifi {
|
||||
P.avg = 0.0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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::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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
@@ -102,7 +134,12 @@ namespace OpenWifi {
|
||||
|
||||
auto fromDate = GetParameter("fromDate",0);
|
||||
auto endDate = GetParameter("endDate",0);
|
||||
auto maxRecords = GetParameter("maxRecords",1000);
|
||||
std::uint64_t maxRecords;
|
||||
if(Request->has("limit"))
|
||||
maxRecords = QB_.Limit;
|
||||
else
|
||||
maxRecords = GetParameter("maxRecords",1000);
|
||||
|
||||
auto statsOnly = GetBoolParameter("statsOnly");
|
||||
auto pointsOnly = GetBoolParameter("pointsOnly");
|
||||
auto pointsStatsOnly = GetBoolParameter("pointsStatsOnly");
|
||||
@@ -115,71 +152,39 @@ namespace OpenWifi {
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
auto Points = std::make_unique<AnalyticsObjects::DeviceTimePointList>();
|
||||
StorageService()->TimePointsDB().SelectRecords(id,fromDate, endDate, maxRecords, Points->points);
|
||||
AnalyticsObjects::DeviceTimePointList Points;
|
||||
StorageService()->TimePointsDB().SelectRecords(id,fromDate, endDate, maxRecords, Points.points);
|
||||
std::cout << "1 MaxRecords=" << maxRecords << " retrieved=" << Points.points.size() << std::endl;
|
||||
|
||||
// sort by timestamp & serial number.
|
||||
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;
|
||||
}
|
||||
} DeviceTimePoint_sort;
|
||||
split_points sp;
|
||||
|
||||
struct {
|
||||
bool operator()(const AnalyticsObjects::SSIDTimePoint &lhs, const AnalyticsObjects::SSIDTimePoint &rhs) const {
|
||||
if(lhs.ssid < rhs.ssid) return true;
|
||||
if(lhs.ssid > rhs.ssid) return false;
|
||||
return lhs.bssid < rhs.bssid;
|
||||
}
|
||||
} SSID_sort;
|
||||
NewSort(Points,sp);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
struct {
|
||||
bool operator()(const AnalyticsObjects::UETimePoint &lhs, const AnalyticsObjects::UETimePoint &rhs) const {
|
||||
if(lhs.station < rhs.station) return true;
|
||||
return false;
|
||||
}
|
||||
} Association_sort;
|
||||
|
||||
std::sort( Points->points.begin(), Points->points.end(), DeviceTimePoint_sort);
|
||||
auto BucketsNeeded = find_number_of_buckets(Points->points);
|
||||
|
||||
auto sp = std::make_unique<split_points>();
|
||||
split_in_buckets(BucketsNeeded,Points->points, *sp);
|
||||
// must sort each bucket according to serial number.
|
||||
for(auto &i: *sp) {
|
||||
std::sort(i.begin(),i.end(),DeviceTimePoint_sort);
|
||||
// now sort according to UEs within a block
|
||||
for(auto &j:i) {
|
||||
std::sort(j.ssid_data.begin(),j.ssid_data.end(),SSID_sort);
|
||||
for(auto &k:j.ssid_data) {
|
||||
std::sort(k.associations.begin(),k.associations.end(),Association_sort);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Answer = std::make_unique<Poco::JSON::Object>();
|
||||
Poco::JSON::Object Answer;
|
||||
if(!pointsStatsOnly) {
|
||||
auto Points_OuterArray = std::make_unique<Poco::JSON::Array>();
|
||||
for (const auto &point_list:*sp) {
|
||||
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);
|
||||
Points_OuterArray.add(Points_InnerArray);
|
||||
}
|
||||
Answer->set("points",*Points_OuterArray);
|
||||
Answer.set("points",Points_OuterArray);
|
||||
}
|
||||
|
||||
// calculate the stats for each time slot
|
||||
if(!pointsOnly) {
|
||||
auto Stats_Array = std::make_unique<Poco::JSON::Array>();
|
||||
for (const auto &point_list:*sp) {
|
||||
Poco::JSON::Array Stats_Array;
|
||||
for (const auto &point_list:sp) {
|
||||
AnalyticsObjects::DeviceTimePointAnalysis DTPA;
|
||||
|
||||
if(point_list.empty())
|
||||
continue;
|
||||
|
||||
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);
|
||||
@@ -200,12 +205,12 @@ namespace OpenWifi {
|
||||
|
||||
Poco::JSON::Object Stats_point;
|
||||
DTPA.to_json(Stats_point);
|
||||
Stats_Array->add(Stats_point);
|
||||
Stats_Array.add(Stats_point);
|
||||
}
|
||||
Answer->set("stats", *Stats_Array);
|
||||
Answer.set("stats", Stats_Array);
|
||||
}
|
||||
|
||||
return ReturnObject(*Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
void RESTAPI_board_timepoint_handler::DoDelete() {
|
||||
|
||||
@@ -20,10 +20,9 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if(GetBoolParameter("macsOnly")) {
|
||||
|
||||
auto macFilter = GetParameter("macFilter","");
|
||||
std::vector<uint64_t> Macs;
|
||||
WifiClientCache()->FindNumbers(venue,macFilter,500,Macs);
|
||||
WifiClientCache()->FindNumbers(venue,macFilter,QB_.Offset, QB_.Limit, Macs);
|
||||
Poco::JSON::Array Arr;
|
||||
for(const auto &mac: Macs)
|
||||
Arr.add(Utils::IntToSerialNumber(mac));
|
||||
|
||||
@@ -13,9 +13,27 @@ namespace OpenWifi {
|
||||
int VenueCoordinator::Start() {
|
||||
GetBoardList();
|
||||
Worker_.start(*this);
|
||||
|
||||
ReconcileTimerCallback_ = std::make_unique<Poco::TimerCallback<VenueCoordinator>>(*this,&VenueCoordinator::onReconcileTimer);
|
||||
ReconcileTimerTimer_.setStartInterval( 3 * 60 * 1000 );
|
||||
ReconcileTimerTimer_.setPeriodicInterval(3 * 60 * 1000); // 1 hours
|
||||
ReconcileTimerTimer_.start(*ReconcileTimerCallback_, MicroService::instance().TimerPool());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VenueCoordinator::onReconcileTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Utils::SetThreadName("brd-refresh");
|
||||
|
||||
Logger().information("Starting to reconcile board information.");
|
||||
for(const auto &[board_id, watcher]:Watchers_) {
|
||||
Logger().information(fmt::format("Updating: {}", board_id));
|
||||
UpdateBoard(board_id);
|
||||
}
|
||||
Logger().information("Finished reconciling board information.");
|
||||
}
|
||||
|
||||
void VenueCoordinator::GetBoardList() {
|
||||
BoardsToWatch_.clear();
|
||||
auto F = [&](const AnalyticsObjects::BoardInfo &B) ->bool {
|
||||
@@ -59,9 +77,11 @@ namespace OpenWifi {
|
||||
|
||||
void VenueCoordinator::RetireBoard(const AnalyticsObjects::BoardInfo &B) {
|
||||
Logger().error(fmt::format("Venue board '{}' is no longer in the system. Retiring its associated board.", B.venueList[0].name));
|
||||
/*
|
||||
StopBoard(B.info.id);
|
||||
StorageService()->BoardsDB().DeleteRecord("id",B.info.id);
|
||||
StorageService()->TimePointsDB().DeleteRecords(fmt::format(" boardId='{}' ", B.info.id));
|
||||
*/
|
||||
}
|
||||
|
||||
bool VenueCoordinator::GetDevicesForBoard(const AnalyticsObjects::BoardInfo &B, std::vector<uint64_t> & Devices, bool & VenueExists) {
|
||||
@@ -119,7 +139,7 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void VenueCoordinator::ModifyBoard(const std::string &id) {
|
||||
void VenueCoordinator::UpdateBoard(const std::string &id) {
|
||||
AnalyticsObjects::BoardInfo B;
|
||||
if(StorageService()->BoardsDB().GetRecord("id",id,B)) {
|
||||
std::vector<uint64_t> Devices;
|
||||
@@ -130,15 +150,15 @@ namespace OpenWifi {
|
||||
if(it!=ExistingBoards_.end()) {
|
||||
if(it->second!=Devices) {
|
||||
auto it2 = Watchers_.find(id);
|
||||
if(it2!=Watchers_.end())
|
||||
if(it2!=Watchers_.end()) {
|
||||
it2->second->ModifySerialNumbers(Devices);
|
||||
}
|
||||
ExistingBoards_[id] = Devices;
|
||||
Logger().information(fmt::format("Modified board {}",B.info.name));
|
||||
} else {
|
||||
Logger().information(fmt::format("No device changes in board {}",B.info.name));
|
||||
}
|
||||
}
|
||||
Logger().information(fmt::format("Modified board {}",B.info.name));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "VenueWatcher.h"
|
||||
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class VenueCoordinator : public SubSystemServer, Poco::Runnable {
|
||||
@@ -21,7 +24,7 @@ namespace OpenWifi {
|
||||
void run() override;
|
||||
|
||||
void StopBoard(const std::string &id);
|
||||
void ModifyBoard(const std::string &id);
|
||||
void UpdateBoard(const std::string &id);
|
||||
void AddBoard(const std::string &id);
|
||||
|
||||
bool GetDevicesForBoard(const AnalyticsObjects::BoardInfo &B, std::vector<uint64_t> & Devices, bool & VenueExists);
|
||||
@@ -30,13 +33,17 @@ namespace OpenWifi {
|
||||
bool Watching(const std::string &id);
|
||||
void RetireBoard(const AnalyticsObjects::BoardInfo &B);
|
||||
|
||||
private:
|
||||
Poco::Thread Worker_;
|
||||
std::atomic_bool Running_=false;
|
||||
std::set<AnalyticsObjects::BoardInfo> BoardsToWatch_;
|
||||
std::map<std::string,std::shared_ptr<VenueWatcher>> Watchers_;
|
||||
void onReconcileTimer(Poco::Timer & timer);
|
||||
|
||||
std::map<std::string,std::vector<uint64_t>> ExistingBoards_;
|
||||
private:
|
||||
Poco::Thread Worker_;
|
||||
std::atomic_bool Running_=false;
|
||||
std::set<AnalyticsObjects::BoardInfo> BoardsToWatch_;
|
||||
std::map<std::string,std::shared_ptr<VenueWatcher>> Watchers_;
|
||||
std::unique_ptr<Poco::TimerCallback<VenueCoordinator>> ReconcileTimerCallback_;
|
||||
Poco::Timer ReconcileTimerTimer_;
|
||||
|
||||
std::map<std::string,std::vector<uint64_t>> ExistingBoards_;
|
||||
|
||||
VenueCoordinator() noexcept:
|
||||
SubSystemServer("VenueCoordinator", "VENUE-COORD", "venue.coordinator")
|
||||
|
||||
@@ -69,9 +69,11 @@ namespace OpenWifi {
|
||||
void GetDevices(std::vector<AnalyticsObjects::DeviceInfo> & DI);
|
||||
|
||||
void GetBandwidth(uint64_t start, uint64_t end, uint64_t interval , AnalyticsObjects::BandwidthAnalysis & BW);
|
||||
|
||||
inline std::string Venue() const {
|
||||
return venue_id_;
|
||||
}
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
std::mutex Mutex_;
|
||||
std::string boardId_;
|
||||
std::string venue_id_;
|
||||
Poco::NotificationQueue Queue_;
|
||||
|
||||
@@ -124,32 +124,36 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiClientCache::FindNumbers(const std::string &venue_id, const std::string &S, uint HowMany, std::vector<uint64_t> &A) {
|
||||
void WifiClientCache::FindNumbers(const std::string &venueId, const std::string &SerialNumber, std::uint64_t StartingOffset, std::uint64_t HowMany, std::vector<uint64_t> &A) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
A.clear();
|
||||
auto VenueIt = Cache_.find(venue_id);
|
||||
auto VenueIt = Cache_.find(venueId);
|
||||
if(VenueIt==Cache_.end())
|
||||
return;
|
||||
|
||||
if(S.empty()) {
|
||||
if(SerialNumber.empty()) {
|
||||
auto Start = VenueIt->second.SNs_.begin();
|
||||
std::uint64_t Offset=0;
|
||||
while(HowMany && Start!=VenueIt->second.SNs_.end()) {
|
||||
A.push_back(*Start);
|
||||
if(Offset>=StartingOffset) {
|
||||
A.push_back(*Start);
|
||||
HowMany--;
|
||||
}
|
||||
Start++;
|
||||
HowMany--;
|
||||
Offset++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (S[0] == '*') {
|
||||
if (SerialNumber[0] == '*') {
|
||||
std::string Reversed;
|
||||
std::copy(rbegin(S), rend(S)-1, std::back_inserter(Reversed));
|
||||
std::copy(rbegin(SerialNumber), rend(SerialNumber)-1, std::back_inserter(Reversed));
|
||||
if(Reversed.empty())
|
||||
return;
|
||||
return ReturnNumbers(Reversed, HowMany, VenueIt->second.Reverse_SNs_, A, true);
|
||||
} else {
|
||||
return ReturnNumbers(S, HowMany, VenueIt->second.SNs_, A, false);
|
||||
return ReturnNumbers(SerialNumber, HowMany, VenueIt->second.SNs_, A, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
void AddSerialNumber(const std::string &venueId, const std::string &SerialNumber);
|
||||
void DeleteSerialNumber(const std::string &venueId, const std::string &SerialNumber);
|
||||
void FindNumbers(const std::string &venueId, const std::string &SerialNumber, uint HowMany, std::vector<uint64_t> &A);
|
||||
void FindNumbers(const std::string &venueId, const std::string &SerialNumber, std::uint64_t start, std::uint64_t HowMany, std::vector<uint64_t> &A);
|
||||
inline bool NumberExists(const std::string &venueId, uint64_t SerialNumber) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Cache_.find(venueId);
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace OpenWifi {
|
||||
inline uint64_t Now() { return std::time(nullptr); };
|
||||
}
|
||||
|
||||
namespace OpenWifi::Utils {
|
||||
std::vector<unsigned char> base64decode(const std::string& input);
|
||||
std::string base64encode(const unsigned char *input, uint32_t size);
|
||||
}
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
@@ -238,6 +243,11 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
Obj.set(Field,Value);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) {
|
||||
auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size());
|
||||
Obj.set(Field,Result);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
|
||||
Poco::JSON::Array Array;
|
||||
for(const auto &i:S) {
|
||||
@@ -334,12 +344,12 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||
Value = (double) Obj->get(Field);
|
||||
Value = (double)Obj->get(Field);
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||
Value = (float) Obj->get(Field);
|
||||
Value = (float)Obj->get(Field);
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
|
||||
@@ -374,7 +384,14 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||
Value = (uint64_t ) Obj->get(Field);
|
||||
Value = (uint64_t)Obj->get(Field);
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(Field)) {
|
||||
auto Result = Utils::base64decode(Obj->get(Field).toString());
|
||||
Value.assignRaw((const unsigned char *)&Result[0],Result.size());
|
||||
}
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
|
||||
@@ -686,6 +703,19 @@ namespace OpenWifi::Utils {
|
||||
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0);
|
||||
}
|
||||
|
||||
template <typename ...Args> std::string ComputeHash(Args&&... args) {
|
||||
Poco::SHA2Engine E;
|
||||
auto as_string = [](auto p) {
|
||||
if constexpr(std::is_arithmetic_v<decltype(p)>) {
|
||||
return std::to_string(p);
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
};
|
||||
(E.update(as_string(args)),...);
|
||||
return Poco::SHA2Engine::digestToHex(E.digest());
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) {
|
||||
std::vector<std::string> ReturnList;
|
||||
|
||||
@@ -1382,13 +1412,14 @@ namespace OpenWifi {
|
||||
|
||||
[[nodiscard]] inline const std::string &Address() const { return address_; };
|
||||
[[nodiscard]] inline uint32_t Port() const { return port_; };
|
||||
[[nodiscard]] inline const std::string &KeyFile() const { return key_file_; };
|
||||
[[nodiscard]] inline const std::string &CertFile() const { return cert_file_; };
|
||||
[[nodiscard]] inline const std::string &RootCA() const { return root_ca_; };
|
||||
[[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; };
|
||||
[[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; };
|
||||
[[nodiscard]] inline const std::string &Name() const { return name_; };
|
||||
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
|
||||
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
|
||||
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
|
||||
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
|
||||
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
|
||||
[[nodiscard]] inline auto Name() const { return name_; };
|
||||
[[nodiscard]] inline int Backlog() const { return backlog_; }
|
||||
[[nodiscard]] inline auto Cas() const { return cas_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const {
|
||||
Poco::Net::Context::Params P;
|
||||
@@ -1868,8 +1899,8 @@ namespace OpenWifi {
|
||||
Request = &RequestIn;
|
||||
Response = &ResponseIn;
|
||||
|
||||
std::string th_name = "restsvr_" + std::to_string(TransactionId_);
|
||||
Utils::SetThreadName(th_name.c_str());
|
||||
// std::string th_name = "restsvr_" + std::to_string(TransactionId_);
|
||||
// Utils::SetThreadName(th_name.c_str());
|
||||
|
||||
if(Request->getContentLength()>0) {
|
||||
if(Request->getContentType().find("application/json")!=std::string::npos) {
|
||||
@@ -2064,6 +2095,17 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) {
|
||||
if(O->has(Field)) {
|
||||
std::string Content = O->get(Field).toString();
|
||||
auto DecodedBlob = Utils::base64decode(Content);
|
||||
Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
|
||||
if(O->has(Field)) {
|
||||
assignee = value;
|
||||
@@ -2404,6 +2446,7 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPServerResponse *Response= nullptr;
|
||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||
QueryBlock QB_;
|
||||
const std::string & Requester() const { return REST_Requester_; }
|
||||
protected:
|
||||
BindingMap Bindings_;
|
||||
Poco::URI::QueryParameters Parameters_;
|
||||
@@ -2420,6 +2463,7 @@ namespace OpenWifi {
|
||||
RateLimit MyRates_;
|
||||
uint64_t TransactionId_;
|
||||
Poco::JSON::Object::Ptr ParsedBody_;
|
||||
std::string REST_Requester_;
|
||||
};
|
||||
|
||||
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
||||
@@ -2684,7 +2728,7 @@ namespace OpenWifi {
|
||||
|
||||
inline void run() override {
|
||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||
Utils::SetThreadName("kafka-dispatch");
|
||||
Utils::SetThreadName("kafka:dispatch");
|
||||
while(Note && Running_) {
|
||||
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
|
||||
if(Msg!= nullptr) {
|
||||
@@ -2707,12 +2751,12 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
uint64_t FunctionId_=1;
|
||||
Poco::NotificationQueue Queue_;
|
||||
std::recursive_mutex Mutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
uint64_t FunctionId_=1;
|
||||
Poco::NotificationQueue Queue_;
|
||||
};
|
||||
|
||||
class KafkaManager : public SubSystemServer {
|
||||
@@ -2994,7 +3038,7 @@ namespace OpenWifi {
|
||||
}
|
||||
int Start() override;
|
||||
inline void Stop() override {
|
||||
Logger().information("Stopping ");
|
||||
Logger().information("Stopping...");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stop();
|
||||
Pool_.stopAll();
|
||||
@@ -3002,22 +3046,23 @@ namespace OpenWifi {
|
||||
RESTServers_.clear();
|
||||
}
|
||||
|
||||
|
||||
inline void reinitialize(Poco::Util::Application &self) override;
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
Utils::SetThreadName(fmt::format("rest_ext_{}",Id).c_str());
|
||||
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
|
||||
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
|
||||
}
|
||||
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_;
|
||||
Poco::ThreadPool Pool_{"x-rest",2,32};
|
||||
RESTAPI_GenericServer Server_;
|
||||
|
||||
RESTAPI_ExtServer() noexcept:
|
||||
SubSystemServer("RESTAPI_ExtServer", "RESTAPIServer", "openwifi.restapi"),
|
||||
Pool_("RESTAPI_ExtServer",4,50,120)
|
||||
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -3030,7 +3075,7 @@ namespace OpenWifi {
|
||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
||||
try {
|
||||
Poco::URI uri(Request.getURI());
|
||||
Utils::SetThreadName(fmt::format("rest_ext_{}",TransactionId_).c_str());
|
||||
Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str());
|
||||
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
|
||||
} catch (...) {
|
||||
|
||||
@@ -3128,7 +3173,7 @@ namespace OpenWifi {
|
||||
|
||||
inline int Start() override;
|
||||
inline void Stop() override {
|
||||
Logger().information("Stopping ");
|
||||
Logger().information("Stopping...");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stop();
|
||||
Pool_.stopAll();
|
||||
@@ -3139,17 +3184,18 @@ namespace OpenWifi {
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
Utils::SetThreadName(fmt::format("rest_int_{}",Id).c_str());
|
||||
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
|
||||
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
|
||||
}
|
||||
|
||||
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_;
|
||||
Poco::ThreadPool Pool_{"i-rest",2,16};
|
||||
RESTAPI_GenericServer Server_;
|
||||
|
||||
RESTAPI_IntServer() noexcept:
|
||||
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi"),
|
||||
Pool_("RESTAPI_IntServer",4,50,120)
|
||||
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi")
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -3160,6 +3206,7 @@ namespace OpenWifi {
|
||||
public:
|
||||
inline IntRequestHandlerFactory() = default;
|
||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
||||
Utils::SetThreadName(fmt::format("i-rest:{}",TransactionId_).c_str());
|
||||
Poco::URI uri(Request.getURI());
|
||||
return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_);
|
||||
}
|
||||
@@ -3203,7 +3250,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Version() { return Version_; }
|
||||
// [[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_; }
|
||||
@@ -3236,7 +3282,12 @@ namespace OpenWifi {
|
||||
return Poco::Logger::get(Name);
|
||||
}
|
||||
|
||||
static inline void Exit(int Reason);
|
||||
virtual void GetExtraConfiguration(Poco::JSON::Object & Cfg) {
|
||||
Cfg.set("additionalConfiguration",false);
|
||||
}
|
||||
|
||||
|
||||
static inline void Exit(int Reason);
|
||||
inline void BusMessageReceived(const std::string &Key, const std::string & Payload);
|
||||
inline MicroServiceMetaVec GetServices(const std::string & Type);
|
||||
inline MicroServiceMetaVec GetServices();
|
||||
@@ -3272,7 +3323,6 @@ namespace OpenWifi {
|
||||
inline std::string ConfigPath(const std::string &Key);
|
||||
inline std::string Encrypt(const std::string &S);
|
||||
inline std::string Decrypt(const std::string &S);
|
||||
inline std::string CreateHash(const std::string &S);
|
||||
inline std::string MakeSystemEventMessage( const std::string & Type ) const;
|
||||
[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
|
||||
inline static void SavePID();
|
||||
@@ -3302,6 +3352,9 @@ namespace OpenWifi {
|
||||
return Signer_.sign(T,Algo);
|
||||
}
|
||||
}
|
||||
|
||||
inline Poco::ThreadPool & TimerPool() { return TimerPool_; }
|
||||
|
||||
private:
|
||||
static MicroService * instance_;
|
||||
bool HelpRequested_ = false;
|
||||
@@ -3315,7 +3368,6 @@ namespace OpenWifi {
|
||||
std::string WWWAssetsDir_;
|
||||
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
|
||||
Poco::Crypto::Cipher * Cipher_ = nullptr;
|
||||
Poco::SHA2Engine SHA2_;
|
||||
MicroServiceMetaMap Services_;
|
||||
std::string MyHash_;
|
||||
std::string MyPrivateEndPoint_;
|
||||
@@ -3336,6 +3388,7 @@ namespace OpenWifi {
|
||||
bool NoBuiltInCrypto_=false;
|
||||
Poco::JWT::Signer Signer_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::ThreadPool TimerPool_{"timer:pool",2,16};
|
||||
};
|
||||
|
||||
inline void MicroService::Exit(int Reason) {
|
||||
@@ -3485,7 +3538,7 @@ namespace OpenWifi {
|
||||
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
|
||||
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
|
||||
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
|
||||
MyHash_ = CreateHash(MyPublicEndPoint_);
|
||||
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
|
||||
}
|
||||
|
||||
void MicroServicePostInitialization();
|
||||
@@ -3548,8 +3601,6 @@ namespace OpenWifi {
|
||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||
|
||||
inline void MicroService::initialize(Poco::Util::Application &self) {
|
||||
// Utils::SetThreadName("microservice");
|
||||
|
||||
// add the default services
|
||||
LoadConfigurationFile();
|
||||
InitializeLoggingSystem();
|
||||
@@ -3824,11 +3875,6 @@ namespace OpenWifi {
|
||||
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
||||
}
|
||||
|
||||
inline std::string MicroService::CreateHash(const std::string &S) {
|
||||
SHA2_.update(S);
|
||||
return Utils::ToHex(SHA2_.digest());
|
||||
}
|
||||
|
||||
inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
||||
Poco::JSON::Object Obj;
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
|
||||
@@ -3891,6 +3937,7 @@ namespace OpenWifi {
|
||||
Params->setMaxThreads(50);
|
||||
Params->setMaxQueued(200);
|
||||
Params->setKeepAlive(true);
|
||||
Params->setName("ws:xrest");
|
||||
|
||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
@@ -3927,6 +3974,7 @@ namespace OpenWifi {
|
||||
Params->setMaxThreads(50);
|
||||
Params->setMaxQueued(200);
|
||||
Params->setKeepAlive(true);
|
||||
Params->setName("ws:irest");
|
||||
|
||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
@@ -3944,8 +3992,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline int MicroService::main([[maybe_unused]] const ArgVec &args) {
|
||||
|
||||
// Utils::SetThreadName("main");
|
||||
MyErrorHandler ErrorHandler(*this);
|
||||
Poco::ErrorHandler::set(&ErrorHandler);
|
||||
|
||||
@@ -4052,6 +4098,7 @@ namespace OpenWifi {
|
||||
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
|
||||
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setName("ws:alb");
|
||||
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
|
||||
Server_->start();
|
||||
}
|
||||
@@ -4061,7 +4108,7 @@ namespace OpenWifi {
|
||||
|
||||
inline void BusEventManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("BusEventManager");
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false);
|
||||
while(Running_) {
|
||||
@@ -4148,7 +4195,7 @@ namespace OpenWifi {
|
||||
|
||||
inline void KafkaProducer::run() {
|
||||
|
||||
Utils::SetThreadName("KafkaProducer");
|
||||
Utils::SetThreadName("Kafka:Prod");
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
||||
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
|
||||
@@ -4187,7 +4234,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline void KafkaConsumer::run() {
|
||||
Utils::SetThreadName("KafkaConsumer");
|
||||
Utils::SetThreadName("Kafka:Cons");
|
||||
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
||||
@@ -4327,6 +4374,11 @@ namespace OpenWifi {
|
||||
Answer.set("certificates", Certificates);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
if(GetBoolParameter("extraConfiguration")) {
|
||||
Poco::JSON::Object Answer;
|
||||
MicroService::instance().GetExtraConfiguration(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||
}
|
||||
|
||||
@@ -4699,6 +4751,7 @@ namespace OpenWifi {
|
||||
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
|
||||
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
|
||||
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
|
||||
Contacted = true;
|
||||
if(!Allowed) {
|
||||
if(Server_.LogBadTokens(false)) {
|
||||
Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}",
|
||||
@@ -4707,6 +4760,7 @@ namespace OpenWifi {
|
||||
}
|
||||
} else {
|
||||
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
|
||||
REST_Requester_ = Id;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()), Id,
|
||||
@@ -4730,6 +4784,7 @@ namespace OpenWifi {
|
||||
#else
|
||||
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) {
|
||||
#endif
|
||||
REST_Requester_ = UserInfo_.userinfo.email;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}",
|
||||
UserInfo_.userinfo.email,
|
||||
@@ -4812,7 +4867,7 @@ namespace OpenWifi {
|
||||
void run() override;
|
||||
// MyParallelSocketReactor &ReactorPool();
|
||||
Poco::Net::SocketReactor & Reactor() { return Reactor_; }
|
||||
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id);
|
||||
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName);
|
||||
bool Register(WebSocketClient *Client, const std::string &Id);
|
||||
void SetProcessor(WebSocketClientProcessor *F);
|
||||
void UnRegister(const std::string &Id);
|
||||
@@ -4848,7 +4903,7 @@ namespace OpenWifi {
|
||||
void SendToAll(const std::string &Payload);
|
||||
private:
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
Poco::Thread Thr_;
|
||||
Poco::Thread Thr_;
|
||||
// std::unique_ptr<MyParallelSocketReactor> ReactorPool_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
@@ -4863,18 +4918,22 @@ namespace OpenWifi {
|
||||
|
||||
class WebSocketClient {
|
||||
public:
|
||||
explicit WebSocketClient(Poco::Net::WebSocket &WS, const std::string &Id, Poco::Logger &L,
|
||||
WebSocketClientProcessor *Processor);
|
||||
explicit WebSocketClient(Poco::Net::WebSocket &WS,
|
||||
const std::string &Id,
|
||||
const std::string &UserName,
|
||||
Poco::Logger &L,
|
||||
WebSocketClientProcessor *Processor);
|
||||
virtual ~WebSocketClient();
|
||||
[[nodiscard]] inline const std::string &Id();
|
||||
[[nodiscard]] Poco::Logger &Logger();
|
||||
inline bool Send(const std::string &Payload);
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::string Id_;
|
||||
Poco::Logger &Logger_;
|
||||
bool Authenticated_ = false;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::string Id_;
|
||||
std::string UserName_;
|
||||
Poco::Logger &Logger_;
|
||||
std::atomic_bool Authenticated_ = false;
|
||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||
WebSocketClientProcessor *Processor_ = nullptr;
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
@@ -4882,33 +4941,9 @@ namespace OpenWifi {
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
||||
};
|
||||
|
||||
/* inline MyParallelSocketReactor::MyParallelSocketReactor(uint32_t NumReactors) :
|
||||
NumReactors_(NumReactors)
|
||||
{
|
||||
Reactors_ = new Poco::Net::SocketReactor[NumReactors_];
|
||||
for(uint32_t i=0;i<NumReactors_;i++) {
|
||||
ReactorPool_.start(Reactors_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inline MyParallelSocketReactor::~MyParallelSocketReactor() {
|
||||
for(uint32_t i=0;i<NumReactors_;i++) {
|
||||
Reactors_[i].stop();
|
||||
}
|
||||
ReactorPool_.stopAll();
|
||||
ReactorPool_.joinAll();
|
||||
delete [] Reactors_;
|
||||
}
|
||||
|
||||
inline Poco::Net::SocketReactor & MyParallelSocketReactor::Reactor() {
|
||||
return Reactors_[ rand() % NumReactors_ ];
|
||||
}
|
||||
|
||||
// inline MyParallelSocketReactor & WebSocketClientServer::ReactorPool() { return *ReactorPool_; }
|
||||
*/
|
||||
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id) {
|
||||
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto Client = new WebSocketClient(WS,Id,Logger(), Processor_);
|
||||
auto Client = new WebSocketClient(WS,Id,UserName,Logger(), Processor_);
|
||||
Clients_[Id] = std::make_pair(Client,"");
|
||||
}
|
||||
|
||||
@@ -4938,13 +4973,13 @@ namespace OpenWifi {
|
||||
|
||||
[[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload);
|
||||
inline WebSocketClientServer::WebSocketClientServer() noexcept:
|
||||
SubSystemServer("WebSocketClientServer", "WSCLNT-SVR", "websocketclients")
|
||||
SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients")
|
||||
{
|
||||
}
|
||||
|
||||
inline void WebSocketClientServer::run() {
|
||||
Running_ = true ;
|
||||
Utils::SetThreadName("ws:clnt-svr");
|
||||
Utils::SetThreadName("ws:uiclnt-svr");
|
||||
while(Running_) {
|
||||
Poco::Thread::trySleep(2000);
|
||||
|
||||
@@ -4992,8 +5027,12 @@ namespace OpenWifi {
|
||||
|
||||
for(const auto &client:Clients_) {
|
||||
if(client.second.second == UserName) {
|
||||
if(client.second.first->Send(Payload))
|
||||
Sent++;
|
||||
try {
|
||||
if (client.second.first->Send(Payload))
|
||||
Sent++;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Sent>0;
|
||||
@@ -5015,70 +5054,73 @@ namespace OpenWifi {
|
||||
int flags;
|
||||
int n;
|
||||
bool Done=false;
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
n = WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
try {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
n = WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if(n==0) {
|
||||
return delete this;
|
||||
}
|
||||
if (n == 0) {
|
||||
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||
return delete this;
|
||||
}
|
||||
|
||||
switch(Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.",Id_));
|
||||
Done=true;
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
IncomingFrame.append(0);
|
||||
if(!Authenticated_) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
auto Tokens = Utils::Split(Frame,':');
|
||||
bool Expired = false, Contacted = false;
|
||||
if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||
Authenticated_=true;
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
WS_->sendFrame(S.c_str(),S.size());
|
||||
WebSocketClientServer()->SetUser(Id_,UserInfo_.userinfo.email);
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
WS_->sendFrame(S.c_str(),S.size());
|
||||
Done=true;
|
||||
}
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||
Done = true;
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
IncomingFrame.append(0);
|
||||
if (!Authenticated_) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
auto Tokens = Utils::Split(Frame, ':');
|
||||
bool Expired = false, Contacted = false;
|
||||
if (Tokens.size() == 2 &&
|
||||
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||
Authenticated_ = true;
|
||||
UserName_ = UserInfo_.userinfo.email;
|
||||
Logger().warning(Poco::format("START(%s): %s UI Client is starting WS connection.", Id_, UserName_));
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
WS_->sendFrame(S.c_str(), S.size());
|
||||
WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email);
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
WS_->sendFrame(S.c_str(), S.size());
|
||||
Done = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj = P.parse(IncomingFrame.begin())
|
||||
.extract<Poco::JSON::Object::Ptr>();
|
||||
std::string Answer;
|
||||
if(Processor_!= nullptr)
|
||||
Processor_->Processor(Obj, Answer, Done);
|
||||
if (!Answer.empty())
|
||||
WS_->sendFrame(Answer.c_str(), (int) Answer.size());
|
||||
else {
|
||||
WS_->sendFrame("{}", 2);
|
||||
}
|
||||
} catch (const Poco::JSON::JSONException & E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj =
|
||||
P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>();
|
||||
std::string Answer;
|
||||
if (Processor_ != nullptr)
|
||||
Processor_->Processor(Obj, Answer, Done);
|
||||
if (!Answer.empty())
|
||||
WS_->sendFrame(Answer.c_str(), (int)Answer.size());
|
||||
else {
|
||||
WS_->sendFrame("{}", 2);
|
||||
}
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
Logger().log(E);
|
||||
Done=true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
Done=true;
|
||||
}
|
||||
|
||||
if(Done) {
|
||||
delete this;
|
||||
@@ -5090,9 +5132,10 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
|
||||
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
||||
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, const std::string &UserName, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
||||
Reactor_(WebSocketClientServer()->Reactor()),
|
||||
Id_(Id),
|
||||
UserName_(UserName),
|
||||
Logger_(L),
|
||||
Processor_(Processor) {
|
||||
try {
|
||||
@@ -5172,9 +5215,8 @@ namespace OpenWifi {
|
||||
try
|
||||
{
|
||||
Poco::Net::WebSocket WS(*Request, *Response);
|
||||
Logger().information("WebSocket connection established.");
|
||||
auto Id = MicroService::CreateUUID();
|
||||
WebSocketClientServer()->NewClient(WS,Id);
|
||||
WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email);
|
||||
}
|
||||
catch (...) {
|
||||
std::cout << "Cannot create websocket client..." << std::endl;
|
||||
|
||||
@@ -146,6 +146,10 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationRebootList {
|
||||
std::string title,
|
||||
details,
|
||||
@@ -189,5 +193,58 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationUpgradeList {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
skipped,
|
||||
no_firmware,
|
||||
not_connected;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t;
|
||||
|
||||
inline void WebSocketNotificationUpgradeList::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_to_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_to_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationUpgradeList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_from_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_from_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) {
|
||||
N.type = "venue_upgrader";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
|
||||
@@ -133,6 +133,37 @@ namespace ORM {
|
||||
return R;
|
||||
}
|
||||
|
||||
inline std::string WHERE_AND_(std::string Result) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) {
|
||||
if constexpr(std::is_same_v<T,std::string>)
|
||||
{
|
||||
if(!Value.empty()) {
|
||||
if(!Result.empty())
|
||||
Result += " and ";
|
||||
Result += fieldName;
|
||||
Result += '=';
|
||||
Result += "'";
|
||||
Result += Escape(Value);
|
||||
Result += "'";
|
||||
}
|
||||
} else {
|
||||
if(!Result.empty())
|
||||
Result += " and ";
|
||||
Result += fieldName ;
|
||||
Result += '=';
|
||||
Result += std::to_string(Value);
|
||||
}
|
||||
return WHERE_AND_(Result,args...);
|
||||
}
|
||||
|
||||
template <typename... Args> std::string WHERE_AND(Args... args) {
|
||||
std::string Result;
|
||||
return WHERE_AND_(Result, args...);
|
||||
}
|
||||
|
||||
enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE };
|
||||
enum SqlBinaryOp { AND = 0 , OR };
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace OpenWifi {
|
||||
} else if (LastDate) {
|
||||
WhereClause = fmt::format(" boardId='{}' and (timestamp <= {}) ", boardId, LastDate);
|
||||
}
|
||||
GetRecords(0,MaxRecords,Recs,WhereClause," order by timestamp ASC ");
|
||||
GetRecords(0,MaxRecords,Recs,WhereClause," order by timestamp, serialNumber ASC ");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
7491
stats_sample/bridge-stats-show-clients.json
Normal file
7491
stats_sample/bridge-stats-show-clients.json
Normal file
File diff suppressed because it is too large
Load Diff
7554
stats_sample/last_stats.json
Normal file
7554
stats_sample/last_stats.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -144,25 +144,9 @@ logout() {
|
||||
rm -rf token.json
|
||||
}
|
||||
|
||||
venuecount() {
|
||||
curl ${FLAGS} "https://${OWPROV}/api/v1/venue?countOnly=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-H "accept: application/json" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
contactcount() {
|
||||
curl ${FLAGS} "https://${OWPROV}/api/v1/contact?countOnly=true" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
-H "Accept: application/json" > ${result_file}
|
||||
jq < ${result_file}
|
||||
}
|
||||
|
||||
setloglevel() {
|
||||
payload="{ \"command\" : \"setloglevel\" , \"subsystems\" : [ { \"tag\" : \"$1\" , \"value\" : \"$2\" } ] }"
|
||||
curl ${FLAGS} -X POST "https://${OWPROV}/api/v1/system" \
|
||||
curl ${FLAGS} -X POST "https://${OWANALYTICS}/api/v1/system" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
@@ -171,7 +155,7 @@ setloglevel() {
|
||||
|
||||
getloglevels() {
|
||||
payload="{ \"command\" : \"getloglevels\" }"
|
||||
curl ${FLAGS} -X POST "https://${OWPROV}/api/v1/system" \
|
||||
curl ${FLAGS} -X POST "https://${OWANALYTICS}/api/v1/system" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
@@ -180,7 +164,7 @@ getloglevels() {
|
||||
|
||||
getloglevelnames() {
|
||||
payload="{ \"command\" : \"getloglevelnames\" }"
|
||||
curl ${FLAGS} -X POST "https://${OWPROV}/api/v1/system" \
|
||||
curl ${FLAGS} -X POST "https://${OWANALYTICS}/api/v1/system" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
@@ -189,7 +173,7 @@ getloglevelnames() {
|
||||
|
||||
getsubsystemnames() {
|
||||
payload="{ \"command\" : \"getsubsystemnames\" }"
|
||||
curl ${FLAGS} -X POST "https://${OWPROV}/api/v1/system" \
|
||||
curl ${FLAGS} -X POST "https://${OWANALYTICS}/api/v1/system" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
@@ -197,7 +181,7 @@ getsubsystemnames() {
|
||||
}
|
||||
|
||||
systeminfo() {
|
||||
curl ${FLAGS} -X GET "https://${OWPROV}/api/v1/system?command=info" \
|
||||
curl ${FLAGS} -X GET "https://${OWANALYTICS}/api/v1/system?command=info" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||
jq < ${result_file}
|
||||
@@ -205,7 +189,7 @@ systeminfo() {
|
||||
|
||||
reloadsubsystem() {
|
||||
payload="{ \"command\" : \"reload\", \"subsystems\" : [ \"$1\" ] }"
|
||||
curl ${FLAGS} -X POST "https://${OWPROV}/api/v1/system" \
|
||||
curl ${FLAGS} -X POST "https://${OWANALYTICS}/api/v1/system" \
|
||||
-H "Accept: application/json" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${token}" \
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"children":[{"children":[{"children":[{"children":[],"name":"Ottawa Operations","type":"entity","uuid":"323054d0-3ff0-11ec-82ff-061b87871e04","venues":[{"children":[],"name":"Living Lab","type":"venue","uuid":"4159ea84-3ff0-11ec-9edb-061b87871e04"}]}],"name":"Ontario","type":"entity","uuid":"21dfa464-3ff0-11ec-9a86-061b87871e04","venues":[]},{"children":[{"children":[],"name":"Quebec","type":"entity","uuid":"27b74e1b-52d7-4414-a1b4-47574c799beb","venues":[]},{"children":[],"name":"Ontario","type":"entity","uuid":"3cb15a80-3550-11ec-9a22-061b87871e04","venues":[{"children":[],"name":"CN Tower","type":"venue","uuid":"3cb28f0e-3550-11ec-acfa-061b87871e04"},{"children":[],"name":"Rogers Center","type":"venue","uuid":"3cb3c798-3550-11ec-8c1a-061b87871e04"}]},{"children":[],"name":"BC","type":"entity","uuid":"3cb503c4-3550-11ec-b436-061b87871e04","venues":[{"children":[],"name":"BC Place","type":"venue","uuid":"3cb76452-3550-11ec-a5ab-061b87871e04"},{"children":[],"name":"Stanley Park","type":"venue","uuid":"3cb8b230-3550-11ec-bbe6-061b87871e04"},{"children":[],"name":"MegaLab","type":"venue","uuid":"a73a23c4-6f3d-4031-bc92-d28c205f2d85"},{"children":[],"name":"Bowen Development","type":"venue","uuid":"d656500b-9f00-4c09-9096-e209085c2a3e"}]}],"name":"Provinces","type":"entity","uuid":"3cac92ca-3550-11ec-b360-061b87871e04","venues":[]}],"name":"Canada","type":"entity","uuid":"3cab2c32-3550-11ec-8a03-061b87871e04","venues":[]},{"children":[],"name":"USA","type":"entity","uuid":"6392c6b3-ef48-4b81-8785-1b5b4888bbd2","venues":[]},{"children":[{"children":[],"name":"Hamburg","type":"entity","uuid":"5939f995-e059-439d-ab0c-29a6f7c0a495","venues":[]}],"name":"Germany","type":"entity","uuid":"6fb5662d-dc48-4fbd-b8f9-69d0308bb902","venues":[]},{"children":[],"name":"Test Land","type":"entity","uuid":"70161a6f-98af-45d7-b0ed-e6b15ba5d84e","venues":[{"children":[],"name":"Test","type":"venue","uuid":"1d06b289-449e-4669-abc9-1f2dcdd1fbbc"}]}],"name":"World","type":"entity","uuid":"0000-0000-0000","venues":[]}
|
||||
Reference in New Issue
Block a user