Compare commits

..

12 Commits

Author SHA1 Message Date
TIP Automation User
439aa1d07a Chg: update image tag in helm values to v2.6.0-RC3 2022-06-23 19:01:35 +00:00
Stephane Bourque
a9293a7717 Merge pull request #29 from Telecominfraproject/main
https://telecominfraproject.atlassian.net/browse/WIFI-9553
2022-06-23 11:28:26 -07:00
Dmitry Dunaev
80d5ae340f Merge pull request #28 from Telecominfraproject/fix/wifi-9646--git-merge-conflict
[WIFI-9646] Fix: git merge conflict
2022-06-17 17:46:07 +03:00
Dmitry Dunaev
265ae7483b [WIFI-9646] Fix: git merge conflict
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-06-17 17:27:31 +03:00
TIP Automation User
43c4ad2211 Chg: update image tag in helm values to v2.6.0-RC2 2022-06-17 13:39:27 +00:00
Stephane Bourque
5cccd0b797 Merge pull request #27 from Telecominfraproject/WIFI-9616
Wifi 9616
2022-06-15 17:53:47 -07:00
stephb9959
b8bcece4bf Adding new configuration validator
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-06-15 17:21:59 -07:00
Dmitry Dunaev
3132b964bd Merge pull request #26 from Telecominfraproject/fix/wifi-9174--dep-charts-2.6
[WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
2022-06-03 19:27:31 +03:00
Dmitry Dunaev
711dc59fa6 [WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-06-03 19:27:02 +03:00
Stephane Bourque
82fbfeebc6 Merge pull request #23 from Telecominfraproject/WIFI8096
Fixing: https://telecominfraproject.atlassian.net/browse/WIFI-8096
2022-05-26 23:51:59 -07:00
stephb9959
77a4df5221 Fixing: https://telecominfraproject.atlassian.net/browse/WIFI-8096
Signed-off-by: Stephane Bourque <stephane.bourque@arilia.com>
2022-05-26 23:43:05 -07:00
TIP Automation User
c749275ef8 Chg: update image tag in helm values to v2.6.0-RC1 2022-05-23 12:55:15 +00:00
38 changed files with 847 additions and 2197 deletions

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
project(owprov VERSION 2.7.0) project(owprov VERSION 2.6.0)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
@@ -125,6 +125,7 @@ add_executable(owprov
src/RESTAPI/RESTAPI_db_helpers.h src/RESTAPI/RESTAPI_db_helpers.h
src/JobController.cpp src/JobController.h src/JobController.cpp src/JobController.h
src/JobRegistrations.cpp src/JobRegistrations.cpp
src/storage/storage_jobs.cpp src/storage/storage_jobs.h
src/storage/storage_maps.cpp src/storage/storage_maps.h src/storage/storage_maps.cpp src/storage/storage_maps.h
src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h
src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h
@@ -134,14 +135,7 @@ add_executable(owprov
src/storage/storage_variables.cpp src/storage/storage_variables.h src/storage/storage_variables.cpp src/storage/storage_variables.h
src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h
src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h
src/FileDownloader.cpp src/FileDownloader.h src/FileDownloader.cpp src/FileDownloader.h src/Tasks/VenueConfigUpdater.h src/Kafka_ProvUpdater.cpp src/Kafka_ProvUpdater.h src/storage/storage_operataor.cpp src/storage/storage_operataor.h src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h src/storage/storage_service_class.cpp src/storage/storage_service_class.h src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h src/RESTAPI/RESTAPI_service_class_handler.cpp src/RESTAPI/RESTAPI_service_class_handler.h src/RESTAPI/RESTAPI_operators_list_handler.cpp src/RESTAPI/RESTAPI_operators_list_handler.h src/RESTAPI/RESTAPI_operators_handler.cpp src/RESTAPI/RESTAPI_operators_handler.h src/storage/storage_op_contacts.cpp src/storage/storage_op_contacts.h src/storage/storage_op_locations.cpp src/storage/storage_op_locations.h src/RESTAPI/RESTAPI_op_contact_list_handler.cpp src/RESTAPI/RESTAPI_op_contact_list_handler.h src/RESTAPI/RESTAPI_op_contact_handler.cpp src/RESTAPI/RESTAPI_op_contact_handler.h src/RESTAPI/RESTAPI_op_location_list_handler.cpp src/RESTAPI/RESTAPI_op_location_list_handler.h src/RESTAPI/RESTAPI_op_location_handler.cpp src/RESTAPI/RESTAPI_op_location_handler.h src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h)
src/Tasks/VenueConfigUpdater.h
src/libs/croncpp.h
src/Kafka_ProvUpdater.cpp src/Kafka_ProvUpdater.h
src/storage/storage_operataor.cpp src/storage/storage_operataor.h
src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h
src/storage/storage_service_class.cpp src/storage/storage_service_class.h
src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h src/RESTAPI/RESTAPI_service_class_handler.cpp src/RESTAPI/RESTAPI_service_class_handler.h src/RESTAPI/RESTAPI_operators_list_handler.cpp src/RESTAPI/RESTAPI_operators_list_handler.h src/RESTAPI/RESTAPI_operators_handler.cpp src/RESTAPI/RESTAPI_operators_handler.h src/storage/storage_op_contacts.cpp src/storage/storage_op_contacts.h src/storage/storage_op_locations.cpp src/storage/storage_op_locations.h src/RESTAPI/RESTAPI_op_contact_list_handler.cpp src/RESTAPI/RESTAPI_op_contact_list_handler.h src/RESTAPI/RESTAPI_op_contact_handler.cpp src/RESTAPI/RESTAPI_op_contact_handler.h src/RESTAPI/RESTAPI_op_location_list_handler.cpp src/RESTAPI/RESTAPI_op_location_list_handler.h src/RESTAPI/RESTAPI_op_location_handler.cpp src/RESTAPI/RESTAPI_op_location_handler.h src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h)
target_link_libraries(owprov PUBLIC target_link_libraries(owprov PUBLIC
${Poco_LIBRARIES} ${Poco_LIBRARIES}

View File

@@ -1,10 +1,4 @@
ARG ALPINE_VERSION=3.16.2 FROM alpine:3.15 AS build-base
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 \ RUN apk add --update --no-cache \
make cmake g++ git \ make cmake g++ git \
@@ -15,10 +9,8 @@ RUN apk add --update --no-cache \
FROM build-base AS poco-build FROM build-base AS poco-build
ARG POCO_VERSION ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/poco /poco
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 WORKDIR /poco
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -27,26 +19,10 @@ RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
RUN cmake --build . --target install 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 FROM build-base AS cppkafka-build
ARG CPPKAFKA_VERSION ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
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 WORKDIR /cppkafka
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -57,10 +33,8 @@ RUN cmake --build . --target install
FROM build-base AS json-schema-validator-build FROM build-base AS json-schema-validator-build
ARG JSON_VALIDATOR_VERSION 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
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 WORKDIR /json-schema-validator
RUN mkdir cmake-build RUN mkdir cmake-build
@@ -69,6 +43,18 @@ RUN cmake ..
RUN make RUN make
RUN make install 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 owprov-build FROM build-base AS owprov-build
ADD CMakeLists.txt build /owprov/ ADD CMakeLists.txt build /owprov/
@@ -91,7 +77,7 @@ WORKDIR /owprov/cmake-build
RUN cmake .. RUN cmake ..
RUN cmake --build . --config Release -j8 RUN cmake --build . --config Release -j8
FROM alpine:$ALPINE_VERSION FROM alpine:3.15
ENV OWPROV_USER=owprov \ ENV OWPROV_USER=owprov \
OWPROV_ROOT=/owprov-data \ OWPROV_ROOT=/owprov-data \

2
build
View File

@@ -1 +1 @@
15 129

View File

@@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
update-ca-certificates update-ca-certificates
fi fi
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWPROV_CONFIG"/owprov.properties ]]; then
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWPROV_ROOT/certs/restapi-ca.pem"} \ RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWPROV_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16005"} \ RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16005"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWPROV_ROOT/certs/restapi-cert.pem"} \ RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWPROV_ROOT/certs/restapi-cert.pem"} \

2
helm/.gitignore vendored
View File

@@ -1,3 +1 @@
*.swp *.swp
Chart.lock
charts/

View File

@@ -1,5 +1,4 @@
{{- $root := . -}} {{- $root := . -}}
{{- $storageType := index .Values.configProperties "storage.type" -}}
--- ---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@@ -47,39 +46,6 @@ spec:
- -timeout - -timeout
- 600s - 600s
{{- if eq $storageType "postgresql" }}
- name: wait-postgres
image: "{{ .Values.images.owprov.repository }}:{{ .Values.images.owprov.tag }}"
imagePullPolicy: {{ .Values.images.owprov.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 "owprov.fullname" $root }}-env
key: {{ $key }}
{{- end }}
volumeMounts:
{{- range .Values.volumes.owprov }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- if .subPath }}
subPath: {{ .subPath }}
{{- end }}
{{- end }}
{{- end }}
containers: containers:
- name: owprov - name: owprov

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images: images:
owprov: owprov:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov
tag: v2.7.0-RC1 tag: v2.6.0-RC3
pullPolicy: Always pullPolicy: Always
# regcred: # regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io # registry: tip-tip-wlan-cloud-ucentral.jfrog.io

View File

@@ -27,13 +27,71 @@ components:
responses: responses:
NotFound: NotFound:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' description: The specified resource was not found.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: string
Unauthorized: Unauthorized:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/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
Success: Success:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' description: The requested operation was performed.
content:
application/json:
schema:
properties:
Operation:
type: string
Details:
type: string
Code:
type: integer
BadRequest: BadRequest:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' description: The requested operation failed.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: integer
schemas: schemas:
@@ -1958,6 +2016,11 @@ paths:
schema: schema:
type: boolean type: boolean
required: false required: false
- in: query
name: deviceType
schema:
type: string
required: false
- in: query - in: query
description: Pagination start (starts at 1. If not specified, 1 is assumed) description: Pagination start (starts at 1. If not specified, 1 is assumed)
name: offset name: offset
@@ -2029,21 +2092,6 @@ paths:
type: string type: string
format: uuid format: uuid
required: false required: false
- in: query
description: return RRM settings for a specific device
name: rrmSettings
schema:
type: boolean
default: false
required: false
- in: query
description: return the resolved configuration for a specific device
name: resolveConfig
schema:
type: boolean
default: false
required: false
responses: responses:
200: 200:
description: Return a list of elements description: Return a list of elements
@@ -2265,6 +2313,12 @@ paths:
type: string type: string
example: serial1,serial2,serial3 example: serial1,serial2,serial3
required: false required: false
- in: query
description: only serial numbers of full device details
name: serialOnly
schema:
type: boolean
required: false
- in: query - in: query
description: return the number of devices description: return the number of devices
name: countOnly name: countOnly

View File

@@ -1,174 +0,0 @@
openapi: 3.0.1
info:
title: OpenWiFi RRM Provider Model
description: Definitions and APIs to manages an OpenWiFi RRM Providers.
version: 1.0.0
license:
name: BSD3
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
servers:
- url: 'https://localhost:16022/api/v1'
security:
- bearerAuth: []
- ApiKeyAuth: []
components:
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-API-KEY
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
responses:
NotFound:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
Unauthorized:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
Success:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
BadRequest:
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
schemas:
Provider:
type: object
properties:
vendor:
description: The name of the vendor for display.
type: string
minLength: 1
maxLength: 128
vendorShortname:
description: A shortname for the vendor. Only letters and numbers are allowed. This is the name used internally.
type: string
minLength: 4
maxLength: 16
version:
description: An identifier that will help users identify the version of the RRM module they are using.
type: string
about:
description: A link to the Vendor page for this RRM Module
type: string
Algorithm:
type: object
properties:
name:
description: A display for this algorithm.
type: string
minLength: 1
maxLength: 128
description:
description: A description of the algorithm.
type: string
shortName:
description: This is the name used internally.
type: string
minLength: 4
maxLength: 16
parameterFormat:
description: this is a Regex used to validate the input. If this is empty, no validation will be performed.
type: string
parameterSamples:
description: These samples will be displayed in the UI to the user trying to configure the options
type: array
items:
type: string
helper:
description: A link to a web page or PDF document explaining the algorithm and its parameters
type: string
Algorithms:
description: The list of all algorithms supported by the vendor
type: array
items:
$ref: '#/components/schemas/Algorithm'
paths:
/provider:
get:
tags:
- RRM
operationId: getProvider
summary: Retrieve information about the provider for this RRM Module
responses:
200:
$ref: '#/components/schemas/Provider'
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/algorithms:
get:
tags:
- RRM
operationId: getAlgorithms
summary: Retrieve a lists of algorithms supported in the module.
responses:
200:
$ref: '#/components/schemas/Algorithms'
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/runRRM:
put:
tags:
- RRM
operationId: runRRMNow
summary: Run a specific or default RRM algorithm. The UI user or CLI user will have the ability to run an algorithm on demand.
parameters:
- in: query
description:
name: venue
schema:
type: string
format: uuid
required: true
- in: query
description: Perform RRM without updating anything. This may be used by an admin to see what RRM would do.
name: mock
schema:
type: boolean
default: false
required: false
- in: query
description: Specify the RRM algorithm to use. If omitted, select the default algorithm.
schema:
type: string
required: false
- in: query
description: Specify the parameters to use with the RRM algorithm to use. If omitted, select the default parameters.
schema:
type: string
required: false
responses:
200:
description: Return the list of actions that were or would be performed.
content:
application/json:
schema:
type: array
items:
type: string
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'

View File

@@ -153,62 +153,60 @@ namespace OpenWifi {
} }
} }
try { std::set<std::string> Sections;
std::set<std::string> Sections; for(const auto &i:Config_) {
for (const auto &i: Config_) { Poco::JSON::Parser P;
Poco::JSON::Parser P; auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>();
auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>(); auto Names = O->getNames();
auto Names = O->getNames(); for(const auto &SectionName:Names) {
for (const auto &SectionName: Names) { auto InsertInfo = Sections.insert(SectionName);
auto InsertInfo = Sections.insert(SectionName); if (InsertInfo.second) {
if (InsertInfo.second) { if (O->isArray(SectionName)) {
if (O->isArray(SectionName)) { auto OriginalArray = O->getArray(SectionName);
auto OriginalArray = O->getArray(SectionName);
if (Explain_) {
Poco::JSON::Object ExObj;
ExObj.set("from-uuid", i.info.id);
ExObj.set("from-name", i.info.name);
ExObj.set("action", "added");
ExObj.set("element", OriginalArray);
Explanation_.add(ExObj);
}
auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>();
ReplaceVariablesInArray(OriginalArray, ExpandedArray);
Configuration->set(SectionName, ExpandedArray);
} else if (O->isObject(SectionName)) {
auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>();
if (Explain_) {
Poco::JSON::Object ExObj;
ExObj.set("from-uuid", i.info.id);
ExObj.set("from-name", i.info.name);
ExObj.set("action", "added");
ExObj.set("element", OriginalSection);
Explanation_.add(ExObj);
}
auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>();
ReplaceVariablesInObject(OriginalSection, ExpandedSection);
Configuration->set(SectionName, ExpandedSection);
} else {
std::cout << " --- unknown element type --- " << O->get(SectionName).toString()
<< std::endl;
}
} else {
if (Explain_) { if (Explain_) {
Poco::JSON::Object ExObj; Poco::JSON::Object ExObj;
ExObj.set("from-uuid", i.info.id); ExObj.set("from-uuid", i.info.id);
ExObj.set("from-name", i.info.name); ExObj.set("from-name", i.info.name);
ExObj.set("action", "ignored"); ExObj.set("action", "added");
ExObj.set("reason", "weight insufficient"); ExObj.set("element", OriginalArray);
ExObj.set("element", O->get(SectionName));
Explanation_.add(ExObj); Explanation_.add(ExObj);
} }
auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>();
ReplaceVariablesInArray(OriginalArray, ExpandedArray);
Configuration->set(SectionName, ExpandedArray);
} else if (O->isObject(SectionName)) {
auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>();
if (Explain_) {
Poco::JSON::Object ExObj;
ExObj.set("from-uuid", i.info.id);
ExObj.set("from-name", i.info.name);
ExObj.set("action", "added");
ExObj.set("element", OriginalSection);
Explanation_.add(ExObj);
}
auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>();
ReplaceVariablesInObject(OriginalSection, ExpandedSection);
Configuration->set(SectionName, ExpandedSection);
} else {
std::cout << " --- unknown element type --- " << O->get(SectionName).toString() << std::endl;
}
} else {
if (Explain_) {
Poco::JSON::Object ExObj;
ExObj.set("from-uuid", i.info.id);
ExObj.set("from-name", i.info.name);
ExObj.set("action", "ignored");
ExObj.set("reason", "weight insufficient");
ExObj.set("element", O->get(SectionName));
Explanation_.add(ExObj);
} }
} }
} }
} catch (...) {
} }
return !Config_.empty(); if(Config_.empty())
return false;
return true;
} }
static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) { static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) {

View File

@@ -26,7 +26,6 @@ namespace OpenWifi {
void AutoDiscovery::run() { void AutoDiscovery::run() {
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification()); Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("auto-discovery");
while(Note && Running_) { while(Note && Running_) {
auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get()); auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get());
if(Msg!= nullptr) { if(Msg!= nullptr) {

View File

@@ -33,7 +33,7 @@ namespace OpenWifi {
void Stop() override; void Stop() override;
void ConnectionReceived( const std::string & Key, const std::string & Payload) { void ConnectionReceived( const std::string & Key, const std::string & Payload) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
poco_debug(Logger(),Poco::format("Device(%s): Connection/Ping message.", Key)); Logger().information(Poco::format("Device(%s): Connection/Ping message.", Key));
Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload)); Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload));
} }
void run() override; void run() override;

View File

@@ -26,8 +26,6 @@ namespace OpenWifi {
{"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" } {"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" }
}; };
Utils::SetThreadName("file-dmnldr");
for(const auto &[url,filename]:Files) { for(const auto &[url,filename]:Files) {
try { try {
std::string FileContent; std::string FileContent;

View File

@@ -27,32 +27,11 @@ namespace OpenWifi {
void JobController::run() { void JobController::run() {
Running_ = true ; Running_ = true ;
Utils::SetThreadName("job-controller");
while(Running_) { while(Running_) {
Poco::Thread::trySleep(2000); Poco::Thread::trySleep(2000);
std::lock_guard G(Mutex_);
for(auto &current_job:jobs_) {
if(current_job!=nullptr) {
if(current_job->Started()==0 && Pool_.used()<Pool_.available()) {
current_job->Logger().information(fmt::format("Starting {}: {}",current_job->JobId(),current_job->Name()));
current_job->Start();
Pool_.start(*current_job);
}
}
}
for(auto it = jobs_.begin(); it!=jobs_.end();) {\
auto current_job = *it;
if(current_job!=nullptr && current_job->Completed()!=0) {
current_job->Logger().information(fmt::format("Completed {}: {}",current_job->JobId(),current_job->Name()));
it = jobs_.erase(it);
delete current_job;
} else {
++it;
}
}
} }
} }
} }

View File

@@ -7,45 +7,99 @@
#include <vector> #include <vector>
#include <utility> #include <utility>
#include <functional> #include <functional>
#include <list>
#include "framework/MicroService.h" #include "framework/MicroService.h"
namespace OpenWifi { namespace OpenWifi {
class Job : public Poco::Runnable { class Job {
public: public:
Job(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : struct Parameter {
jobId_(JobID), std::string name;
name_(name), std::string value;
parameters_(parameters), inline void to_json(Poco::JSON::Object &Obj) const {
when_(when), RESTAPI_utils::field_to_json(Obj,"name",name);
userinfo_(UI), RESTAPI_utils::field_to_json(Obj,"value",value);
Logger_(L) }
{};
virtual void run() = 0; inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
[[nodiscard]] std::string Name() const { return name_; } try {
const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; } RESTAPI_utils::field_from_json(Obj,"name",name);
Poco::Logger & Logger() { return Logger_; } RESTAPI_utils::field_from_json(Obj,"value",value);
const std::string & JobId() const { return jobId_; } return true;
const std::string & Parameter(int x) const { return parameters_[x];} } catch (...) {
uint64_t When() const { return when_; }
void Start() { started_ = OpenWifi::Now(); }
uint64_t Started() const { return started_; }
uint64_t Completed() const { return completed_;}
void Complete() { completed_ = OpenWifi::Now(); }
private: }
std::string jobId_; return false;
std::string name_; }
std::vector<std::string> parameters_; };
uint64_t when_=0;
SecurityObjects::UserInfo userinfo_; struct Status {
Poco::Logger & Logger_; Types::UUID_t UUID;
uint64_t started_=0; uint64_t Start = 0 ;
uint64_t completed_=0; uint64_t Progress = 0 ;
uint64_t Completed = 0 ;
std::string CurrentDisplay;
};
struct Result {
int Error=0;
std::string Reason;
};
typedef std::vector<Parameter> Parameters;
typedef std::vector<Parameters> ParametersVec;
typedef std::function<bool(const Parameters &Parameters, Result &Result, bool &Retry)> WorkerFunction;
typedef std::vector<Status> Statuses;
Job(std::string Title,
std::string Description,
std::string RegisteredName,
ParametersVec Parameters,
[[maybe_unused]] bool Parallel=true) :
Title_(std::move(Title)),
Description_(std::move(Description)),
RegisteredName_(std::move(RegisteredName)),
Parameters_(std::move(Parameters))
{
UUID_ = MicroService::instance().CreateUUID();
}
[[nodiscard]] inline const Types::UUID_t & ID() const { return UUID_; }
private:
Types::UUID_t UUID_;
std::string Title_;
std::string Description_;
std::string RegisteredName_;
ParametersVec Parameters_;
}; };
class JobRegistry {
public:
static auto instance() {
static auto instance_ = new JobRegistry;
return instance_;
}
inline void RegisterJobType( const std::string & JobType, Job::WorkerFunction Function) {
JobTypes_[JobType] = std::move(Function);
}
inline bool Execute(const std::string &JobType, const Job::Parameters & Params, Job::Result &Result, bool & Retry) {
auto Hint = JobTypes_.find(JobType);
if(Hint != end(JobTypes_)) {
Hint->second(Params, Result, Retry);
return true;
}
return false;
}
private:
std::map<std::string,Job::WorkerFunction> JobTypes_;
};
inline auto JobRegistry() { return JobRegistry::instance(); }
class JobController : public SubSystemServer, Poco::Runnable { class JobController : public SubSystemServer, Poco::Runnable {
public: public:
static auto instance() { static auto instance() {
@@ -58,16 +112,11 @@ namespace OpenWifi {
void run() override; void run() override;
inline void wakeup() { Thr_.wakeUp(); } inline void wakeup() { Thr_.wakeUp(); }
void AddJob( Job* newJob ) { bool JobList(Job::Statuses & Statuses);
std::lock_guard G(Mutex_);
jobs_.push_back(newJob);
}
private: private:
Poco::Thread Thr_; Poco::Thread Thr_;
std::atomic_bool Running_=false; std::atomic_bool Running_=false;
std::list<Job *> jobs_;
Poco::ThreadPool Pool_;
JobController() noexcept: JobController() noexcept:
SubSystemServer("JobController", "JOB-SVR", "job") SubSystemServer("JobController", "JOB-SVR", "job")

View File

@@ -23,7 +23,6 @@ namespace OpenWifi {
bool &Done, std::string &Answer) { bool &Done, std::string &Answer) {
Done = false; Done = false;
auto Prefix = O->get("serial_prefix").toString(); auto Prefix = O->get("serial_prefix").toString();
Poco::toLowerInPlace(Prefix);
Logger().information(Poco::format("serial_number_search: %s", Prefix)); Logger().information(Poco::format("serial_number_search: %s", Prefix));
if (!Prefix.empty() && Prefix.length() < 13) { if (!Prefix.empty() && Prefix.length() < 13) {
std::vector<uint64_t> Numbers; std::vector<uint64_t> Numbers;
@@ -84,7 +83,6 @@ namespace OpenWifi {
Done = false; Done = false;
auto operatorId = O->get("operatorId").toString(); auto operatorId = O->get("operatorId").toString();
auto Prefix = O->get("serial_prefix").toString(); auto Prefix = O->get("serial_prefix").toString();
Poco::toLowerInPlace(Prefix);
std::string Query; std::string Query;
if(Prefix[0]=='*') { if(Prefix[0]=='*') {

View File

@@ -9,9 +9,6 @@
#include "framework/MicroService.h" #include "framework/MicroService.h"
#include "framework/ConfigurationValidator.h" #include "framework/ConfigurationValidator.h"
#include "sdks/SDK_sec.h" #include "sdks/SDK_sec.h"
#include "Poco/StringTokenizer.h"
#include "libs/croncpp.h"
namespace OpenWifi { namespace OpenWifi {
@@ -408,9 +405,7 @@ namespace OpenWifi {
} }
inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) { inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) {
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", "unit" };
"unit", "definitions", "ethernet", "switch", "config-raw",
"third-party" };
for(const auto &i:Config.configuration) { for(const auto &i:Config.configuration) {
Poco::JSON::Parser P; Poco::JSON::Parser P;
@@ -526,39 +521,12 @@ namespace OpenWifi {
} }
} }
} }
return Result; return Result;
} }
inline bool ValidSchedule(const std::string &v) {
try
{
auto cron = cron::make_cron(v);
return true;
}
catch (cron::bad_cronexpr const & ex)
{
}
return false;
}
inline bool ValidRRM(const std::string &v) {
if((v=="no") || (v=="inherit")) return true;
try {
Poco::JSON::Parser P;
auto O = P.parse(v).extract<Poco::JSON::Object::Ptr>();
ProvObjects::RRMDetails D;
if(D.from_json(O)) {
return ValidSchedule(D.schedule);
}
} catch (...) {
}
return false;
}
inline bool ValidDeviceRules(const ProvObjects::DeviceRules & DR) { inline bool ValidDeviceRules(const ProvObjects::DeviceRules & DR) {
return (ValidRRM(DR.rrm)) && return (DR.rrm=="yes" || DR.rrm=="no" || DR.rrm=="inherit") &&
(DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") && (DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") &&
(DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit"); (DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit");
} }

View File

@@ -35,53 +35,36 @@ namespace OpenWifi{
void RESTAPI_inventory_handler::DoGet() { void RESTAPI_inventory_handler::DoGet() {
ProvObjects::InventoryTag Existing; ProvObjects::InventoryTag Existing;
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
Logger().debug(Poco::format("%s: Retrieving inventory information.", SerialNumber)); Logger().debug(Poco::format("%s: Retrieving inventory information.",SerialNumber));
if (SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) { if(SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER,SerialNumber,Existing)) {
return NotFound(); return NotFound();
} }
Logger().debug( Logger().debug(Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id ));
Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id));
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
std::string Arg; std::string Arg;
if (HasParameter("config", Arg) && Arg == "true") { if(HasParameter("config",Arg) && Arg=="true") {
bool Explain = (HasParameter("explain", Arg) && Arg == "true"); bool Explain = (HasParameter("explain",Arg) && Arg == "true");
APConfig Device(SerialNumber, Existing.deviceType, Logger(), Explain); APConfig Device(SerialNumber,Existing.deviceType,Logger(), Explain);
auto Configuration = Poco::makeShared<Poco::JSON::Object>(); auto Configuration = Poco::makeShared<Poco::JSON::Object>();
if (Device.Get(Configuration)) { if(Device.Get(Configuration)) {
Answer.set("config", Configuration); Answer.set("config", Configuration);
if (Explain) if(Explain)
Answer.set("explanation", Device.Explanation()); Answer.set("explanation", Device.Explanation());
} else { } else {
Answer.set("config", "none"); Answer.set("config","none");
} }
return ReturnObject(Answer); return ReturnObject(Answer);
} else if (GetBoolParameter("firmwareOptions", false)) { } else if(HasParameter("firmwareOptions", Arg) && Arg=="true") {
ProvObjects::DeviceRules Rules; ProvObjects::DeviceRules Rules;
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber,Rules);
Answer.set("firmwareUpgrade", Rules.firmwareUpgrade); Answer.set("firmwareUpgrade",Rules.firmwareUpgrade);
Answer.set("firmwareRCOnly", Rules.rcOnly == "yes"); Answer.set("firmwareRCOnly", Rules.rcOnly == "yes" );
return ReturnObject(Answer); return ReturnObject(Answer);
} else if(GetBoolParameter("rrmSettings",false)) { } else if(HasParameter("applyConfiguration",Arg) && Arg=="true") {
ProvObjects::DeviceRules Rules;
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules);
if(Rules.rrm=="no" || Rules.rrm=="inherit") {
Answer.set("rrm", Rules.rrm);
} else {
ProvObjects::RRMDetails D;
Poco::JSON::Parser P;
try {
auto Obj = P.parse(Rules.rrm).extract<Poco::JSON::Object::Ptr>();
Answer.set("rrm", Obj);
} catch (...) {
Answer.set("rrm", "invalid");
}
}
return ReturnObject(Answer);
} else if(GetBoolParameter("applyConfiguration", false)) {
Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber)); Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber));
auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false);
auto Configuration = Poco::makeShared<Poco::JSON::Object>(); auto Configuration = Poco::makeShared<Poco::JSON::Object>();
@@ -108,19 +91,6 @@ namespace OpenWifi{
} }
Results.to_json(Answer); Results.to_json(Answer);
return ReturnObject(Answer); return ReturnObject(Answer);
} else if(GetBoolParameter("resolveConfig", false)) {
Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber));
auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false);
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
Poco::JSON::Object ErrorsObj, WarningsObj;
ProvObjects::InventoryConfigApplyResult Results;
Logger().debug(Poco::format("%s: Computing configuration.",Existing.serialNumber));
if (Device->Get(Configuration)) {
Answer.set("configuration", Configuration);
} else {
Answer.set("error", 1);
}
return ReturnObject(Answer);
} else if(QB_.AdditionalInfo) { } else if(QB_.AdditionalInfo) {
AddExtendedInfo(Existing,Answer); AddExtendedInfo(Existing,Answer);
} }
@@ -166,7 +136,6 @@ namespace OpenWifi{
void RESTAPI_inventory_handler::DoPost() { void RESTAPI_inventory_handler::DoPost() {
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
Poco::toLowerInPlace(SerialNumber);
if(SerialNumber.empty()) { if(SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingSerialNumber); return BadRequest(RESTAPI::Errors::MissingSerialNumber);
} }

View File

@@ -101,7 +101,7 @@ namespace OpenWifi {
{ "email", UserName }, { "email", UserName },
{ "signupUUID" , SignupUUID }, { "signupUUID" , SignupUUID },
{ "owner" , SignupOperator.info.id }, { "owner" , SignupOperator.info.id },
{ "operatorName", SignupOperator.registrationId }
}, Body, 30000); }, Body, 30000);
Poco::JSON::Object::Ptr Answer; Poco::JSON::Object::Ptr Answer;

View File

@@ -228,10 +228,10 @@ namespace OpenWifi{
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
SNL.serialNumbers = Existing.devices; SNL.serialNumbers = Existing.devices;
auto JobId = MicroService::instance().CreateUUID();
Types::StringVec Parameters{UUID};; auto Task = new VenueConfigUpdater(UUID,UserInfo_.userinfo,0,Logger());
auto NewJob = new VenueConfigUpdater(JobId,"VenueConfigurationUpdater", Parameters, 0, UserInfo_.userinfo, Logger()); auto JobId = Task->Start();
JobController()->AddJob(dynamic_cast<Job*>(NewJob));
SNL.to_json(Answer); SNL.to_json(Answer);
Answer.set("jobId",JobId); Answer.set("jobId",JobId);
return ReturnObject(Answer); return ReturnObject(Answer);
@@ -242,10 +242,10 @@ namespace OpenWifi{
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
SNL.serialNumbers = Existing.devices; SNL.serialNumbers = Existing.devices;
auto JobId = MicroService::instance().CreateUUID();
Types::StringVec Parameters{UUID};; auto Task = new VenueUpgrade(UUID,UserInfo_.userinfo,0,Logger());
auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger()); auto JobId = Task->Start();
JobController()->AddJob(dynamic_cast<Job*>(NewJob));
SNL.to_json(Answer); SNL.to_json(Answer);
Answer.set("jobId",JobId); Answer.set("jobId",JobId);
return ReturnObject(Answer); return ReturnObject(Answer);
@@ -256,10 +256,10 @@ namespace OpenWifi{
Poco::JSON::Object Answer; Poco::JSON::Object Answer;
SNL.serialNumbers = Existing.devices; SNL.serialNumbers = Existing.devices;
auto JobId = MicroService::instance().CreateUUID();
Types::StringVec Parameters{UUID};; auto Task = new VenueRebooter(UUID,UserInfo_.userinfo,0,Logger());
auto NewJob = new VenueRebooter(JobId,"VenueRebooter", Parameters, 0, UserInfo_.userinfo, Logger()); auto JobId = Task->Start();
JobController()->AddJob(dynamic_cast<Job*>(NewJob));
SNL.to_json(Answer); SNL.to_json(Answer);
Answer.set("jobId",JobId); Answer.set("jobId",JobId);
return ReturnObject(Answer); return ReturnObject(Answer);

View File

@@ -1159,40 +1159,5 @@ namespace OpenWifi::ProvObjects {
return false; return false;
} }
void RRMAlgorithmDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"name",name);
field_to_json(Obj,"parameters",parameters);
}
bool RRMAlgorithmDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"name",name);
field_from_json(Obj,"parameters",parameters);
return true;
} catch(...) {
}
return false;
}
void RRMDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"vendor",vendor);
field_to_json(Obj,"schedule",schedule);
field_to_json(Obj,"algorithms",algorithms);
}
bool RRMDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"vendor",vendor);
field_from_json(Obj,"schedule",schedule);
field_from_json(Obj,"algorithms",algorithms);
return true;
} catch(...) {
}
return false;
}
} }

View File

@@ -62,21 +62,6 @@ namespace OpenWifi::ProvObjects {
}; };
typedef std::vector<ManagementPolicy> ManagementPolicyVec; typedef std::vector<ManagementPolicy> ManagementPolicyVec;
struct RRMAlgorithmDetails {
std::string name;
std::string parameters;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RRMDetails {
std::string vendor;
std::string schedule;
std::vector<RRMAlgorithmDetails> algorithms;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceRules { struct DeviceRules {
std::string rcOnly{"inherit"}; std::string rcOnly{"inherit"};
std::string rrm{"inherit"}; std::string rrm{"inherit"};

View File

@@ -42,7 +42,6 @@ namespace OpenWifi {
void Signup::run() { void Signup::run() {
Running_ = true; Running_ = true;
Utils::SetThreadName("signup-mgr");
while(Running_) { while(Running_) {
Poco::Thread::trySleep(5000); Poco::Thread::trySleep(5000);

View File

@@ -105,7 +105,6 @@ namespace OpenWifi {
} }
void Storage::onTimer([[maybe_unused]] Poco::Timer &timer) { void Storage::onTimer([[maybe_unused]] Poco::Timer &timer) {
Utils::SetThreadName("strg-janitor");
} }
void Storage::Stop() { void Storage::Stop() {
@@ -195,24 +194,18 @@ namespace OpenWifi {
// check that all inventory in venues and entities actually exists, if not, fix it. // check that all inventory in venues and entities actually exists, if not, fix it.
auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool { auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool {
Types::UUIDvec_t NewDevices; Types::UUIDvec_t NewDevices;
bool modified=false;
for(const auto &device:V.devices) { for(const auto &device:V.devices) {
ProvObjects::InventoryTag T; ProvObjects::InventoryTag T;
if(InventoryDB().GetRecord("id", device, T)) { if(InventoryDB().GetRecord("id", device, T)) {
NewDevices.emplace_back(device); NewDevices.emplace_back(device);
} else { } else {
modified=true;
} }
} }
ProvObjects::Venue NewVenue = V; if(NewDevices!=V.devices) {
if(V.deviceRules.rrm=="yes") {
NewVenue.deviceRules.rrm="inherit";
modified=true;
}
if(modified) {
Logger().warning(fmt::format(" fixing venue: {}", V.info.name)); Logger().warning(fmt::format(" fixing venue: {}", V.info.name));
ProvObjects::Venue NewVenue = V;
NewVenue.devices = NewDevices; NewVenue.devices = NewDevices;
VenueDB().UpdateRecord("id", V.info.id, NewVenue); VenueDB().UpdateRecord("id", V.info.id, NewVenue);
} }
@@ -272,16 +265,10 @@ namespace OpenWifi {
} }
} }
ProvObjects::Entity NewEntity = E;
if(E.deviceRules.rrm=="yes") {
NewEntity.deviceRules.rrm="inherit";
Modified=true;
}
if(Modified) if(Modified)
{ {
Logger().warning(fmt::format(" fixing entity: {}",E.info.name)); Logger().warning(fmt::format(" fixing entity: {}",E.info.name));
ProvObjects::Entity NewEntity = E;
NewEntity.devices = NewDevices; NewEntity.devices = NewDevices;
NewEntity.contacts = NewContacts; NewEntity.contacts = NewContacts;
NewEntity.locations = NewLocations; NewEntity.locations = NewLocations;
@@ -292,103 +279,11 @@ namespace OpenWifi {
return true; return true;
}; };
auto FixInventory = [&](const ProvObjects::InventoryTag &T) -> bool {
// check the venue/entity for this device.
ProvObjects::InventoryTag NewTag{T};
bool modified=false;
if(!T.venue.empty() && !VenueDB().Exists("id",T.venue)) {
NewTag.venue.clear();
modified=true;
}
if(!T.entity.empty() && !EntityDB().Exists("id",T.entity)) {
NewTag.entity.clear();
modified=true;
}
if(!T.location.empty() && !LocationDB().Exists("id",T.location)) {
NewTag.location.clear();
modified=true;
}
if(!T.contact.empty() && !ContactDB().Exists("id",T.contact)) {
NewTag.contact.clear();
modified=true;
}
if(T.deviceRules.rrm=="yes") {
NewTag.deviceRules.rrm = "inherit";
modified=true;
}
if(modified) {
Logger().warning(fmt::format(" fixing entity: {}",T.info.name));
InventoryDB().UpdateRecord("id", T.info.id, NewTag);
}
return true;
};
auto FixConfiguration = [&](const ProvObjects::DeviceConfiguration &C) -> bool {
ProvObjects::DeviceConfiguration NewConfig{C};
bool modified = false;
if (C.deviceRules.rrm == "yes") {
NewConfig.deviceRules.rrm = "inherit";
modified = true;
}
if (modified) {
Logger().warning(fmt::format(" fixing configuration: {}", C.info.name));
ConfigurationDB().UpdateRecord("id", C.info.id, NewConfig);
}
return true;
};
auto FixOperator = [&](const ProvObjects::Operator &O) -> bool {
ProvObjects::Operator NewOp{O};
bool modified = false;
if (O.deviceRules.rrm == "yes") {
NewOp.deviceRules.rrm = "inherit";
modified = true;
}
if (modified) {
Logger().warning(fmt::format(" fixing operator: {}", O.info.name));
OperatorDB().UpdateRecord("id", O.info.id, NewOp);
}
return true;
};
auto FixSubscriber = [&](const ProvObjects::SubscriberDevice &O) -> bool {
ProvObjects::SubscriberDevice NewSub{O};
bool modified = false;
if (O.deviceRules.rrm == "yes") {
NewSub.deviceRules.rrm = "inherit";
modified = true;
}
if (modified) {
Logger().warning(fmt::format(" fixing subscriber: {}", O.info.name));
SubscriberDeviceDB().UpdateRecord("id", O.info.id, NewSub);
}
return true;
};
Logger().information("Checking DB consistency: venues"); Logger().information("Checking DB consistency: venues");
VenueDB().Iterate(FixVenueDevices); VenueDB().Iterate(FixVenueDevices);
Logger().information("Checking DB consistency: entities"); Logger().information("Checking DB consistency: entities");
EntityDB().Iterate(FixEntity); EntityDB().Iterate(FixEntity);
Logger().information("Checking DB consistency: inventory");
InventoryDB().Iterate(FixInventory);
Logger().information("Checking DB consistency: configurations");
ConfigurationDB().Iterate(FixConfiguration);
Logger().information("Checking DB consistency: operators");
OperatorDB().Iterate(FixOperator);
Logger().information("Checking DB consistency: subscribers");
SubscriberDeviceDB().Iterate(FixSubscriber);
} }
void Storage::InitializeSystemDBs() { void Storage::InitializeSystemDBs() {

View File

@@ -21,7 +21,7 @@ namespace OpenWifi {
} }
void TagServer::run() { void TagServer::run() {
Utils::SetThreadName("tag-server");
} }
} }

View File

@@ -9,7 +9,6 @@
#include "APConfig.h" #include "APConfig.h"
#include "sdks/SDK_gw.h" #include "sdks/SDK_gw.h"
#include "framework/WebSocketClientNotifications.h" #include "framework/WebSocketClientNotifications.h"
#include "JobController.h"
namespace OpenWifi { namespace OpenWifi {
@@ -20,6 +19,8 @@ namespace OpenWifi {
auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>(); auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>();
auto Rejected = Status->getArray("rejected"); auto Rejected = Status->getArray("rejected");
std::transform(Rejected->begin(),Rejected->end(),std::back_inserter(Warnings), [](auto i) -> auto { return i.toString(); }); std::transform(Rejected->begin(),Rejected->end(),std::back_inserter(Warnings), [](auto i) -> auto { return i.toString(); });
// for(const auto &i:*Rejected)
// Warnings.push_back(i.toString());
} }
} catch (...) { } catch (...) {
} }
@@ -36,42 +37,35 @@ namespace OpenWifi {
void run() final { void run() final {
ProvObjects::InventoryTag Device; ProvObjects::InventoryTag Device;
started_=true; started_=true;
Utils::SetThreadName("venue-cfg");
if(StorageService()->InventoryDB().GetRecord("id",uuid_,Device)) { if(StorageService()->InventoryDB().GetRecord("id",uuid_,Device)) {
SerialNumber = Device.serialNumber; SerialNumber = Device.serialNumber;
// std::cout << "Starting push for " << Device.serialNumber << std::endl; // std::cout << "Starting push for " << Device.serialNumber << std::endl;
Logger().debug(fmt::format("{}: Computing configuration.",Device.serialNumber)); Logger().debug(fmt::format("{}: Computing configuration.",Device.serialNumber));
auto DeviceConfig = std::make_shared<APConfig>(Device.serialNumber, Device.deviceType, Logger(), false); auto DeviceConfig = std::make_shared<APConfig>(Device.serialNumber, Device.deviceType, Logger(), false);
auto Configuration = Poco::makeShared<Poco::JSON::Object>(); auto Configuration = Poco::makeShared<Poco::JSON::Object>();
try { if (DeviceConfig->Get(Configuration)) {
if (DeviceConfig->Get(Configuration)) { std::ostringstream OS;
std::ostringstream OS; Configuration->stringify(OS);
Configuration->stringify(OS); auto Response=Poco::makeShared<Poco::JSON::Object>();
auto Response = Poco::makeShared<Poco::JSON::Object>(); Logger().debug(fmt::format("{}: Pushing configuration.",Device.serialNumber));
Logger().debug(fmt::format("{}: Pushing configuration.", Device.serialNumber)); if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) {
if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) { Logger().debug(fmt::format("{}: Configuration pushed.",Device.serialNumber));
Logger().debug(fmt::format("{}: Configuration pushed.", Device.serialNumber)); Logger().information(fmt::format("{}: Updated.", Device.serialNumber));
Logger().information(fmt::format("{}: Updated.", Device.serialNumber)); // std::cout << Device.serialNumber << ": Updated" << std::endl;
// std::cout << Device.serialNumber << ": Updated" << std::endl; updated_++;
updated_++;
} else {
Logger().information(fmt::format("{}: Not updated.", Device.serialNumber));
// std::cout << Device.serialNumber << ": Failed" << std::endl;
failed_++;
}
} else { } else {
Logger().debug(fmt::format("{}: Configuration is bad.", Device.serialNumber)); Logger().information(fmt::format("{}: Not updated.", Device.serialNumber));
bad_config_++; // std::cout << Device.serialNumber << ": Failed" << std::endl;
// std::cout << Device.serialNumber << ": Bad config" << std::endl; failed_++;
} }
} catch (...) { } else {
Logger().debug(fmt::format("{}: Configuration is bad (caused an exception).", Device.serialNumber)); Logger().debug(fmt::format("{}: Configuration is bad.",Device.serialNumber));
bad_config_++; bad_config_++;
// std::cout << Device.serialNumber << ": Bad config" << std::endl;
} }
} }
done_ = true; done_ = true;
// std::cout << "Done push for " << Device.serialNumber << std::endl; // std::cout << "Done push for " << Device.serialNumber << std::endl;
Utils::SetThreadName("free");
} }
uint64_t updated_=0, failed_=0, bad_config_=0; uint64_t updated_=0, failed_=0, bad_config_=0;
@@ -86,101 +80,133 @@ namespace OpenWifi {
inline Poco::Logger & Logger() { return Logger_; } inline Poco::Logger & Logger() { return Logger_; }
}; };
class VenueConfigUpdater: public Job { class VenueConfigUpdater: public Poco::Runnable {
public: public:
VenueConfigUpdater(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : explicit VenueConfigUpdater(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
Job(JobID, name, parameters, when, UI, L) { VenueUUID_(VenueUUID),
UI_(UI),
When_(When),
Logger_(L)
{
} }
inline virtual void run() { inline std::string Start() {
std::string VenueUUID_; JobId_ = MicroService::CreateUUID();
Worker_.start(*this);
return JobId_;
}
Utils::SetThreadName("venue-update"); private:
VenueUUID_ = Parameter(0); std::string VenueUUID_;
SecurityObjects::UserInfo UI_;
uint64_t When_;
Poco::Logger &Logger_;
Poco::Thread Worker_;
std::string JobId_;
Poco::ThreadPool Pool_{2,16,300};
inline Poco::Logger & Logger() { return Logger_; }
inline void run() final {
if(When_ && When_>OpenWifi::Now())
Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 );
WebSocketNotification<WebSocketNotificationJobContent> N; WebSocketNotification<WebSocketNotificationJobContent> N;
Logger().information(fmt::format("Job {} Starting.", JobId_));
ProvObjects::Venue Venue; ProvObjects::Venue Venue;
uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ; uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ;
if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) {
const std::size_t MaxThreads=16;
struct tState {
Poco::Thread thr_;
VenueDeviceConfigUpdater *task= nullptr;
};
N.content.title = fmt::format("Updating {} configurations", Venue.info.name); N.content.title = fmt::format("Updating {} configurations", Venue.info.name);
N.content.jobId = JobId(); N.content.jobId = JobId_;
Poco::ThreadPool Pool_;
std::list<VenueDeviceConfigUpdater*> JobList;
std::array<tState,MaxThreads> Tasks;
for(const auto &uuid:Venue.devices) { for(const auto &uuid:Venue.devices) {
auto NewTask = new VenueDeviceConfigUpdater(uuid, Venue.info.name, Logger()); auto NewTask = new VenueDeviceConfigUpdater(uuid, Venue.info.name, Logger());
bool TaskAdded=false; // std::cout << "Scheduling config push for " << uuid << std::endl;
while(!TaskAdded) { bool found_slot = false;
if (Pool_.available()) { while (!found_slot) {
JobList.push_back(NewTask); for (auto &cur_task: Tasks) {
Pool_.start(*NewTask); if (cur_task.task == nullptr) {
TaskAdded = true; cur_task.task = NewTask;
continue; cur_task.thr_.start(*NewTask);
} found_slot = true;
} break;
}
for(auto job_it = JobList.begin(); job_it !=JobList.end();) { }
VenueDeviceConfigUpdater * current_job = *job_it;
if(current_job!= nullptr && current_job->done_) { // Let's look for a slot...
Updated += current_job->updated_; if (!found_slot) {
Failed += current_job->failed_; for (auto &cur_task: Tasks) {
BadConfigs += current_job->bad_config_; if (cur_task.task != nullptr && cur_task.task->started_) {
if(current_job->updated_) { if (cur_task.thr_.isRunning())
N.content.success.push_back(current_job->SerialNumber); continue;
} else if(current_job->failed_) { if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
N.content.warning.push_back(current_job->SerialNumber); cur_task.thr_.join();
} else { Updated += cur_task.task->updated_;
N.content.error.push_back(current_job->SerialNumber); Failed += cur_task.task->failed_;
BadConfigs += cur_task.task->bad_config_;
cur_task.task->started_ = cur_task.task->done_ = false;
delete cur_task.task;
cur_task.task = nullptr;
}
}
} }
job_it = JobList.erase(job_it);
delete current_job;
} else {
++job_it;
} }
} }
} }
Logger().debug("Waiting for outstanding update threads to finish."); Logger().debug("Waiting for outstanding update threads to finish.");
Pool_.joinAll(); bool stillTasksRunning=true;
for(auto job_it = JobList.begin(); job_it !=JobList.end();) { while(stillTasksRunning) {
VenueDeviceConfigUpdater * current_job = *job_it; stillTasksRunning = false;
if(current_job!= nullptr && current_job->done_) { for(auto &cur_task:Tasks) {
Updated += current_job->updated_; if(cur_task.task!= nullptr && cur_task.task->started_) {
Failed += current_job->failed_; if(cur_task.thr_.isRunning()) {
BadConfigs += current_job->bad_config_; stillTasksRunning = true;
if(current_job->updated_) { continue;
N.content.success.push_back(current_job->SerialNumber); }
} else if(current_job->failed_) { if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
N.content.warning.push_back(current_job->SerialNumber); cur_task.thr_.join();
} else { if(cur_task.task->updated_) {
N.content.error.push_back(current_job->SerialNumber); Updated++;
N.content.success.push_back(cur_task.task->SerialNumber);
} else if(cur_task.task->failed_) {
Failed++;
N.content.warning.push_back(cur_task.task->SerialNumber);
} else {
BadConfigs++;
N.content.error.push_back(cur_task.task->SerialNumber);
}
cur_task.task->started_ = cur_task.task->done_ = false;
delete cur_task.task;
cur_task.task = nullptr;
}
} }
job_it = JobList.erase(job_it);
delete current_job;
} else {
++job_it;
} }
} }
N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ", N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ",
JobId(), Updated ,Failed, BadConfigs); JobId_, Updated ,Failed, BadConfigs);
} else { } else {
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
Logger().warning(N.content.details); Logger().warning(N.content.details);
} }
// std::cout << N.content.details << std::endl; WebSocketClientNotificationVenueUpdateJobCompletionToUser(UI_.email, N);
WebSocketClientNotificationVenueUpdateJobCompletionToUser(UserInfo().email, N);
Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.", Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.",
JobId(), Updated ,Failed, BadConfigs)); JobId_, Updated ,Failed, BadConfigs));
Utils::SetThreadName("free"); delete this;
Complete();
} }
}; };

View File

@@ -8,7 +8,6 @@
#include "StorageService.h" #include "StorageService.h"
#include "APConfig.h" #include "APConfig.h"
#include "sdks/SDK_gw.h" #include "sdks/SDK_gw.h"
#include "JobController.h"
namespace OpenWifi { namespace OpenWifi {
@@ -49,90 +48,129 @@ namespace OpenWifi {
inline Poco::Logger & Logger() { return Logger_; } inline Poco::Logger & Logger() { return Logger_; }
}; };
class VenueRebooter: public Job { class VenueRebooter: public Poco::Runnable {
public: public:
VenueRebooter(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : explicit VenueRebooter(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
Job(JobID, name, parameters, when, UI, L) { VenueUUID_(VenueUUID),
UI_(UI),
When_(When),
Logger_(L)
{
} }
inline virtual void run() final { inline std::string Start() {
JobId_ = MicroService::CreateUUID();
Worker_.start(*this);
return JobId_;
}
Utils::SetThreadName("venue-reboot"); private:
std::string VenueUUID_;
SecurityObjects::UserInfo UI_;
uint64_t When_;
Poco::Logger &Logger_;
Poco::Thread Worker_;
std::string JobId_;
Poco::ThreadPool Pool_{2,16,300};
inline Poco::Logger & Logger() { return Logger_; }
inline void run() final {
if(When_ && When_>OpenWifi::Now())
Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 );
WebSocketClientNotificationVenueRebootList_t N; WebSocketClientNotificationVenueRebootList_t N;
auto VenueUUID_ = Parameter(0);
Logger().information(fmt::format("Job {} Starting.", JobId_));
ProvObjects::Venue Venue; ProvObjects::Venue Venue;
uint64_t rebooted_ = 0, failed_ = 0; uint64_t rebooted_ = 0, failed_ = 0;
if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) {
const std::size_t MaxThreads=16;
struct tState {
Poco::Thread thr_;
VenueDeviceRebooter *task= nullptr;
};
N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name); N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name);
N.content.jobId = JobId(); N.content.jobId = JobId_;
Poco::ThreadPool Pool_; std::array<tState,MaxThreads> Tasks;
std::list<VenueDeviceRebooter*> JobList;
for(const auto &uuid:Venue.devices) { for(const auto &uuid:Venue.devices) {
auto NewTask = new VenueDeviceRebooter(uuid, Venue.info.name, Logger()); auto NewTask = new VenueDeviceRebooter(uuid, Venue.info.name, Logger());
bool TaskAdded=false; // std::cout << "Scheduling config push for " << uuid << std::endl;
while(!TaskAdded) { bool found_slot = false;
if (Pool_.available()) { while (!found_slot) {
JobList.push_back(NewTask); for (auto &cur_task: Tasks) {
Pool_.start(*NewTask); if (cur_task.task == nullptr) {
TaskAdded = true; cur_task.task = NewTask;
continue; cur_task.thr_.start(*NewTask);
found_slot = true;
break;
}
} }
}
for(auto job_it = JobList.begin(); job_it !=JobList.end();) { // Let's look for a slot...
VenueDeviceRebooter * current_job = *job_it; if (!found_slot) {
if(current_job!= nullptr && current_job->done_) { for (auto &cur_task: Tasks) {
if(current_job->rebooted_) if (cur_task.task != nullptr && cur_task.task->started_) {
N.content.success.push_back(current_job->SerialNumber); if (cur_task.thr_.isRunning())
else continue;
N.content.warning.push_back(current_job->SerialNumber); if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
rebooted_ += current_job->rebooted_; cur_task.thr_.join();
failed_ += current_job->failed_; rebooted_ += cur_task.task->rebooted_;
job_it = JobList.erase(job_it); failed_ += cur_task.task->failed_;
delete current_job; cur_task.task->started_ = cur_task.task->done_ = false;
} else { delete cur_task.task;
++job_it; cur_task.task = nullptr;
}
}
}
} }
} }
} }
Logger().debug("Waiting for outstanding update threads to finish."); Logger().debug("Waiting for outstanding update threads to finish.");
Pool_.joinAll(); bool stillTasksRunning=true;
for(auto job_it = JobList.begin(); job_it !=JobList.end();) { while(stillTasksRunning) {
VenueDeviceRebooter * current_job = *job_it; stillTasksRunning = false;
if(current_job!= nullptr && current_job->done_) { for(auto &cur_task:Tasks) {
if(current_job->rebooted_) if(cur_task.task!= nullptr && cur_task.task->started_) {
N.content.success.push_back(current_job->SerialNumber); if(cur_task.thr_.isRunning()) {
else stillTasksRunning = true;
N.content.warning.push_back(current_job->SerialNumber); continue;
rebooted_ += current_job->rebooted_; }
failed_ += current_job->failed_; if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
job_it = JobList.erase(job_it); cur_task.thr_.join();
delete current_job; if(cur_task.task->rebooted_) {
} else { rebooted_++;
++job_it; N.content.success.push_back(cur_task.task->SerialNumber);
} else if(cur_task.task->failed_) {
failed_++;
N.content.warning.push_back(cur_task.task->SerialNumber);
}
cur_task.task->started_ = cur_task.task->done_ = false;
delete cur_task.task;
cur_task.task = nullptr;
}
}
} }
} }
N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.",
JobId(), rebooted_ ,failed_); JobId_, rebooted_ ,failed_);
} else { } else {
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
Logger().warning(N.content.details); Logger().warning(N.content.details);
} }
// std::cout << N.content.details << std::endl; WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N);
WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N);
Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.",
JobId(), rebooted_ ,failed_)); JobId_, rebooted_ ,failed_));
Utils::SetThreadName("free"); delete this;
Complete();
} }
}; };

View File

@@ -11,7 +11,6 @@
#include "APConfig.h" #include "APConfig.h"
#include "sdks/SDK_gw.h" #include "sdks/SDK_gw.h"
#include "sdks/SDK_fms.h" #include "sdks/SDK_fms.h"
#include "JobController.h"
namespace OpenWifi { namespace OpenWifi {
class VenueDeviceUpgrade : public Poco::Runnable { class VenueDeviceUpgrade : public Poco::Runnable {
@@ -31,7 +30,7 @@ namespace OpenWifi {
Storage::ApplyRules(rules_,Device.deviceRules); Storage::ApplyRules(rules_,Device.deviceRules);
if(Device.deviceRules.firmwareUpgrade=="no") { if(Device.deviceRules.firmwareUpgrade=="no") {
poco_debug(Logger(),fmt::format("Skipped Upgrade: {}", Device.serialNumber)); std::cout << "Skipped Upgrade:" << Device.serialNumber << std::endl;
skipped_++; skipped_++;
done_=true; done_=true;
return; return;
@@ -40,25 +39,24 @@ namespace OpenWifi {
FMSObjects::Firmware F; FMSObjects::Firmware F;
if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) { if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) {
if (SDK::GW::Device::Upgrade(nullptr, Device.serialNumber, 0, F.uri)) { if (SDK::GW::Device::Upgrade(nullptr, Device.serialNumber, 0, F.uri)) {
std::cout << "Upgraded:" << Device.serialNumber << " to " << F.uri << std::endl;
Logger().debug(fmt::format("{}: Upgraded.",Device.serialNumber)); Logger().debug(fmt::format("{}: Upgraded.",Device.serialNumber));
upgraded_++; upgraded_++;
} else { } else {
std::cout << "Did not Upgrade:" << Device.serialNumber << " to " << F.uri << std::endl;
Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber)); Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber));
not_connected_++; failed_++;
} }
} else { } else {
Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber)); std::cout << "Did not Upgrade:" << Device.serialNumber << " to <unknown>" << std::endl;
no_firmware_++; failed_++;
} }
} }
done_ = true; done_ = true;
// std::cout << "Done push for " << Device.serialNumber << std::endl; // std::cout << "Done push for " << Device.serialNumber << std::endl;
} }
std::uint64_t upgraded_ = 0, uint64_t upgraded_=0, failed_=0, skipped_=0;
not_connected_ = 0,
skipped_ = 0,
no_firmware_ = 0;
bool started_ = false, bool started_ = false,
done_ = false; done_ = false;
std::string SerialNumber; std::string SerialNumber;
@@ -71,111 +69,132 @@ namespace OpenWifi {
inline Poco::Logger & Logger() { return Logger_; } inline Poco::Logger & Logger() { return Logger_; }
}; };
class VenueUpgrade: public Job { class VenueUpgrade: public Poco::Runnable {
public: public:
VenueUpgrade(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : explicit VenueUpgrade(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
Job(JobID, name, parameters, when, UI, L) { VenueUUID_(VenueUUID),
UI_(UI),
When_(When),
Logger_(L)
{
} }
inline virtual void run() final { inline std::string Start() {
JobId_ = MicroService::CreateUUID();
Worker_.start(*this);
return JobId_;
}
Utils::SetThreadName("venue-upgr"); private:
auto VenueUUID_ = Parameter(0); std::string VenueUUID_;
SecurityObjects::UserInfo UI_;
uint64_t When_;
Poco::Logger &Logger_;
Poco::Thread Worker_;
std::string JobId_;
Poco::ThreadPool Pool_{2,16,300};
WebSocketClientNotificationVenueUpgradeList_t N; inline Poco::Logger & Logger() { return Logger_; }
inline void run() final {
if(When_ && When_>OpenWifi::Now())
Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 );
WebSocketClientNotificationVenueRebootList_t N;
Logger().information(fmt::format("Job {} Starting.", JobId_));
ProvObjects::Venue Venue; ProvObjects::Venue Venue;
uint64_t upgraded_ = 0, uint64_t upgraded_ = 0, failed_ = 0;
not_connected_ = 0,
skipped_ = 0,
no_firmware_ = 0;
if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) {
const std::size_t MaxThreads=16;
struct tState {
Poco::Thread thr_;
VenueDeviceUpgrade *task= nullptr;
};
N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name); N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name);
N.content.jobId = JobId(); N.content.jobId = JobId_;
Poco::ThreadPool Pool_; std::array<tState,MaxThreads> Tasks;
std::list<VenueDeviceUpgrade*> JobList; ProvObjects::DeviceRules Rules;
ProvObjects::DeviceRules Rules;
StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules); StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules);
for(const auto &uuid:Venue.devices) { for(const auto &uuid:Venue.devices) {
auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules, Logger()); auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules,Logger());
bool TaskAdded = false; // std::cout << "Scheduling config push for " << uuid << std::endl;
while (!TaskAdded) { bool found_slot = false;
if (Pool_.available()) { while (!found_slot) {
JobList.push_back(NewTask); for (auto &cur_task: Tasks) {
Pool_.start(*NewTask); if (cur_task.task == nullptr) {
TaskAdded = true; cur_task.task = NewTask;
continue; cur_task.thr_.start(*NewTask);
found_slot = true;
break;
}
}
// Let's look for a slot...
if (!found_slot) {
for (auto &cur_task: Tasks) {
if (cur_task.task != nullptr && cur_task.task->started_) {
if (cur_task.thr_.isRunning())
continue;
if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
cur_task.thr_.join();
upgraded_ += cur_task.task->upgraded_;
failed_ += cur_task.task->failed_;
cur_task.task->started_ = cur_task.task->done_ = false;
delete cur_task.task;
cur_task.task = nullptr;
}
}
}
} }
} }
}
for (auto job_it = JobList.begin(); job_it != JobList.end();) { Logger().debug("Waiting for outstanding update threads to finish.");
VenueDeviceUpgrade *current_job = *job_it; bool stillTasksRunning=true;
if (current_job != nullptr && current_job->done_) { while(stillTasksRunning) {
if (current_job->upgraded_) stillTasksRunning = false;
N.content.success.push_back(current_job->SerialNumber); for(auto &cur_task:Tasks) {
else if (current_job->skipped_) if(cur_task.task!= nullptr && cur_task.task->started_) {
N.content.skipped.push_back(current_job->SerialNumber); if(cur_task.thr_.isRunning()) {
else if (current_job->not_connected_) stillTasksRunning = true;
N.content.not_connected.push_back(current_job->SerialNumber); continue;
else if (current_job->no_firmware_) }
N.content.no_firmware.push_back(current_job->SerialNumber); if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
upgraded_ += current_job->upgraded_; cur_task.thr_.join();
skipped_ += current_job->skipped_; if(cur_task.task->upgraded_) {
no_firmware_ += current_job->no_firmware_; upgraded_++;
not_connected_ += current_job->not_connected_; N.content.success.push_back(cur_task.task->SerialNumber);
job_it = JobList.erase(job_it); } else if(cur_task.task->failed_) {
delete current_job; failed_++;
} else { N.content.warning.push_back(cur_task.task->SerialNumber);
++job_it; }
cur_task.task->started_ = cur_task.task->done_ = false;
delete cur_task.task;
cur_task.task = nullptr;
}
} }
} }
} }
Logger().debug("Waiting for outstanding upgrade threads to finish."); N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
Pool_.joinAll(); JobId_, upgraded_ ,failed_);
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
VenueDeviceUpgrade * current_job = *job_it;
if(current_job!= nullptr && current_job->done_) {
if (current_job->upgraded_)
N.content.success.push_back(current_job->SerialNumber);
else if (current_job->skipped_)
N.content.skipped.push_back(current_job->SerialNumber);
else if (current_job->not_connected_)
N.content.not_connected.push_back(current_job->SerialNumber);
else if (current_job->no_firmware_)
N.content.no_firmware.push_back(current_job->SerialNumber);
upgraded_ += current_job->upgraded_;
skipped_ += current_job->skipped_;
no_firmware_ += current_job->no_firmware_;
not_connected_ += current_job->not_connected_;
job_it = JobList.erase(job_it);
delete current_job;
} else {
++job_it;
}
}
N.content.details = fmt::format("Job {} Completed: {} upgraded, {} not connected, {} skipped, {} no firmware.",
JobId(),
upgraded_ ,
not_connected_,
skipped_,
no_firmware_);
} else { } else {
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
Logger().warning(N.content.details); Logger().warning(N.content.details);
} }
// std::cout << N.content.details << std::endl; WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N);
WebSocketClientNotificationVenueUpgradeCompletionToUser(UserInfo().email,N); Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
Logger().information(N.content.details); JobId_, upgraded_ ,failed_));
Utils::SetThreadName("free"); delete this;
Complete();
} }
}; };
} }

View File

@@ -14,7 +14,7 @@
namespace OpenWifi { namespace OpenWifi {
static const std::string GitUCentralJSONSchemaFile{ static const std::string GitUCentralJSONSchemaFile{
"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; "https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"};
static json DefaultUCentralSchema = R"( static json DefaultUCentralSchema = R"(

View File

@@ -27,11 +27,6 @@ namespace OpenWifi {
inline uint64_t Now() { return std::time(nullptr); }; 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; using namespace std::chrono_literals;
#include "Poco/Util/Application.h" #include "Poco/Util/Application.h"
@@ -243,11 +238,6 @@ namespace OpenWifi::RESTAPI_utils {
Obj.set(Field,Value); Obj.set(Field,Value);
} }
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) {
auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size());
Obj.set(Field,Result);
}
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) { inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
Poco::JSON::Array Array; Poco::JSON::Array Array;
for(const auto &i:S) { for(const auto &i:S) {
@@ -344,12 +334,12 @@ namespace OpenWifi::RESTAPI_utils {
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) { inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
if(Obj->has(Field) && !Obj->isNull(Field)) 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) { inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
if(Obj->has(Field) && !Obj->isNull(Field)) 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) { inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
@@ -384,14 +374,7 @@ namespace OpenWifi::RESTAPI_utils {
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) { inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
if(Obj->has(Field) && !Obj->isNull(Field)) 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) { inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
@@ -660,27 +643,6 @@ namespace OpenWifi::RESTAPI_utils {
namespace OpenWifi::Utils { namespace OpenWifi::Utils {
inline void SetThreadName(const char *name) {
#ifdef __linux__
Poco::Thread::current()->setName(name);
pthread_setname_np(pthread_self(), name);
#endif
#ifdef __APPLE__
Poco::Thread::current()->setName(name);
pthread_setname_np(name);
#endif
}
inline void SetThreadName(Poco::Thread &thr, const char *name) {
#ifdef __linux__
thr.setName(name);
pthread_setname_np(thr.tid(), name);
#endif
#ifdef __APPLE__
thr.setName(name);
#endif
}
enum MediaTypeEncodings { enum MediaTypeEncodings {
PLAIN, PLAIN,
BINARY, BINARY,
@@ -703,19 +665,6 @@ namespace OpenWifi::Utils {
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0); 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=',' ) { [[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) {
std::vector<std::string> ReturnList; std::vector<std::string> ReturnList;
@@ -1367,7 +1316,7 @@ namespace OpenWifi {
inline void Start(); inline void Start();
inline void Stop(); inline void Stop();
private: private:
mutable std::atomic_bool Running_ = false; std::atomic_bool Running_ = false;
Poco::Thread Thread_; Poco::Thread Thread_;
}; };
@@ -1412,14 +1361,13 @@ namespace OpenWifi {
[[nodiscard]] inline const std::string &Address() const { return address_; }; [[nodiscard]] inline const std::string &Address() const { return address_; };
[[nodiscard]] inline uint32_t Port() const { return port_; }; [[nodiscard]] inline uint32_t Port() const { return port_; };
[[nodiscard]] inline auto KeyFile() const { return key_file_; }; [[nodiscard]] inline const std::string &KeyFile() const { return key_file_; };
[[nodiscard]] inline auto CertFile() const { return cert_file_; }; [[nodiscard]] inline const std::string &CertFile() const { return cert_file_; };
[[nodiscard]] inline auto RootCA() const { return root_ca_; }; [[nodiscard]] inline const std::string &RootCA() const { return root_ca_; };
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; }; [[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; };
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; }; [[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; };
[[nodiscard]] inline auto Name() const { return name_; }; [[nodiscard]] inline const std::string &Name() const { return name_; };
[[nodiscard]] inline int Backlog() const { return backlog_; } [[nodiscard]] inline int Backlog() const { return backlog_; }
[[nodiscard]] inline auto Cas() const { return cas_; }
[[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const { [[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const {
Poco::Net::Context::Params P; Poco::Net::Context::Params P;
@@ -1899,8 +1847,7 @@ namespace OpenWifi {
Request = &RequestIn; Request = &RequestIn;
Response = &ResponseIn; Response = &ResponseIn;
// std::string th_name = "restsvr_" + std::to_string(TransactionId_); Poco::Thread::current()->setName("WebServerThread_" + std::to_string(TransactionId_));
// Utils::SetThreadName(th_name.c_str());
if(Request->getContentLength()>0) { if(Request->getContentLength()>0) {
if(Request->getContentType().find("application/json")!=std::string::npos) { if(Request->getContentType().find("application/json")!=std::string::npos) {
@@ -2095,17 +2042,6 @@ namespace OpenWifi {
return false; 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) { template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
if(O->has(Field)) { if(O->has(Field)) {
assignee = value; assignee = value;
@@ -2446,7 +2382,6 @@ namespace OpenWifi {
Poco::Net::HTTPServerResponse *Response= nullptr; Poco::Net::HTTPServerResponse *Response= nullptr;
SecurityObjects::UserInfoAndPolicy UserInfo_; SecurityObjects::UserInfoAndPolicy UserInfo_;
QueryBlock QB_; QueryBlock QB_;
const std::string & Requester() const { return REST_Requester_; }
protected: protected:
BindingMap Bindings_; BindingMap Bindings_;
Poco::URI::QueryParameters Parameters_; Poco::URI::QueryParameters Parameters_;
@@ -2463,7 +2398,6 @@ namespace OpenWifi {
RateLimit MyRates_; RateLimit MyRates_;
uint64_t TransactionId_; uint64_t TransactionId_;
Poco::JSON::Object::Ptr ParsedBody_; Poco::JSON::Object::Ptr ParsedBody_;
std::string REST_Requester_;
}; };
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler { class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
@@ -2645,7 +2579,7 @@ namespace OpenWifi {
private: private:
std::recursive_mutex Mutex_; std::recursive_mutex Mutex_;
Poco::Thread Worker_; Poco::Thread Worker_;
mutable std::atomic_bool Running_=false; std::atomic_bool Running_=false;
Poco::NotificationQueue Queue_; Poco::NotificationQueue Queue_;
}; };
@@ -2671,7 +2605,7 @@ namespace OpenWifi {
private: private:
std::recursive_mutex Mutex_; std::recursive_mutex Mutex_;
Poco::Thread Worker_; Poco::Thread Worker_;
mutable std::atomic_bool Running_=false; std::atomic_bool Running_=false;
}; };
class KafkaDispatcher : public Poco::Runnable { class KafkaDispatcher : public Poco::Runnable {
@@ -2728,7 +2662,6 @@ namespace OpenWifi {
inline void run() override { inline void run() override {
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification()); Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("kafka:dispatch");
while(Note && Running_) { while(Note && Running_) {
auto Msg = dynamic_cast<KafkaMessage*>(Note.get()); auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
if(Msg!= nullptr) { if(Msg!= nullptr) {
@@ -2751,12 +2684,12 @@ namespace OpenWifi {
} }
private: private:
std::recursive_mutex Mutex_; std::recursive_mutex Mutex_;
Types::NotifyTable Notifiers_; Types::NotifyTable Notifiers_;
Poco::Thread Worker_; Poco::Thread Worker_;
mutable std::atomic_bool Running_=false; std::atomic_bool Running_=false;
uint64_t FunctionId_=1; uint64_t FunctionId_=1;
Poco::NotificationQueue Queue_; Poco::NotificationQueue Queue_;
}; };
class KafkaManager : public SubSystemServer { class KafkaManager : public SubSystemServer {
@@ -2949,7 +2882,6 @@ namespace OpenWifi {
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override
{ {
Utils::SetThreadName("alb-request");
try { try {
if((id_ % 100) == 0) { if((id_ % 100) == 0) {
Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.",
@@ -3018,7 +2950,7 @@ namespace OpenWifi {
std::unique_ptr<Poco::Net::HTTPServer> Server_; std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_; std::unique_ptr<Poco::Net::ServerSocket> Socket_;
int Port_ = 0; int Port_ = 0;
mutable std::atomic_bool Running_=false; std::atomic_bool Running_=false;
}; };
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); } inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
@@ -3038,7 +2970,7 @@ namespace OpenWifi {
} }
int Start() override; int Start() override;
inline void Stop() override { inline void Stop() override {
Logger().information("Stopping..."); Logger().information("Stopping ");
for( const auto & svr : RESTServers_ ) for( const auto & svr : RESTServers_ )
svr->stop(); svr->stop();
Pool_.stopAll(); Pool_.stopAll();
@@ -3046,23 +2978,22 @@ namespace OpenWifi {
RESTServers_.clear(); RESTServers_.clear();
} }
inline void reinitialize(Poco::Util::Application &self) override; inline void reinitialize(Poco::Util::Application &self) override;
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings; RESTAPIHandler::BindingMap Bindings;
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str()); Poco::Thread::current()->setName(fmt::format("RESTAPI_ExtServer_{}",Id));
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id); return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
} }
const Poco::ThreadPool & Pool() { return Pool_; }
private: private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_; std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_{"x-rest",2,32}; Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_; RESTAPI_GenericServer Server_;
RESTAPI_ExtServer() noexcept: RESTAPI_ExtServer() noexcept:
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi") SubSystemServer("RESTAPI_ExtServer", "RESTAPIServer", "openwifi.restapi"),
Pool_("RESTAPI_ExtServer",4,50,120)
{ {
} }
}; };
@@ -3075,7 +3006,7 @@ namespace OpenWifi {
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
try { try {
Poco::URI uri(Request.getURI()); Poco::URI uri(Request.getURI());
Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str()); Poco::Thread::current()->setName(fmt::format("ExtWebServer_{}",TransactionId_));
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++); return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
} catch (...) { } catch (...) {
@@ -3173,7 +3104,7 @@ namespace OpenWifi {
inline int Start() override; inline int Start() override;
inline void Stop() override { inline void Stop() override {
Logger().information("Stopping..."); Logger().information("Stopping ");
for( const auto & svr : RESTServers_ ) for( const auto & svr : RESTServers_ )
svr->stop(); svr->stop();
Pool_.stopAll(); Pool_.stopAll();
@@ -3184,18 +3115,17 @@ namespace OpenWifi {
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) { inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings; RESTAPIHandler::BindingMap Bindings;
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str()); Poco::Thread::current()->setName(fmt::format("RESTAPI_IntServer_{}",Id));
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id); return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
} }
const Poco::ThreadPool & Pool() { return Pool_; }
private: private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_; std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_{"i-rest",2,16}; Poco::ThreadPool Pool_;
RESTAPI_GenericServer Server_; RESTAPI_GenericServer Server_;
RESTAPI_IntServer() noexcept: RESTAPI_IntServer() noexcept:
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi") SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi"),
Pool_("RESTAPI_IntServer",4,50,120)
{ {
} }
}; };
@@ -3206,7 +3136,6 @@ namespace OpenWifi {
public: public:
inline IntRequestHandlerFactory() = default; inline IntRequestHandlerFactory() = default;
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override { 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()); Poco::URI uri(Request.getURI());
return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_); return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_);
} }
@@ -3250,6 +3179,7 @@ namespace OpenWifi {
} }
[[nodiscard]] std::string Version() { return Version_; } [[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 & DataDir() { return DataDir_; }
[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; } [[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; }
[[nodiscard]] bool Debug() const { return DebugMode_; } [[nodiscard]] bool Debug() const { return DebugMode_; }
@@ -3282,12 +3212,7 @@ namespace OpenWifi {
return Poco::Logger::get(Name); return Poco::Logger::get(Name);
} }
virtual void GetExtraConfiguration(Poco::JSON::Object & Cfg) { static inline void Exit(int Reason);
Cfg.set("additionalConfiguration",false);
}
static inline void Exit(int Reason);
inline void BusMessageReceived(const std::string &Key, const std::string & Payload); inline void BusMessageReceived(const std::string &Key, const std::string & Payload);
inline MicroServiceMetaVec GetServices(const std::string & Type); inline MicroServiceMetaVec GetServices(const std::string & Type);
inline MicroServiceMetaVec GetServices(); inline MicroServiceMetaVec GetServices();
@@ -3323,6 +3248,7 @@ namespace OpenWifi {
inline std::string ConfigPath(const std::string &Key); inline std::string ConfigPath(const std::string &Key);
inline std::string Encrypt(const std::string &S); inline std::string Encrypt(const std::string &S);
inline std::string Decrypt(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; inline std::string MakeSystemEventMessage( const std::string & Type ) const;
[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request); [[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
inline static void SavePID(); inline static void SavePID();
@@ -3352,9 +3278,6 @@ namespace OpenWifi {
return Signer_.sign(T,Algo); return Signer_.sign(T,Algo);
} }
} }
inline Poco::ThreadPool & TimerPool() { return TimerPool_; }
private: private:
static MicroService * instance_; static MicroService * instance_;
bool HelpRequested_ = false; bool HelpRequested_ = false;
@@ -3368,6 +3291,7 @@ namespace OpenWifi {
std::string WWWAssetsDir_; std::string WWWAssetsDir_;
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory(); Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
Poco::Crypto::Cipher * Cipher_ = nullptr; Poco::Crypto::Cipher * Cipher_ = nullptr;
Poco::SHA2Engine SHA2_;
MicroServiceMetaMap Services_; MicroServiceMetaMap Services_;
std::string MyHash_; std::string MyHash_;
std::string MyPrivateEndPoint_; std::string MyPrivateEndPoint_;
@@ -3388,7 +3312,6 @@ namespace OpenWifi {
bool NoBuiltInCrypto_=false; bool NoBuiltInCrypto_=false;
Poco::JWT::Signer Signer_; Poco::JWT::Signer Signer_;
Poco::Logger &Logger_; Poco::Logger &Logger_;
Poco::ThreadPool TimerPool_{"timer:pool",2,16};
}; };
inline void MicroService::Exit(int Reason) { inline void MicroService::Exit(int Reason) {
@@ -3538,7 +3461,7 @@ namespace OpenWifi {
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private"); MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public"); MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
UIURI_ = ConfigGetString("openwifi.system.uri.ui"); UIURI_ = ConfigGetString("openwifi.system.uri.ui");
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_); MyHash_ = CreateHash(MyPublicEndPoint_);
} }
void MicroServicePostInitialization(); void MicroServicePostInitialization();
@@ -3601,7 +3524,7 @@ namespace OpenWifi {
void DaemonPostInitialization(Poco::Util::Application &self); void DaemonPostInitialization(Poco::Util::Application &self);
inline void MicroService::initialize(Poco::Util::Application &self) { inline void MicroService::initialize(Poco::Util::Application &self) {
// add the default services // add the default services
LoadConfigurationFile(); LoadConfigurationFile();
InitializeLoggingSystem(); InitializeLoggingSystem();
@@ -3875,6 +3798,11 @@ namespace OpenWifi {
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);; 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 { inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
Poco::JSON::Object Obj; Poco::JSON::Object Obj;
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type); Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
@@ -3937,7 +3865,6 @@ namespace OpenWifi {
Params->setMaxThreads(50); Params->setMaxThreads(50);
Params->setMaxQueued(200); Params->setMaxQueued(200);
Params->setKeepAlive(true); Params->setKeepAlive(true);
Params->setName("ws:xrest");
std::unique_ptr<Poco::Net::HTTPServer> NewServer; std::unique_ptr<Poco::Net::HTTPServer> NewServer;
if(MicroService::instance().NoAPISecurity()) { if(MicroService::instance().NoAPISecurity()) {
@@ -3974,7 +3901,6 @@ namespace OpenWifi {
Params->setMaxThreads(50); Params->setMaxThreads(50);
Params->setMaxQueued(200); Params->setMaxQueued(200);
Params->setKeepAlive(true); Params->setKeepAlive(true);
Params->setName("ws:irest");
std::unique_ptr<Poco::Net::HTTPServer> NewServer; std::unique_ptr<Poco::Net::HTTPServer> NewServer;
if(MicroService::instance().NoAPISecurity()) { if(MicroService::instance().NoAPISecurity()) {
@@ -3992,6 +3918,7 @@ namespace OpenWifi {
} }
inline int MicroService::main([[maybe_unused]] const ArgVec &args) { inline int MicroService::main([[maybe_unused]] const ArgVec &args) {
MyErrorHandler ErrorHandler(*this); MyErrorHandler ErrorHandler(*this);
Poco::ErrorHandler::set(&ErrorHandler); Poco::ErrorHandler::set(&ErrorHandler);
@@ -4098,7 +4025,6 @@ namespace OpenWifi {
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015); Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_); Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
auto Params = new Poco::Net::HTTPServerParams; auto Params = new Poco::Net::HTTPServerParams;
Params->setName("ws:alb");
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params); Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
Server_->start(); Server_->start();
} }
@@ -4108,7 +4034,6 @@ namespace OpenWifi {
inline void BusEventManager::run() { inline void BusEventManager::run() {
Running_ = true; Running_ = true;
Utils::SetThreadName("fmwk:EventMgr");
auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN); auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false); KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false);
while(Running_) { while(Running_) {
@@ -4194,8 +4119,6 @@ namespace OpenWifi {
} }
inline void KafkaProducer::run() { inline void KafkaProducer::run() {
Utils::SetThreadName("Kafka:Prod");
cppkafka::Configuration Config({ cppkafka::Configuration Config({
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") } { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
@@ -4234,8 +4157,6 @@ namespace OpenWifi {
} }
inline void KafkaConsumer::run() { inline void KafkaConsumer::run() {
Utils::SetThreadName("Kafka:Cons");
cppkafka::Configuration Config({ cppkafka::Configuration Config({
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") }, { "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }, { "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") },
@@ -4374,11 +4295,6 @@ namespace OpenWifi {
Answer.set("certificates", Certificates); Answer.set("certificates", Certificates);
return ReturnObject(Answer); return ReturnObject(Answer);
} }
if(GetBoolParameter("extraConfiguration")) {
Poco::JSON::Object Answer;
MicroService::instance().GetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
BadRequest(RESTAPI::Errors::InvalidCommand); BadRequest(RESTAPI::Errors::InvalidCommand);
} }
@@ -4751,7 +4667,6 @@ namespace OpenWifi {
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) { inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
if(Internal_ && Request->has("X-INTERNAL-NAME")) { if(Internal_ && Request->has("X-INTERNAL-NAME")) {
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request); auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
Contacted = true;
if(!Allowed) { if(!Allowed) {
if(Server_.LogBadTokens(false)) { if(Server_.LogBadTokens(false)) {
Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}", Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}",
@@ -4760,7 +4675,6 @@ namespace OpenWifi {
} }
} else { } else {
auto Id = Request->get("X-INTERNAL-NAME", "unknown"); auto Id = Request->get("X-INTERNAL-NAME", "unknown");
REST_Requester_ = Id;
if(Server_.LogIt(Request->getMethod(),true)) { if(Server_.LogIt(Request->getMethod(),true)) {
Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}", Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()), Id, Utils::FormatIPv6(Request->clientAddress().toString()), Id,
@@ -4784,7 +4698,6 @@ namespace OpenWifi {
#else #else
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) { if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) {
#endif #endif
REST_Requester_ = UserInfo_.userinfo.email;
if(Server_.LogIt(Request->getMethod(),true)) { if(Server_.LogIt(Request->getMethod(),true)) {
Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}", Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}",
UserInfo_.userinfo.email, UserInfo_.userinfo.email,
@@ -4867,7 +4780,7 @@ namespace OpenWifi {
void run() override; void run() override;
// MyParallelSocketReactor &ReactorPool(); // MyParallelSocketReactor &ReactorPool();
Poco::Net::SocketReactor & Reactor() { return Reactor_; } Poco::Net::SocketReactor & Reactor() { return Reactor_; }
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName); void NewClient(Poco::Net::WebSocket &WS, const std::string &Id);
bool Register(WebSocketClient *Client, const std::string &Id); bool Register(WebSocketClient *Client, const std::string &Id);
void SetProcessor(WebSocketClientProcessor *F); void SetProcessor(WebSocketClientProcessor *F);
void UnRegister(const std::string &Id); void UnRegister(const std::string &Id);
@@ -4902,8 +4815,8 @@ namespace OpenWifi {
[[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload); [[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload);
void SendToAll(const std::string &Payload); void SendToAll(const std::string &Payload);
private: private:
mutable std::atomic_bool Running_ = false; std::atomic_bool Running_ = false;
Poco::Thread Thr_; Poco::Thread Thr_;
// std::unique_ptr<MyParallelSocketReactor> ReactorPool_; // std::unique_ptr<MyParallelSocketReactor> ReactorPool_;
Poco::Net::SocketReactor Reactor_; Poco::Net::SocketReactor Reactor_;
Poco::Thread ReactorThread_; Poco::Thread ReactorThread_;
@@ -4918,22 +4831,18 @@ namespace OpenWifi {
class WebSocketClient { class WebSocketClient {
public: public:
explicit WebSocketClient(Poco::Net::WebSocket &WS, explicit WebSocketClient(Poco::Net::WebSocket &WS, const std::string &Id, Poco::Logger &L,
const std::string &Id, WebSocketClientProcessor *Processor);
const std::string &UserName,
Poco::Logger &L,
WebSocketClientProcessor *Processor);
virtual ~WebSocketClient(); virtual ~WebSocketClient();
[[nodiscard]] inline const std::string &Id(); [[nodiscard]] inline const std::string &Id();
[[nodiscard]] Poco::Logger &Logger(); [[nodiscard]] Poco::Logger &Logger();
inline bool Send(const std::string &Payload); inline bool Send(const std::string &Payload);
private: private:
std::unique_ptr<Poco::Net::WebSocket> WS_; std::unique_ptr<Poco::Net::WebSocket> WS_;
Poco::Net::SocketReactor &Reactor_; Poco::Net::SocketReactor &Reactor_;
std::string Id_; std::string Id_;
std::string UserName_; Poco::Logger &Logger_;
Poco::Logger &Logger_; bool Authenticated_ = false;
std::atomic_bool Authenticated_ = false;
SecurityObjects::UserInfoAndPolicy UserInfo_; SecurityObjects::UserInfoAndPolicy UserInfo_;
WebSocketClientProcessor *Processor_ = nullptr; WebSocketClientProcessor *Processor_ = nullptr;
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf); void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
@@ -4941,9 +4850,33 @@ namespace OpenWifi {
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf); void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
}; };
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) { /* 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) {
std::lock_guard G(Mutex_); std::lock_guard G(Mutex_);
auto Client = new WebSocketClient(WS,Id,UserName,Logger(), Processor_); auto Client = new WebSocketClient(WS,Id,Logger(), Processor_);
Clients_[Id] = std::make_pair(Client,""); Clients_[Id] = std::make_pair(Client,"");
} }
@@ -4973,13 +4906,12 @@ namespace OpenWifi {
[[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload); [[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload);
inline WebSocketClientServer::WebSocketClientServer() noexcept: inline WebSocketClientServer::WebSocketClientServer() noexcept:
SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients") SubSystemServer("WebSocketClientServer", "WSCLNT-SVR", "websocketclients")
{ {
} }
inline void WebSocketClientServer::run() { inline void WebSocketClientServer::run() {
Running_ = true ; Running_ = true ;
Utils::SetThreadName("ws:uiclnt-svr");
while(Running_) { while(Running_) {
Poco::Thread::trySleep(2000); Poco::Thread::trySleep(2000);
@@ -5027,12 +4959,8 @@ namespace OpenWifi {
for(const auto &client:Clients_) { for(const auto &client:Clients_) {
if(client.second.second == UserName) { if(client.second.second == UserName) {
try { if(client.second.first->Send(Payload))
if (client.second.first->Send(Payload)) Sent++;
Sent++;
} catch (...) {
return false;
}
} }
} }
return Sent>0; return Sent>0;
@@ -5054,73 +4982,70 @@ namespace OpenWifi {
int flags; int flags;
int n; int n;
bool Done=false; bool Done=false;
try { Poco::Buffer<char> IncomingFrame(0);
Poco::Buffer<char> IncomingFrame(0); n = WS_->receiveFrame(IncomingFrame, flags);
n = WS_->receiveFrame(IncomingFrame, flags); auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
if (n == 0) { if(n==0) {
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_)); return delete this;
return delete this; }
}
switch (Op) { switch(Op) {
case Poco::Net::WebSocket::FRAME_OP_PING: { case Poco::Net::WebSocket::FRAME_OP_PING: {
WS_->sendFrame("", 0, WS_->sendFrame("", 0,
(int)Poco::Net::WebSocket::FRAME_OP_PONG | (int)Poco::Net::WebSocket::FRAME_OP_PONG |
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN); (int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
} break; }
case Poco::Net::WebSocket::FRAME_OP_PONG: { break;
} break; case Poco::Net::WebSocket::FRAME_OP_PONG: {
case Poco::Net::WebSocket::FRAME_OP_CLOSE: { }
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_)); break;
Done = true; case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
} break; Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.",Id_));
case Poco::Net::WebSocket::FRAME_OP_TEXT: { Done=true;
IncomingFrame.append(0); }
if (!Authenticated_) { break;
std::string Frame{IncomingFrame.begin()}; case Poco::Net::WebSocket::FRAME_OP_TEXT: {
auto Tokens = Utils::Split(Frame, ':'); IncomingFrame.append(0);
bool Expired = false, Contacted = false; if(!Authenticated_) {
if (Tokens.size() == 2 && std::string Frame{IncomingFrame.begin()};
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) { auto Tokens = Utils::Split(Frame,':');
Authenticated_ = true; bool Expired = false, Contacted = false;
UserName_ = UserInfo_.userinfo.email; if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
Logger().warning(Poco::format("START(%s): %s UI Client is starting WS connection.", Id_, UserName_)); Authenticated_=true;
std::string S{"Welcome! Bienvenue! Bienvenidos!"}; std::string S{"Welcome! Bienvenue! Bienvenidos!"};
WS_->sendFrame(S.c_str(), S.size()); WS_->sendFrame(S.c_str(),S.size());
WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email); WebSocketClientServer()->SetUser(Id_,UserInfo_.userinfo.email);
} else { } else {
std::string S{"Invalid token. Closing connection."}; std::string S{"Invalid token. Closing connection."};
WS_->sendFrame(S.c_str(), S.size()); WS_->sendFrame(S.c_str(),S.size());
Done = true; Done=true;
} }
} else { } else {
try { try {
Poco::JSON::Parser P; Poco::JSON::Parser P;
auto Obj = auto Obj = P.parse(IncomingFrame.begin())
P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>(); .extract<Poco::JSON::Object::Ptr>();
std::string Answer; std::string Answer;
if (Processor_ != nullptr) if(Processor_!= nullptr)
Processor_->Processor(Obj, Answer, Done); Processor_->Processor(Obj, Answer, Done);
if (!Answer.empty()) if (!Answer.empty())
WS_->sendFrame(Answer.c_str(), (int)Answer.size()); WS_->sendFrame(Answer.c_str(), (int) Answer.size());
else { else {
WS_->sendFrame("{}", 2); WS_->sendFrame("{}", 2);
} }
} catch (const Poco::JSON::JSONException &E) { } catch (const Poco::JSON::JSONException & E) {
Logger().log(E); Logger().log(E);
Done=true; }
} }
} }
} break; break;
default: { default:
} {
}
} catch (...) { }
Done=true; }
}
if(Done) { if(Done) {
delete this; delete this;
@@ -5132,10 +5057,9 @@ namespace OpenWifi {
} }
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, const std::string &UserName, Poco::Logger & L, WebSocketClientProcessor * Processor) : inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, Poco::Logger & L, WebSocketClientProcessor * Processor) :
Reactor_(WebSocketClientServer()->Reactor()), Reactor_(WebSocketClientServer()->Reactor()),
Id_(Id), Id_(Id),
UserName_(UserName),
Logger_(L), Logger_(L),
Processor_(Processor) { Processor_(Processor) {
try { try {
@@ -5215,8 +5139,9 @@ namespace OpenWifi {
try try
{ {
Poco::Net::WebSocket WS(*Request, *Response); Poco::Net::WebSocket WS(*Request, *Response);
Logger().information("WebSocket connection established.");
auto Id = MicroService::CreateUUID(); auto Id = MicroService::CreateUUID();
WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email); WebSocketClientServer()->NewClient(WS,Id);
} }
catch (...) { catch (...) {
std::cout << "Cannot create websocket client..." << std::endl; std::cout << "Cannot create websocket client..." << std::endl;

View File

@@ -146,10 +146,6 @@ namespace OpenWifi {
WebSocketClientServer()->SendUserNotification(User,N); WebSocketClientServer()->SendUserNotification(User,N);
} }
/////
/////
/////
struct WebSocketNotificationRebootList { struct WebSocketNotificationRebootList {
std::string title, std::string title,
details, details,
@@ -193,58 +189,5 @@ namespace OpenWifi {
WebSocketClientServer()->SendUserNotification(User,N); 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 } // namespace OpenWifi

View File

@@ -133,37 +133,6 @@ namespace ORM {
return R; 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 SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE };
enum SqlBinaryOp { AND = 0 , OR }; enum SqlBinaryOp { AND = 0 , OR };

View File

@@ -1,937 +0,0 @@
/*
MIT License
Copyright (c) 2018 Marius Bancila
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This file is from https://github.com/mariusbancila/croncpp.git.
*/
#pragma once
#include <vector>
#include <string>
#include <sstream>
#include <bitset>
#include <cctype>
#include <ctime>
#include <iomanip>
#include <algorithm>
#include <chrono>
#if __cplusplus > 201402L
#include <string_view>
#define CRONCPP_IS_CPP17
#endif
namespace cron
{
#ifdef CRONCPP_IS_CPP17
#define CRONCPP_STRING_VIEW std::string_view
#define CRONCPP_STRING_VIEW_NPOS std::string_view::npos
#define CRONCPP_CONSTEXPTR constexpr
#else
#define CRONCPP_STRING_VIEW std::string const &
#define CRONCPP_STRING_VIEW_NPOS std::string::npos
#define CRONCPP_CONSTEXPTR
#endif
using cron_int = uint8_t;
constexpr std::time_t INVALID_TIME = static_cast<std::time_t>(-1);
constexpr size_t INVALID_INDEX = static_cast<size_t>(-1);
class cronexpr;
namespace detail
{
enum class cron_field
{
second,
minute,
hour_of_day,
day_of_week,
day_of_month,
month,
year
};
template <typename Traits>
static bool find_next(cronexpr const & cex,
std::tm& date,
size_t const dot);
}
struct bad_cronexpr : public std::runtime_error
{
public:
explicit bad_cronexpr(CRONCPP_STRING_VIEW message) :
std::runtime_error(message.data())
{}
};
struct cron_standard_traits
{
static const cron_int CRON_MIN_SECONDS = 0;
static const cron_int CRON_MAX_SECONDS = 59;
static const cron_int CRON_MIN_MINUTES = 0;
static const cron_int CRON_MAX_MINUTES = 59;
static const cron_int CRON_MIN_HOURS = 0;
static const cron_int CRON_MAX_HOURS = 23;
static const cron_int CRON_MIN_DAYS_OF_WEEK = 0;
static const cron_int CRON_MAX_DAYS_OF_WEEK = 6;
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
static const cron_int CRON_MIN_MONTHS = 1;
static const cron_int CRON_MAX_MONTHS = 12;
static const cron_int CRON_MAX_YEARS_DIFF = 4;
#ifdef CRONCPP_IS_CPP17
static const inline std::vector<std::string> DAYS = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
#else
static std::vector<std::string>& DAYS()
{
static std::vector<std::string> days = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
return days;
}
static std::vector<std::string>& MONTHS()
{
static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
return months;
}
#endif
};
struct cron_oracle_traits
{
static const cron_int CRON_MIN_SECONDS = 0;
static const cron_int CRON_MAX_SECONDS = 59;
static const cron_int CRON_MIN_MINUTES = 0;
static const cron_int CRON_MAX_MINUTES = 59;
static const cron_int CRON_MIN_HOURS = 0;
static const cron_int CRON_MAX_HOURS = 23;
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
static const cron_int CRON_MIN_MONTHS = 0;
static const cron_int CRON_MAX_MONTHS = 11;
static const cron_int CRON_MAX_YEARS_DIFF = 4;
#ifdef CRONCPP_IS_CPP17
static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
static const inline std::vector<std::string> MONTHS = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
#else
static std::vector<std::string>& DAYS()
{
static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
return days;
}
static std::vector<std::string>& MONTHS()
{
static std::vector<std::string> months = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
return months;
}
#endif
};
struct cron_quartz_traits
{
static const cron_int CRON_MIN_SECONDS = 0;
static const cron_int CRON_MAX_SECONDS = 59;
static const cron_int CRON_MIN_MINUTES = 0;
static const cron_int CRON_MAX_MINUTES = 59;
static const cron_int CRON_MIN_HOURS = 0;
static const cron_int CRON_MAX_HOURS = 23;
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
static const cron_int CRON_MIN_MONTHS = 1;
static const cron_int CRON_MAX_MONTHS = 12;
static const cron_int CRON_MAX_YEARS_DIFF = 4;
#ifdef CRONCPP_IS_CPP17
static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
#else
static std::vector<std::string>& DAYS()
{
static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
return days;
}
static std::vector<std::string>& MONTHS()
{
static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
return months;
}
#endif
};
class cronexpr;
template <typename Traits = cron_standard_traits>
static cronexpr make_cron(CRONCPP_STRING_VIEW expr);
class cronexpr
{
std::bitset<60> seconds;
std::bitset<60> minutes;
std::bitset<24> hours;
std::bitset<7> days_of_week;
std::bitset<31> days_of_month;
std::bitset<12> months;
std::string expr;
friend bool operator==(cronexpr const & e1, cronexpr const & e2);
friend bool operator!=(cronexpr const & e1, cronexpr const & e2);
template <typename Traits>
friend bool detail::find_next(cronexpr const & cex,
std::tm& date,
size_t const dot);
friend std::string to_cronstr(cronexpr const& cex);
friend std::string to_string(cronexpr const & cex);
template <typename Traits>
friend cronexpr make_cron(CRONCPP_STRING_VIEW expr);
};
inline bool operator==(cronexpr const & e1, cronexpr const & e2)
{
return
e1.seconds == e2.seconds &&
e1.minutes == e2.minutes &&
e1.hours == e2.hours &&
e1.days_of_week == e2.days_of_week &&
e1.days_of_month == e2.days_of_month &&
e1.months == e2.months;
}
inline bool operator!=(cronexpr const & e1, cronexpr const & e2)
{
return !(e1 == e2);
}
inline std::string to_string(cronexpr const & cex)
{
return
cex.seconds.to_string() + " " +
cex.minutes.to_string() + " " +
cex.hours.to_string() + " " +
cex.days_of_month.to_string() + " " +
cex.months.to_string() + " " +
cex.days_of_week.to_string();
}
inline std::string to_cronstr(cronexpr const& cex)
{
return cex.expr;
}
namespace utils
{
inline std::time_t tm_to_time(std::tm& date)
{
return std::mktime(&date);
}
inline std::tm* time_to_tm(std::time_t const * date, std::tm* const out)
{
#ifdef _WIN32
errno_t err = localtime_s(out, date);
return 0 == err ? out : nullptr;
#else
return localtime_r(date, out);
#endif
}
inline std::tm to_tm(CRONCPP_STRING_VIEW time)
{
std::tm result;
#if __cplusplus > 201103L
std::istringstream str(time.data());
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
str >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
if (str.fail()) throw std::runtime_error("Parsing date failed!");
#else
int year = 1900;
int month = 1;
int day = 1;
int hour = 0;
int minute = 0;
int second = 0;
sscanf(time.data(), "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
result.tm_year = year - 1900;
result.tm_mon = month - 1;
result.tm_mday = day;
result.tm_hour = hour;
result.tm_min = minute;
result.tm_sec = second;
#endif
result.tm_isdst = -1; // DST info not available
return result;
}
inline std::string to_string(std::tm const & tm)
{
#if __cplusplus > 201103L
std::ostringstream str;
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
str << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
if (str.fail()) throw std::runtime_error("Writing date failed!");
return str.str();
#else
char buff[70] = {0};
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm);
return std::string(buff);
#endif
}
inline std::string to_upper(std::string text)
{
std::transform(std::begin(text), std::end(text),
std::begin(text), [](char const c) { return static_cast<char>(std::toupper(c)); });
return text;
}
static std::vector<std::string> split(CRONCPP_STRING_VIEW text, char const delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(text.data());
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}
CRONCPP_CONSTEXPTR inline bool contains(CRONCPP_STRING_VIEW text, char const ch) noexcept
{
return CRONCPP_STRING_VIEW_NPOS != text.find_first_of(ch);
}
}
namespace detail
{
inline cron_int to_cron_int(CRONCPP_STRING_VIEW text)
{
try
{
return static_cast<cron_int>(std::stoul(text.data()));
}
catch (std::exception const & ex)
{
throw bad_cronexpr(ex.what());
}
}
static std::string replace_ordinals(
std::string text,
std::vector<std::string> const & replacement)
{
for (size_t i = 0; i < replacement.size(); ++i)
{
auto pos = text.find(replacement[i]);
if (std::string::npos != pos)
text.replace(pos, 3 ,std::to_string(i));
}
return text;
}
static std::pair<cron_int, cron_int> make_range(
CRONCPP_STRING_VIEW field,
cron_int const minval,
cron_int const maxval)
{
cron_int first = 0;
cron_int last = 0;
if (field.size() == 1 && field[0] == '*')
{
first = minval;
last = maxval;
}
else if (!utils::contains(field, '-'))
{
first = to_cron_int(field);
last = first;
}
else
{
auto parts = utils::split(field, '-');
if (parts.size() != 2)
throw bad_cronexpr("Specified range requires two fields");
first = to_cron_int(parts[0]);
last = to_cron_int(parts[1]);
}
if (first > maxval || last > maxval)
{
throw bad_cronexpr("Specified range exceeds maximum");
}
if (first < minval || last < minval)
{
throw bad_cronexpr("Specified range is less than minimum");
}
if (first > last)
{
throw bad_cronexpr("Specified range start exceeds range end");
}
return { first, last };
}
template <size_t N>
static void set_cron_field(
CRONCPP_STRING_VIEW value,
std::bitset<N>& target,
cron_int const minval,
cron_int const maxval)
{
if(value.length() > 0 && value[value.length()-1] == ',')
throw bad_cronexpr("Value cannot end with comma");
auto fields = utils::split(value, ',');
if (fields.empty())
throw bad_cronexpr("Expression parsing error");
for (auto const & field : fields)
{
if (!utils::contains(field, '/'))
{
#ifdef CRONCPP_IS_CPP17
auto[first, last] = detail::make_range(field, minval, maxval);
#else
auto range = detail::make_range(field, minval, maxval);
auto first = range.first;
auto last = range.second;
#endif
for (cron_int i = first - minval; i <= last - minval; ++i)
{
target.set(i);
}
}
else
{
auto parts = utils::split(field, '/');
if (parts.size() != 2)
throw bad_cronexpr("Incrementer must have two fields");
#ifdef CRONCPP_IS_CPP17
auto[first, last] = detail::make_range(parts[0], minval, maxval);
#else
auto range = detail::make_range(parts[0], minval, maxval);
auto first = range.first;
auto last = range.second;
#endif
if (!utils::contains(parts[0], '-'))
{
last = maxval;
}
auto delta = detail::to_cron_int(parts[1]);
if(delta <= 0)
throw bad_cronexpr("Incrementer must be a positive value");
for (cron_int i = first - minval; i <= last - minval; i += delta)
{
target.set(i);
}
}
}
}
template <typename Traits>
static void set_cron_days_of_week(
std::string value,
std::bitset<7>& target)
{
auto days = utils::to_upper(value);
auto days_replaced = detail::replace_ordinals(
days,
#ifdef CRONCPP_IS_CPP17
Traits::DAYS
#else
Traits::DAYS()
#endif
);
if (days_replaced.size() == 1 && days_replaced[0] == '?')
days_replaced[0] = '*';
set_cron_field(
days_replaced,
target,
Traits::CRON_MIN_DAYS_OF_WEEK,
Traits::CRON_MAX_DAYS_OF_WEEK);
}
template <typename Traits>
static void set_cron_days_of_month(
std::string value,
std::bitset<31>& target)
{
if (value.size() == 1 && value[0] == '?')
value[0] = '*';
set_cron_field(
value,
target,
Traits::CRON_MIN_DAYS_OF_MONTH,
Traits::CRON_MAX_DAYS_OF_MONTH);
}
template <typename Traits>
static void set_cron_month(
std::string value,
std::bitset<12>& target)
{
auto month = utils::to_upper(value);
auto month_replaced = replace_ordinals(
month,
#ifdef CRONCPP_IS_CPP17
Traits::MONTHS
#else
Traits::MONTHS()
#endif
);
set_cron_field(
month_replaced,
target,
Traits::CRON_MIN_MONTHS,
Traits::CRON_MAX_MONTHS);
}
template <size_t N>
inline size_t next_set_bit(
std::bitset<N> const & target,
size_t /*minimum*/,
size_t /*maximum*/,
size_t offset)
{
for (auto i = offset; i < N; ++i)
{
if (target.test(i)) return i;
}
return INVALID_INDEX;
}
inline void add_to_field(
std::tm& date,
cron_field const field,
int const val)
{
switch (field)
{
case cron_field::second:
date.tm_sec += val;
break;
case cron_field::minute:
date.tm_min += val;
break;
case cron_field::hour_of_day:
date.tm_hour += val;
break;
case cron_field::day_of_week:
case cron_field::day_of_month:
date.tm_mday += val;
break;
case cron_field::month:
date.tm_mon += val;
break;
case cron_field::year:
date.tm_year += val;
break;
}
if (INVALID_TIME == utils::tm_to_time(date))
throw bad_cronexpr("Invalid time expression");
}
inline void set_field(
std::tm& date,
cron_field const field,
int const val)
{
switch (field)
{
case cron_field::second:
date.tm_sec = val;
break;
case cron_field::minute:
date.tm_min = val;
break;
case cron_field::hour_of_day:
date.tm_hour = val;
break;
case cron_field::day_of_week:
date.tm_wday = val;
break;
case cron_field::day_of_month:
date.tm_mday = val;
break;
case cron_field::month:
date.tm_mon = val;
break;
case cron_field::year:
date.tm_year = val;
break;
}
if (INVALID_TIME == utils::tm_to_time(date))
throw bad_cronexpr("Invalid time expression");
}
inline void reset_field(
std::tm& date,
cron_field const field)
{
switch (field)
{
case cron_field::second:
date.tm_sec = 0;
break;
case cron_field::minute:
date.tm_min = 0;
break;
case cron_field::hour_of_day:
date.tm_hour = 0;
break;
case cron_field::day_of_week:
date.tm_wday = 0;
break;
case cron_field::day_of_month:
date.tm_mday = 1;
break;
case cron_field::month:
date.tm_mon = 0;
break;
case cron_field::year:
date.tm_year = 0;
break;
}
if (INVALID_TIME == utils::tm_to_time(date))
throw bad_cronexpr("Invalid time expression");
}
inline void reset_all_fields(
std::tm& date,
std::bitset<7> const & marked_fields)
{
for (size_t i = 0; i < marked_fields.size(); ++i)
{
if (marked_fields.test(i))
reset_field(date, static_cast<cron_field>(i));
}
}
inline void mark_field(
std::bitset<7> & orders,
cron_field const field)
{
if (!orders.test(static_cast<size_t>(field)))
orders.set(static_cast<size_t>(field));
}
template <size_t N>
static size_t find_next(
std::bitset<N> const & target,
std::tm& date,
unsigned int const minimum,
unsigned int const maximum,
unsigned int const value,
cron_field const field,
cron_field const next_field,
std::bitset<7> const & marked_fields)
{
auto next_value = next_set_bit(target, minimum, maximum, value);
if (INVALID_INDEX == next_value)
{
add_to_field(date, next_field, 1);
reset_field(date, field);
next_value = next_set_bit(target, minimum, maximum, 0);
}
if (INVALID_INDEX == next_value || next_value != value)
{
set_field(date, field, static_cast<int>(next_value));
reset_all_fields(date, marked_fields);
}
return next_value;
}
template <typename Traits>
static size_t find_next_day(
std::tm& date,
std::bitset<31> const & days_of_month,
size_t day_of_month,
std::bitset<7> const & days_of_week,
size_t day_of_week,
std::bitset<7> const & marked_fields)
{
unsigned int count = 0;
unsigned int maximum = 366;
while (
(!days_of_month.test(day_of_month - Traits::CRON_MIN_DAYS_OF_MONTH) ||
!days_of_week.test(day_of_week - Traits::CRON_MIN_DAYS_OF_WEEK))
&& count++ < maximum)
{
add_to_field(date, cron_field::day_of_month, 1);
day_of_month = date.tm_mday;
day_of_week = date.tm_wday;
reset_all_fields(date, marked_fields);
}
return day_of_month;
}
template <typename Traits>
static bool find_next(cronexpr const & cex,
std::tm& date,
size_t const dot)
{
bool res = true;
std::bitset<7> marked_fields{ 0 };
std::bitset<7> empty_list{ 0 };
unsigned int second = date.tm_sec;
auto updated_second = find_next(
cex.seconds,
date,
Traits::CRON_MIN_SECONDS,
Traits::CRON_MAX_SECONDS,
second,
cron_field::second,
cron_field::minute,
empty_list);
if (second == updated_second)
{
mark_field(marked_fields, cron_field::second);
}
unsigned int minute = date.tm_min;
auto update_minute = find_next(
cex.minutes,
date,
Traits::CRON_MIN_MINUTES,
Traits::CRON_MAX_MINUTES,
minute,
cron_field::minute,
cron_field::hour_of_day,
marked_fields);
if (minute == update_minute)
{
mark_field(marked_fields, cron_field::minute);
}
else
{
res = find_next<Traits>(cex, date, dot);
if (!res) return res;
}
unsigned int hour = date.tm_hour;
auto updated_hour = find_next(
cex.hours,
date,
Traits::CRON_MIN_HOURS,
Traits::CRON_MAX_HOURS,
hour,
cron_field::hour_of_day,
cron_field::day_of_week,
marked_fields);
if (hour == updated_hour)
{
mark_field(marked_fields, cron_field::hour_of_day);
}
else
{
res = find_next<Traits>(cex, date, dot);
if (!res) return res;
}
unsigned int day_of_week = date.tm_wday;
unsigned int day_of_month = date.tm_mday;
auto updated_day_of_month = find_next_day<Traits>(
date,
cex.days_of_month,
day_of_month,
cex.days_of_week,
day_of_week,
marked_fields);
if (day_of_month == updated_day_of_month)
{
mark_field(marked_fields, cron_field::day_of_month);
}
else
{
res = find_next<Traits>(cex, date, dot);
if (!res) return res;
}
unsigned int month = date.tm_mon;
auto updated_month = find_next(
cex.months,
date,
Traits::CRON_MIN_MONTHS,
Traits::CRON_MAX_MONTHS,
month,
cron_field::month,
cron_field::year,
marked_fields);
if (month != updated_month)
{
if (date.tm_year - dot > Traits::CRON_MAX_YEARS_DIFF)
return false;
res = find_next<Traits>(cex, date, dot);
if (!res) return res;
}
return res;
}
}
template <typename Traits>
static cronexpr make_cron(CRONCPP_STRING_VIEW expr)
{
cronexpr cex;
if (expr.empty())
throw bad_cronexpr("Invalid empty cron expression");
auto fields = utils::split(expr, ' ');
fields.erase(
std::remove_if(std::begin(fields), std::end(fields),
[](CRONCPP_STRING_VIEW s) {return s.empty(); }),
std::end(fields));
if (fields.size() != 6)
throw bad_cronexpr("cron expression must have six fields");
detail::set_cron_field(fields[0], cex.seconds, Traits::CRON_MIN_SECONDS, Traits::CRON_MAX_SECONDS);
detail::set_cron_field(fields[1], cex.minutes, Traits::CRON_MIN_MINUTES, Traits::CRON_MAX_MINUTES);
detail::set_cron_field(fields[2], cex.hours, Traits::CRON_MIN_HOURS, Traits::CRON_MAX_HOURS);
detail::set_cron_days_of_week<Traits>(fields[5], cex.days_of_week);
detail::set_cron_days_of_month<Traits>(fields[3], cex.days_of_month);
detail::set_cron_month<Traits>(fields[4], cex.months);
cex.expr = expr;
return cex;
}
template <typename Traits = cron_standard_traits>
static std::tm cron_next(cronexpr const & cex, std::tm date)
{
time_t original = utils::tm_to_time(date);
if (INVALID_TIME == original) return {};
if (!detail::find_next<Traits>(cex, date, date.tm_year))
return {};
time_t calculated = utils::tm_to_time(date);
if (INVALID_TIME == calculated) return {};
if (calculated == original)
{
add_to_field(date, detail::cron_field::second, 1);
if (!detail::find_next<Traits>(cex, date, date.tm_year))
return {};
}
return date;
}
template <typename Traits = cron_standard_traits>
static std::time_t cron_next(cronexpr const & cex, std::time_t const & date)
{
std::tm val;
std::tm* dt = utils::time_to_tm(&date, &val);
if (dt == nullptr) return INVALID_TIME;
time_t original = utils::tm_to_time(*dt);
if (INVALID_TIME == original) return INVALID_TIME;
if(!detail::find_next<Traits>(cex, *dt, dt->tm_year))
return INVALID_TIME;
time_t calculated = utils::tm_to_time(*dt);
if (INVALID_TIME == calculated) return calculated;
if (calculated == original)
{
add_to_field(*dt, detail::cron_field::second, 1);
if(!detail::find_next<Traits>(cex, *dt, dt->tm_year))
return INVALID_TIME;
}
return utils::tm_to_time(*dt);
}
template <typename Traits = cron_standard_traits>
static std::chrono::system_clock::time_point cron_next(cronexpr const & cex, std::chrono::system_clock::time_point const & time_point) {
return std::chrono::system_clock::from_time_t(cron_next<Traits>(cex, std::chrono::system_clock::to_time_t(time_point)));
}
}

View File

@@ -96,42 +96,40 @@ namespace OpenWifi {
void EntityDB::AddVenues(Poco::JSON::Object &Tree, const std::string & Node) { void EntityDB::AddVenues(Poco::JSON::Object &Tree, const std::string & Node) {
ProvObjects::Venue E; ProvObjects::Venue E;
// std::cout << "Adding venue:" << Node << std::endl; // std::cout << "Adding venue:" << Node << std::endl;
if(StorageService()->VenueDB().GetRecord("id",Node,E)) { StorageService()->VenueDB().GetRecord("id",Node,E);
Poco::JSON::Array Venues; Poco::JSON::Array Venues;
for (const auto &i: E.children) { for(const auto &i:E.children) {
Poco::JSON::Object Venue; Poco::JSON::Object Venue;
AddVenues(Venue, i); AddVenues(Venue, i);
Venues.add(Venue); Venues.add(Venue);
}
Tree.set("type", "venue");
Tree.set("name", E.info.name);
Tree.set("uuid", E.info.id);
Tree.set("children", Venues);
} }
Tree.set("type","venue");
Tree.set("name",E.info.name);
Tree.set("uuid",E.info.id);
Tree.set("children",Venues);
} }
void EntityDB::BuildTree(Poco::JSON::Object &Tree, const std::string & Node) { void EntityDB::BuildTree(Poco::JSON::Object &Tree, const std::string & Node) {
ProvObjects::Entity E; ProvObjects::Entity E;
// std::cout << "Adding node:" << Node << std::endl; // std::cout << "Adding node:" << Node << std::endl;
if(StorageService()->EntityDB().GetRecord("id",Node,E)) { StorageService()->EntityDB().GetRecord("id",Node,E);
Poco::JSON::Array Children; Poco::JSON::Array Children;
for (const auto &i: E.children) { for(const auto &i:E.children) {
Poco::JSON::Object Child; Poco::JSON::Object Child;
BuildTree(Child, i); BuildTree(Child,i);
Children.add(Child); Children.add(Child);
}
Poco::JSON::Array Venues;
for (const auto &i: E.venues) {
Poco::JSON::Object Venue;
AddVenues(Venue, i);
Venues.add(Venue);
}
Tree.set("type", "entity");
Tree.set("name", E.info.name);
Tree.set("uuid", E.info.id);
Tree.set("children", Children);
Tree.set("venues", Venues);
} }
Poco::JSON::Array Venues;
for(const auto &i:E.venues) {
Poco::JSON::Object Venue;
AddVenues(Venue, i);
Venues.add(Venue);
}
Tree.set("type","entity");
Tree.set("name",E.info.name);
Tree.set("uuid",E.info.id);
Tree.set("children",Children);
Tree.set("venues", Venues);
} }
void EntityDB::ImportVenues(const Poco::JSON::Object::Ptr &O, const std::string &Parent) { void EntityDB::ImportVenues(const Poco::JSON::Object::Ptr &O, const std::string &Parent) {

View File

@@ -83,13 +83,12 @@ namespace OpenWifi {
InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {} DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {}
bool InventoryDB::CreateFromConnection( const std::string &SerialNumberRaw, bool InventoryDB::CreateFromConnection( const std::string &SerialNumber,
const std::string &ConnectionInfo, const std::string &ConnectionInfo,
const std::string &DeviceType, const std::string &DeviceType,
const std::string &Locale) { const std::string &Locale) {
ProvObjects::InventoryTag ExistingDevice; ProvObjects::InventoryTag ExistingDevice;
auto SerialNumber = Poco::toLower(SerialNumberRaw);
if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) { if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) {
ProvObjects::InventoryTag NewDevice; ProvObjects::InventoryTag NewDevice;
uint64_t Now = OpenWifi::Now(); uint64_t Now = OpenWifi::Now();
@@ -224,7 +223,7 @@ namespace OpenWifi {
ProvObjects::DeviceRules Rules; ProvObjects::DeviceRules Rules;
std::string SerialNumber = Utils::IntToSerialNumber(i); std::string SerialNumber = Utils::IntToSerialNumber(i);
if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) { if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) {
if(Rules.rrm!="no" && Rules.rrm!="inherit") if(Rules.rrm=="yes")
DeviceList.push_back(SerialNumber); DeviceList.push_back(SerialNumber);
} }
} }

View File

@@ -0,0 +1,51 @@
//
// Created by stephane bourque on 2021-10-28.
//
#include "storage_jobs.h"
#include "framework/OpenWifiTypes.h"
#include "framework/MicroService.h"
namespace OpenWifi {
static ORM::FieldVec JobDB_Fields{
// object info
ORM::Field{"id",64, true},
ORM::Field{"name",ORM::FieldType::FT_TEXT},
ORM::Field{"description",ORM::FieldType::FT_TEXT},
ORM::Field{"type",ORM::FieldType::FT_TEXT},
ORM::Field{"progress",ORM::FieldType::FT_BIGINT},
ORM::Field{"total",ORM::FieldType::FT_BIGINT},
ORM::Field{"parameters",ORM::FieldType::FT_TEXT}
};
static ORM::IndexVec JobDB_Indexes{
{ std::string("job_name_index"),
ORM::IndexEntryVec{
{std::string("name"),
ORM::Indextype::ASC} } }
};
JobDB::JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
DB(T, "jobs", JobDB_Fields, JobDB_Indexes, P, L, "job") {}
}
template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobDBRecordType &In, OpenWifi::JobRecord &Out) {
Out.id = In.get<0>();
Out.name = In.get<1>();
Out.description = In.get<2>();
Out.type = In.get<3>();
Out.progress = In.get<4>();
Out.total = In.get<5>();
Out.parameters = OpenWifi::RESTAPI_utils::to_array_of_array_of_object<OpenWifi::Job::Parameter>(In.get<3>());
}
template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobRecord &In, OpenWifi::JobDBRecordType &Out) {
Out.set<0>(In.id);
Out.set<1>(In.name);
Out.set<2>(In.description);
Out.set<3>(In.type);
Out.set<4>(In.progress);
Out.set<5>(In.total);
Out.set<6>(OpenWifi::RESTAPI_utils::to_string(In.parameters));
}

View File

@@ -0,0 +1,40 @@
//
// Created by stephane bourque on 2021-10-28.
//
#pragma once
#include "framework/orm.h"
#include "JobController.h"
namespace OpenWifi {
typedef Poco::Tuple<
std::string,
std::string,
std::string,
std::string,
uint64_t,
uint64_t,
std::string
> JobDBRecordType;
struct JobRecord {
Types::UUID_t id;
std::string name;
std::string description;
std::string type;
uint64_t progress;
uint64_t total;
Job::ParametersVec parameters;
// void from_string(const std::string &S);
// std::string to_string() const;
};
class JobDB : public ORM::DB<JobDBRecordType, JobRecord> {
public:
JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L);
virtual ~JobDB() {};
private:
};
}

View File

@@ -97,7 +97,7 @@ if [ -z ${OWPROV_OVERRIDE+x} ]; then
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')" port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
path="$(echo $url | grep / | cut -d/ -f2-)" path="$(echo $url | grep / | cut -d/ -f2-)"
export OWPROV=${url} export OWPROV=${url}
echo "Using PROV=${OWPROV}..." echo "Using ${OWPROV}..."
else else
echo "OWPROV endpoint is not found:" echo "OWPROV endpoint is not found:"
jq < ${result_file} jq < ${result_file}
@@ -108,33 +108,6 @@ else
fi fi
} }
setrrm() {
if [ -z ${OWRRM_OVERRIDE+x} ]; then
curl ${FLAGS} -X GET "https://${OWSEC}/api/v1/systemEndpoints" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${token}" > ${result_file}
rawurl="$(cat ${result_file} | jq -r '.endpoints[] | select( .type == "owrrm" ) | .uri')"
if [[ ! -z "${rawurl}" ]]; then
proto="$(echo $rawurl | grep :// | sed -e's,^\(.*://\).*,\1,g')"
url="$(echo ${rawurl/$proto/})"
user="$(echo $url | grep @ | cut -d@ -f1)"
hostport="$(echo ${url/$user@/} | cut -d/ -f1)"
host="$(echo $hostport | sed -e 's,:.*,,g')"
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
path="$(echo $url | grep / | cut -d/ -f2-)"
export OWRRM=${url}
echo "Using RRM=${OWRRM}..."
else
echo "OWRRM endpoint is not found:"
jq < ${result_file}
exit 1
fi
else
export OWRRM=${OWRRM_OVERRIDE}
fi
}
logout() { logout() {
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \ curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
@@ -534,24 +507,6 @@ getvenuedevices() {
jq < ${result_file} jq < ${result_file}
} }
listrrmalgos() {
setrrm
curl ${FLAGS} -X GET "http://${OWRRM}/api/v1/algorithms" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${token}" \
-H "Accept: application/json" > ${result_file}
jq < ${result_file}
}
rrmprovider() {
setrrm
curl ${FLAGS} -X GET "http://${OWRRM}/api/v1/provider" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${token}" \
-H "Accept: application/json" > ${result_file}
jq < ${result_file}
}
shopt -s nocasematch shopt -s nocasematch
case "$1" in case "$1" in
"login") login; echo "You are logged in..." ; logout ;; "login") login; echo "You are logged in..." ; logout ;;
@@ -600,8 +555,6 @@ case "$1" in
"getsubdevs") login; getsubdevs $2; logout;; "getsubdevs") login; getsubdevs $2; logout;;
"listvenues") login; listvenues $2; logout;; "listvenues") login; listvenues $2; logout;;
"getvenuedevices") login; getvenuedevices $2; logout;; "getvenuedevices") login; getvenuedevices $2; logout;;
"listrrmalgos") login; listrrmalgos; logout;;
"rrmprovider") login; rrmprovider; logout;;
*) help ;; *) help ;;
esac esac