mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov.git
synced 2025-11-02 11:37:54 +00:00
Compare commits
77 Commits
v2.6.0-RC2
...
v2.7.0-RC1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a33815096 | ||
|
|
f515bb8e30 | ||
|
|
02fd6d726a | ||
|
|
27ffb31a7c | ||
|
|
5fd9831d6b | ||
|
|
fed085cc4a | ||
|
|
121fee841e | ||
|
|
4c6f03ba14 | ||
|
|
0fb9478675 | ||
|
|
97c2af83fd | ||
|
|
599ba0793c | ||
|
|
6df780dba3 | ||
|
|
a00287ae85 | ||
|
|
c7a300b81e | ||
|
|
5dc507a82e | ||
|
|
8b3e1326b7 | ||
|
|
667f8bc4bd | ||
|
|
0168301d6b | ||
|
|
1a0b00e989 | ||
|
|
7c2229f3d6 | ||
|
|
541df429ec | ||
|
|
6f9fe6cd5d | ||
|
|
2594a2c5f2 | ||
|
|
2e02d96523 | ||
|
|
a1375f9468 | ||
|
|
777bc0f2aa | ||
|
|
bd0e99309c | ||
|
|
6cb6a60142 | ||
|
|
fc7947394d | ||
|
|
1341e15874 | ||
|
|
f065815df3 | ||
|
|
03ba51e869 | ||
|
|
efd7ef2a9b | ||
|
|
4b90a6e893 | ||
|
|
f5cb4a5a87 | ||
|
|
e3e4aac202 | ||
|
|
5945d02b3d | ||
|
|
0ac192cdc0 | ||
|
|
1b5eb87eef | ||
|
|
46db18d7cd | ||
|
|
30b8665d7d | ||
|
|
c8b3a3b060 | ||
|
|
096da35ff4 | ||
|
|
bd7f3af11c | ||
|
|
2a06021c4a | ||
|
|
bf18bb25ba | ||
|
|
e93f899b76 | ||
|
|
eda73038f6 | ||
|
|
953ca155a4 | ||
|
|
898806f232 | ||
|
|
7d97b19b85 | ||
|
|
d6c587fde6 | ||
|
|
58c9a7805b | ||
|
|
94dd4c84e9 | ||
|
|
2636715f6f | ||
|
|
f9f4624add | ||
|
|
cf441de197 | ||
|
|
158455a528 | ||
|
|
4d2ccec1a8 | ||
|
|
7dad5a9bdb | ||
|
|
cd2ac84c5b | ||
|
|
9735f709e9 | ||
|
|
ae5fd31818 | ||
|
|
2b46ad4a66 | ||
|
|
43d7078cb7 | ||
|
|
18f5d42f00 | ||
|
|
70622b2bb8 | ||
|
|
5b24aea47c | ||
|
|
e97617a0db | ||
|
|
ba63a7033f | ||
|
|
e9db2e1a0d | ||
|
|
d85fef7725 | ||
|
|
543c46bf68 | ||
|
|
73eec53fe4 | ||
|
|
8ad2d67c2c | ||
|
|
442f810688 | ||
|
|
2dca5204ea |
9
.github/workflows/cleanup.yml
vendored
9
.github/workflows/cleanup.yml
vendored
@@ -4,6 +4,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
- 'release/*'
|
||||||
types: [ closed ]
|
types: [ closed ]
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
@@ -16,4 +17,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- run: |
|
- run: |
|
||||||
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
|
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
|
||||||
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owprov/$PR_BRANCH_TAG"
|
|
||||||
|
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
|
||||||
|
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
|
||||||
|
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owprov/$PR_BRANCH_TAG"
|
||||||
|
else
|
||||||
|
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(owprov VERSION 2.6.0)
|
project(owprov VERSION 2.7.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
@@ -125,7 +125,6 @@ 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
|
||||||
@@ -135,7 +134,14 @@ 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/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/FileDownloader.cpp src/FileDownloader.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}
|
||||||
|
|||||||
54
Dockerfile
54
Dockerfile
@@ -1,4 +1,10 @@
|
|||||||
FROM alpine:3.15 AS build-base
|
ARG ALPINE_VERSION=3.16.2
|
||||||
|
ARG POCO_VERSION=poco-tip-v1
|
||||||
|
ARG FMTLIB_VERSION=9.0.0
|
||||||
|
ARG CPPKAFKA_VERSION=tip-v1
|
||||||
|
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||||
|
|
||||||
|
FROM alpine:$ALPINE_VERSION AS build-base
|
||||||
|
|
||||||
RUN apk add --update --no-cache \
|
RUN apk add --update --no-cache \
|
||||||
make cmake g++ git \
|
make cmake g++ git \
|
||||||
@@ -9,8 +15,10 @@ RUN apk add --update --no-cache \
|
|||||||
|
|
||||||
FROM build-base AS poco-build
|
FROM build-base AS poco-build
|
||||||
|
|
||||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
ARG POCO_VERSION
|
||||||
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
|
||||||
@@ -19,10 +27,26 @@ 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
|
||||||
|
|
||||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
ARG CPPKAFKA_VERSION
|
||||||
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
|
||||||
@@ -33,8 +57,10 @@ RUN cmake --build . --target install
|
|||||||
|
|
||||||
FROM build-base AS json-schema-validator-build
|
FROM build-base AS json-schema-validator-build
|
||||||
|
|
||||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
ARG JSON_VALIDATOR_VERSION
|
||||||
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
|
||||||
@@ -43,18 +69,6 @@ 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/
|
||||||
@@ -77,7 +91,7 @@ WORKDIR /owprov/cmake-build
|
|||||||
RUN cmake ..
|
RUN cmake ..
|
||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
|
|
||||||
FROM alpine:3.15
|
FROM alpine:$ALPINE_VERSION
|
||||||
|
|
||||||
ENV OWPROV_USER=owprov \
|
ENV OWPROV_USER=owprov \
|
||||||
OWPROV_ROOT=/owprov-data \
|
OWPROV_ROOT=/owprov-data \
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
|||||||
update-ca-certificates
|
update-ca-certificates
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWPROV_CONFIG"/owprov.properties ]]; then
|
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; 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
2
helm/.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
*.swp
|
*.swp
|
||||||
|
Chart.lock
|
||||||
|
charts/
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{{- $root := . -}}
|
{{- $root := . -}}
|
||||||
|
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -46,6 +47,39 @@ 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
|
||||||
|
|||||||
@@ -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: main
|
tag: v2.7.0-RC1
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
# regcred:
|
# regcred:
|
||||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||||
|
|||||||
@@ -27,71 +27,13 @@ components:
|
|||||||
|
|
||||||
responses:
|
responses:
|
||||||
NotFound:
|
NotFound:
|
||||||
description: The specified resource was not found.
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
properties:
|
|
||||||
ErrorCode:
|
|
||||||
type: integer
|
|
||||||
ErrorDetails:
|
|
||||||
type: string
|
|
||||||
ErrorDescription:
|
|
||||||
type: string
|
|
||||||
|
|
||||||
Unauthorized:
|
Unauthorized:
|
||||||
description: The requested does not have sufficient rights to perform the operation.
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||||
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:
|
||||||
description: The requested operation was performed.
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
properties:
|
|
||||||
Operation:
|
|
||||||
type: string
|
|
||||||
Details:
|
|
||||||
type: string
|
|
||||||
Code:
|
|
||||||
type: integer
|
|
||||||
|
|
||||||
BadRequest:
|
BadRequest:
|
||||||
description: The requested operation failed.
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
properties:
|
|
||||||
ErrorCode:
|
|
||||||
type: integer
|
|
||||||
ErrorDetails:
|
|
||||||
type: string
|
|
||||||
ErrorDescription:
|
|
||||||
type: integer
|
|
||||||
|
|
||||||
schemas:
|
schemas:
|
||||||
|
|
||||||
@@ -2016,11 +1958,6 @@ 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
|
||||||
@@ -2092,6 +2029,21 @@ 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
|
||||||
@@ -2313,12 +2265,6 @@ 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
|
||||||
|
|||||||
174
openapi/rrm_provider.yaml
Normal file
174
openapi/rrm_provider.yaml
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
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'
|
||||||
|
|
||||||
@@ -153,60 +153,62 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> Sections;
|
try {
|
||||||
for(const auto &i:Config_) {
|
std::set<std::string> Sections;
|
||||||
Poco::JSON::Parser P;
|
for (const auto &i: Config_) {
|
||||||
auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>();
|
Poco::JSON::Parser P;
|
||||||
auto Names = O->getNames();
|
auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>();
|
||||||
for(const auto &SectionName:Names) {
|
auto Names = O->getNames();
|
||||||
auto InsertInfo = Sections.insert(SectionName);
|
for (const auto &SectionName: Names) {
|
||||||
if (InsertInfo.second) {
|
auto InsertInfo = Sections.insert(SectionName);
|
||||||
if (O->isArray(SectionName)) {
|
if (InsertInfo.second) {
|
||||||
auto OriginalArray = O->getArray(SectionName);
|
if (O->isArray(SectionName)) {
|
||||||
if (Explain_) {
|
auto OriginalArray = O->getArray(SectionName);
|
||||||
Poco::JSON::Object ExObj;
|
if (Explain_) {
|
||||||
ExObj.set("from-uuid", i.info.id);
|
Poco::JSON::Object ExObj;
|
||||||
ExObj.set("from-name", i.info.name);
|
ExObj.set("from-uuid", i.info.id);
|
||||||
ExObj.set("action", "added");
|
ExObj.set("from-name", i.info.name);
|
||||||
ExObj.set("element", OriginalArray);
|
ExObj.set("action", "added");
|
||||||
Explanation_.add(ExObj);
|
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;
|
||||||
}
|
}
|
||||||
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 {
|
} else {
|
||||||
std::cout << " --- unknown element type --- " << O->get(SectionName).toString() << std::endl;
|
if (Explain_) {
|
||||||
}
|
Poco::JSON::Object ExObj;
|
||||||
} else {
|
ExObj.set("from-uuid", i.info.id);
|
||||||
if (Explain_) {
|
ExObj.set("from-name", i.info.name);
|
||||||
Poco::JSON::Object ExObj;
|
ExObj.set("action", "ignored");
|
||||||
ExObj.set("from-uuid", i.info.id);
|
ExObj.set("reason", "weight insufficient");
|
||||||
ExObj.set("from-name", i.info.name);
|
ExObj.set("element", O->get(SectionName));
|
||||||
ExObj.set("action", "ignored");
|
Explanation_.add(ExObj);
|
||||||
ExObj.set("reason", "weight insufficient");
|
}
|
||||||
ExObj.set("element", O->get(SectionName));
|
|
||||||
Explanation_.add(ExObj);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} catch (...) {
|
||||||
if(Config_.empty())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
}
|
||||||
|
return !Config_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) {
|
static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ 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) {
|
||||||
|
|||||||
@@ -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_);
|
||||||
Logger().information(Poco::format("Device(%s): Connection/Ping message.", Key));
|
poco_debug(Logger(),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;
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ 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;
|
||||||
|
|||||||
@@ -27,11 +27,32 @@ 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 ¤t_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,99 +7,45 @@
|
|||||||
#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 {
|
class Job : public Poco::Runnable {
|
||||||
public:
|
public:
|
||||||
struct Parameter {
|
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) :
|
||||||
std::string name;
|
jobId_(JobID),
|
||||||
std::string value;
|
name_(name),
|
||||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
parameters_(parameters),
|
||||||
RESTAPI_utils::field_to_json(Obj,"name",name);
|
when_(when),
|
||||||
RESTAPI_utils::field_to_json(Obj,"value",value);
|
userinfo_(UI),
|
||||||
}
|
Logger_(L)
|
||||||
|
{};
|
||||||
|
|
||||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
virtual void run() = 0;
|
||||||
try {
|
[[nodiscard]] std::string Name() const { return name_; }
|
||||||
RESTAPI_utils::field_from_json(Obj,"name",name);
|
const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; }
|
||||||
RESTAPI_utils::field_from_json(Obj,"value",value);
|
Poco::Logger & Logger() { return Logger_; }
|
||||||
return true;
|
const std::string & JobId() const { return jobId_; }
|
||||||
} catch (...) {
|
const std::string & Parameter(int x) const { return parameters_[x];}
|
||||||
|
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:
|
||||||
return false;
|
std::string jobId_;
|
||||||
}
|
std::string name_;
|
||||||
};
|
std::vector<std::string> parameters_;
|
||||||
|
uint64_t when_=0;
|
||||||
struct Status {
|
SecurityObjects::UserInfo userinfo_;
|
||||||
Types::UUID_t UUID;
|
Poco::Logger & Logger_;
|
||||||
uint64_t Start = 0 ;
|
uint64_t started_=0;
|
||||||
uint64_t Progress = 0 ;
|
uint64_t completed_=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() {
|
||||||
@@ -112,11 +58,16 @@ namespace OpenWifi {
|
|||||||
void run() override;
|
void run() override;
|
||||||
inline void wakeup() { Thr_.wakeUp(); }
|
inline void wakeup() { Thr_.wakeUp(); }
|
||||||
|
|
||||||
bool JobList(Job::Statuses & Statuses);
|
void AddJob( Job* newJob ) {
|
||||||
|
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")
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ 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;
|
||||||
@@ -83,6 +84,7 @@ 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]=='*') {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#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 {
|
||||||
|
|
||||||
@@ -405,7 +408,9 @@ 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", "unit" };
|
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services",
|
||||||
|
"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;
|
||||||
@@ -521,12 +526,39 @@ 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 (DR.rrm=="yes" || DR.rrm=="no" || DR.rrm=="inherit") &&
|
return (ValidRRM(DR.rrm)) &&
|
||||||
(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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,36 +35,53 @@ 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(Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id ));
|
Logger().debug(
|
||||||
|
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(HasParameter("firmwareOptions", Arg) && Arg=="true") {
|
} else if (GetBoolParameter("firmwareOptions", false)) {
|
||||||
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(HasParameter("applyConfiguration",Arg) && Arg=="true") {
|
} else if(GetBoolParameter("rrmSettings",false)) {
|
||||||
|
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>();
|
||||||
@@ -91,6 +108,19 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -136,6 +166,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace OpenWifi{
|
|||||||
for (const auto &i: V.children) {
|
for (const auto &i: V.children) {
|
||||||
ProvObjects::Venue V2;
|
ProvObjects::Venue V2;
|
||||||
if (StorageService()->VenueDB().GetRecord("id", i, V2)) {
|
if (StorageService()->VenueDB().GetRecord("id", i, V2)) {
|
||||||
|
std::copy(V2.devices.begin(),V2.devices.end(),std::back_inserter(R));
|
||||||
auto LowerDevs = GetDevices(V2, GetChildren);
|
auto LowerDevs = GetDevices(V2, GetChildren);
|
||||||
std::copy(LowerDevs.begin(), LowerDevs.end(), std::back_inserter(R));
|
std::copy(LowerDevs.begin(), LowerDevs.end(), std::back_inserter(R));
|
||||||
}
|
}
|
||||||
@@ -227,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();
|
||||||
auto Task = new VenueConfigUpdater(UUID,UserInfo_.userinfo,0,Logger());
|
Types::StringVec Parameters{UUID};;
|
||||||
auto JobId = Task->Start();
|
auto NewJob = new VenueConfigUpdater(JobId,"VenueConfigurationUpdater", Parameters, 0, UserInfo_.userinfo, Logger());
|
||||||
|
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);
|
||||||
@@ -241,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();
|
||||||
auto Task = new VenueUpgrade(UUID,UserInfo_.userinfo,0,Logger());
|
Types::StringVec Parameters{UUID};;
|
||||||
auto JobId = Task->Start();
|
auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger());
|
||||||
|
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);
|
||||||
@@ -255,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();
|
||||||
auto Task = new VenueRebooter(UUID,UserInfo_.userinfo,0,Logger());
|
Types::StringVec Parameters{UUID};;
|
||||||
auto JobId = Task->Start();
|
auto NewJob = new VenueRebooter(JobId,"VenueRebooter", Parameters, 0, UserInfo_.userinfo, Logger());
|
||||||
|
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);
|
||||||
|
|||||||
@@ -1159,5 +1159,40 @@ 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,21 @@ 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"};
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ 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);
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ 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() {
|
||||||
@@ -194,18 +195,24 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NewDevices!=V.devices) {
|
ProvObjects::Venue NewVenue = V;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
@@ -213,31 +220,175 @@ namespace OpenWifi {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto FixEntityDevices = [&](const ProvObjects::Entity &E) -> bool {
|
auto FixEntity = [&](const ProvObjects::Entity &E) -> bool {
|
||||||
Types::UUIDvec_t NewDevices;
|
Types::UUIDvec_t NewDevices;
|
||||||
|
bool Modified=false;
|
||||||
for(const auto &device:E.devices) {
|
for(const auto &device:E.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NewDevices!=E.devices) {
|
Types::UUIDvec_t NewContacts;
|
||||||
|
for(const auto &contact:E.contacts) {
|
||||||
|
ProvObjects::Contact C;
|
||||||
|
if(ContactDB().GetRecord("id", contact, C)) {
|
||||||
|
NewContacts.emplace_back(contact);
|
||||||
|
} else {
|
||||||
|
Modified=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UUIDvec_t NewLocations;
|
||||||
|
for(const auto &location:E.locations) {
|
||||||
|
ProvObjects::Location L;
|
||||||
|
if(LocationDB().GetRecord("id", location, L)) {
|
||||||
|
NewLocations.emplace_back(location);
|
||||||
|
} else {
|
||||||
|
Modified=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UUIDvec_t NewVenues;
|
||||||
|
for(const auto &venue:E.venues) {
|
||||||
|
ProvObjects::Venue V;
|
||||||
|
if(VenueDB().GetRecord("id", venue, V)) {
|
||||||
|
NewVenues.emplace_back(venue);
|
||||||
|
} else {
|
||||||
|
Modified=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UUIDvec_t NewVariables;
|
||||||
|
for(const auto &variable:E.variables) {
|
||||||
|
ProvObjects::VariableBlock V;
|
||||||
|
if(VariablesDB().GetRecord("id", variable, V)) {
|
||||||
|
NewVariables.emplace_back(variable);
|
||||||
|
} else {
|
||||||
|
Modified=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ProvObjects::Entity NewEntity = E;
|
||||||
|
|
||||||
|
if(E.deviceRules.rrm=="yes") {
|
||||||
|
NewEntity.deviceRules.rrm="inherit";
|
||||||
|
Modified=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.locations = NewLocations;
|
||||||
|
NewEntity.venues = NewVenues;
|
||||||
|
NewEntity.variables = NewVariables;
|
||||||
EntityDB().UpdateRecord("id", E.info.id, NewEntity);
|
EntityDB().UpdateRecord("id", E.info.id, NewEntity);
|
||||||
}
|
}
|
||||||
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(FixEntityDevices);
|
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() {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TagServer::run() {
|
void TagServer::run() {
|
||||||
|
Utils::SetThreadName("tag-server");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#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 {
|
||||||
|
|
||||||
@@ -19,8 +20,6 @@ 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 (...) {
|
||||||
}
|
}
|
||||||
@@ -37,35 +36,42 @@ 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>();
|
||||||
if (DeviceConfig->Get(Configuration)) {
|
try {
|
||||||
std::ostringstream OS;
|
if (DeviceConfig->Get(Configuration)) {
|
||||||
Configuration->stringify(OS);
|
std::ostringstream OS;
|
||||||
auto Response=Poco::makeShared<Poco::JSON::Object>();
|
Configuration->stringify(OS);
|
||||||
Logger().debug(fmt::format("{}: Pushing configuration.",Device.serialNumber));
|
auto Response = Poco::makeShared<Poco::JSON::Object>();
|
||||||
if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) {
|
Logger().debug(fmt::format("{}: Pushing configuration.", Device.serialNumber));
|
||||||
Logger().debug(fmt::format("{}: Configuration pushed.",Device.serialNumber));
|
if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) {
|
||||||
Logger().information(fmt::format("{}: Updated.", Device.serialNumber));
|
Logger().debug(fmt::format("{}: Configuration pushed.", Device.serialNumber));
|
||||||
// std::cout << Device.serialNumber << ": Updated" << std::endl;
|
Logger().information(fmt::format("{}: Updated.", Device.serialNumber));
|
||||||
updated_++;
|
// std::cout << Device.serialNumber << ": Updated" << std::endl;
|
||||||
|
updated_++;
|
||||||
|
} else {
|
||||||
|
Logger().information(fmt::format("{}: Not updated.", Device.serialNumber));
|
||||||
|
// std::cout << Device.serialNumber << ": Failed" << std::endl;
|
||||||
|
failed_++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger().information(fmt::format("{}: Not updated.", Device.serialNumber));
|
Logger().debug(fmt::format("{}: Configuration is bad.", Device.serialNumber));
|
||||||
// std::cout << Device.serialNumber << ": Failed" << std::endl;
|
bad_config_++;
|
||||||
failed_++;
|
// std::cout << Device.serialNumber << ": Bad config" << std::endl;
|
||||||
}
|
}
|
||||||
} else {
|
} catch (...) {
|
||||||
Logger().debug(fmt::format("{}: Configuration is bad.",Device.serialNumber));
|
Logger().debug(fmt::format("{}: Configuration is bad (caused an exception).", 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;
|
||||||
@@ -80,133 +86,101 @@ namespace OpenWifi {
|
|||||||
inline Poco::Logger & Logger() { return Logger_; }
|
inline Poco::Logger & Logger() { return Logger_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VenueConfigUpdater: public Poco::Runnable {
|
class VenueConfigUpdater: public Job {
|
||||||
public:
|
public:
|
||||||
explicit VenueConfigUpdater(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
|
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) :
|
||||||
VenueUUID_(VenueUUID),
|
Job(JobID, name, parameters, when, UI, L) {
|
||||||
UI_(UI),
|
|
||||||
When_(When),
|
|
||||||
Logger_(L)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string Start() {
|
inline virtual void run() {
|
||||||
JobId_ = MicroService::CreateUUID();
|
std::string VenueUUID_;
|
||||||
Worker_.start(*this);
|
|
||||||
return JobId_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
Utils::SetThreadName("venue-update");
|
||||||
std::string VenueUUID_;
|
VenueUUID_ = Parameter(0);
|
||||||
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());
|
||||||
// std::cout << "Scheduling config push for " << uuid << std::endl;
|
bool TaskAdded=false;
|
||||||
bool found_slot = false;
|
while(!TaskAdded) {
|
||||||
while (!found_slot) {
|
if (Pool_.available()) {
|
||||||
for (auto &cur_task: Tasks) {
|
JobList.push_back(NewTask);
|
||||||
if (cur_task.task == nullptr) {
|
Pool_.start(*NewTask);
|
||||||
cur_task.task = NewTask;
|
TaskAdded = true;
|
||||||
cur_task.thr_.start(*NewTask);
|
continue;
|
||||||
found_slot = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Let's look for a slot...
|
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||||
if (!found_slot) {
|
VenueDeviceConfigUpdater * current_job = *job_it;
|
||||||
for (auto &cur_task: Tasks) {
|
if(current_job!= nullptr && current_job->done_) {
|
||||||
if (cur_task.task != nullptr && cur_task.task->started_) {
|
Updated += current_job->updated_;
|
||||||
if (cur_task.thr_.isRunning())
|
Failed += current_job->failed_;
|
||||||
continue;
|
BadConfigs += current_job->bad_config_;
|
||||||
if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
if(current_job->updated_) {
|
||||||
cur_task.thr_.join();
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
Updated += cur_task.task->updated_;
|
} else if(current_job->failed_) {
|
||||||
Failed += cur_task.task->failed_;
|
N.content.warning.push_back(current_job->SerialNumber);
|
||||||
BadConfigs += cur_task.task->bad_config_;
|
} else {
|
||||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
N.content.error.push_back(current_job->SerialNumber);
|
||||||
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.");
|
||||||
bool stillTasksRunning=true;
|
Pool_.joinAll();
|
||||||
while(stillTasksRunning) {
|
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||||
stillTasksRunning = false;
|
VenueDeviceConfigUpdater * current_job = *job_it;
|
||||||
for(auto &cur_task:Tasks) {
|
if(current_job!= nullptr && current_job->done_) {
|
||||||
if(cur_task.task!= nullptr && cur_task.task->started_) {
|
Updated += current_job->updated_;
|
||||||
if(cur_task.thr_.isRunning()) {
|
Failed += current_job->failed_;
|
||||||
stillTasksRunning = true;
|
BadConfigs += current_job->bad_config_;
|
||||||
continue;
|
if(current_job->updated_) {
|
||||||
}
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
} else if(current_job->failed_) {
|
||||||
cur_task.thr_.join();
|
N.content.warning.push_back(current_job->SerialNumber);
|
||||||
if(cur_task.task->updated_) {
|
} else {
|
||||||
Updated++;
|
N.content.error.push_back(current_job->SerialNumber);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketClientNotificationVenueUpdateJobCompletionToUser(UI_.email, N);
|
// std::cout << N.content.details << std::endl;
|
||||||
|
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));
|
||||||
delete this;
|
Utils::SetThreadName("free");
|
||||||
|
Complete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#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 {
|
||||||
|
|
||||||
@@ -48,129 +49,90 @@ namespace OpenWifi {
|
|||||||
inline Poco::Logger & Logger() { return Logger_; }
|
inline Poco::Logger & Logger() { return Logger_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VenueRebooter: public Poco::Runnable {
|
class VenueRebooter: public Job {
|
||||||
public:
|
public:
|
||||||
explicit VenueRebooter(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
|
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) :
|
||||||
VenueUUID_(VenueUUID),
|
Job(JobID, name, parameters, when, UI, L) {
|
||||||
UI_(UI),
|
|
||||||
When_(When),
|
|
||||||
Logger_(L)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string Start() {
|
inline virtual void run() final {
|
||||||
JobId_ = MicroService::CreateUUID();
|
|
||||||
Worker_.start(*this);
|
|
||||||
return JobId_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
Utils::SetThreadName("venue-reboot");
|
||||||
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();
|
||||||
|
|
||||||
std::array<tState,MaxThreads> Tasks;
|
Poco::ThreadPool Pool_;
|
||||||
|
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());
|
||||||
// std::cout << "Scheduling config push for " << uuid << std::endl;
|
bool TaskAdded=false;
|
||||||
bool found_slot = false;
|
while(!TaskAdded) {
|
||||||
while (!found_slot) {
|
if (Pool_.available()) {
|
||||||
for (auto &cur_task: Tasks) {
|
JobList.push_back(NewTask);
|
||||||
if (cur_task.task == nullptr) {
|
Pool_.start(*NewTask);
|
||||||
cur_task.task = NewTask;
|
TaskAdded = true;
|
||||||
cur_task.thr_.start(*NewTask);
|
continue;
|
||||||
found_slot = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Let's look for a slot...
|
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||||
if (!found_slot) {
|
VenueDeviceRebooter * current_job = *job_it;
|
||||||
for (auto &cur_task: Tasks) {
|
if(current_job!= nullptr && current_job->done_) {
|
||||||
if (cur_task.task != nullptr && cur_task.task->started_) {
|
if(current_job->rebooted_)
|
||||||
if (cur_task.thr_.isRunning())
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
continue;
|
else
|
||||||
if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
N.content.warning.push_back(current_job->SerialNumber);
|
||||||
cur_task.thr_.join();
|
rebooted_ += current_job->rebooted_;
|
||||||
rebooted_ += cur_task.task->rebooted_;
|
failed_ += current_job->failed_;
|
||||||
failed_ += cur_task.task->failed_;
|
job_it = JobList.erase(job_it);
|
||||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
delete current_job;
|
||||||
delete cur_task.task;
|
} else {
|
||||||
cur_task.task = nullptr;
|
++job_it;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger().debug("Waiting for outstanding update threads to finish.");
|
Logger().debug("Waiting for outstanding update threads to finish.");
|
||||||
bool stillTasksRunning=true;
|
Pool_.joinAll();
|
||||||
while(stillTasksRunning) {
|
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||||
stillTasksRunning = false;
|
VenueDeviceRebooter * current_job = *job_it;
|
||||||
for(auto &cur_task:Tasks) {
|
if(current_job!= nullptr && current_job->done_) {
|
||||||
if(cur_task.task!= nullptr && cur_task.task->started_) {
|
if(current_job->rebooted_)
|
||||||
if(cur_task.thr_.isRunning()) {
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
stillTasksRunning = true;
|
else
|
||||||
continue;
|
N.content.warning.push_back(current_job->SerialNumber);
|
||||||
}
|
rebooted_ += current_job->rebooted_;
|
||||||
if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
failed_ += current_job->failed_;
|
||||||
cur_task.thr_.join();
|
job_it = JobList.erase(job_it);
|
||||||
if(cur_task.task->rebooted_) {
|
delete current_job;
|
||||||
rebooted_++;
|
} else {
|
||||||
N.content.success.push_back(cur_task.task->SerialNumber);
|
++job_it;
|
||||||
} 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N);
|
// std::cout << N.content.details << std::endl;
|
||||||
|
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_));
|
||||||
delete this;
|
Utils::SetThreadName("free");
|
||||||
|
Complete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#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 {
|
||||||
@@ -30,7 +31,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
Storage::ApplyRules(rules_,Device.deviceRules);
|
Storage::ApplyRules(rules_,Device.deviceRules);
|
||||||
if(Device.deviceRules.firmwareUpgrade=="no") {
|
if(Device.deviceRules.firmwareUpgrade=="no") {
|
||||||
std::cout << "Skipped Upgrade:" << Device.serialNumber << std::endl;
|
poco_debug(Logger(),fmt::format("Skipped Upgrade: {}", Device.serialNumber));
|
||||||
skipped_++;
|
skipped_++;
|
||||||
done_=true;
|
done_=true;
|
||||||
return;
|
return;
|
||||||
@@ -39,24 +40,25 @@ 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));
|
||||||
failed_++;
|
not_connected_++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Did not Upgrade:" << Device.serialNumber << " to <unknown>" << std::endl;
|
Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber));
|
||||||
failed_++;
|
no_firmware_++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done_ = true;
|
done_ = true;
|
||||||
// std::cout << "Done push for " << Device.serialNumber << std::endl;
|
// std::cout << "Done push for " << Device.serialNumber << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t upgraded_=0, failed_=0, skipped_=0;
|
std::uint64_t upgraded_ = 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;
|
||||||
@@ -69,132 +71,111 @@ namespace OpenWifi {
|
|||||||
inline Poco::Logger & Logger() { return Logger_; }
|
inline Poco::Logger & Logger() { return Logger_; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VenueUpgrade: public Poco::Runnable {
|
class VenueUpgrade: public Job {
|
||||||
public:
|
public:
|
||||||
explicit VenueUpgrade(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
|
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) :
|
||||||
VenueUUID_(VenueUUID),
|
Job(JobID, name, parameters, when, UI, L) {
|
||||||
UI_(UI),
|
|
||||||
When_(When),
|
|
||||||
Logger_(L)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string Start() {
|
inline virtual void run() final {
|
||||||
JobId_ = MicroService::CreateUUID();
|
|
||||||
Worker_.start(*this);
|
|
||||||
return JobId_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
Utils::SetThreadName("venue-upgr");
|
||||||
std::string VenueUUID_;
|
auto VenueUUID_ = Parameter(0);
|
||||||
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_; }
|
WebSocketClientNotificationVenueUpgradeList_t N;
|
||||||
|
|
||||||
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, failed_ = 0;
|
uint64_t upgraded_ = 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();
|
||||||
|
|
||||||
std::array<tState,MaxThreads> Tasks;
|
Poco::ThreadPool Pool_;
|
||||||
ProvObjects::DeviceRules Rules;
|
std::list<VenueDeviceUpgrade*> JobList;
|
||||||
|
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());
|
||||||
// std::cout << "Scheduling config push for " << uuid << std::endl;
|
bool TaskAdded = false;
|
||||||
bool found_slot = false;
|
while (!TaskAdded) {
|
||||||
while (!found_slot) {
|
if (Pool_.available()) {
|
||||||
for (auto &cur_task: Tasks) {
|
JobList.push_back(NewTask);
|
||||||
if (cur_task.task == nullptr) {
|
Pool_.start(*NewTask);
|
||||||
cur_task.task = NewTask;
|
TaskAdded = true;
|
||||||
cur_task.thr_.start(*NewTask);
|
continue;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Logger().debug("Waiting for outstanding update threads to finish.");
|
for (auto job_it = JobList.begin(); job_it != JobList.end();) {
|
||||||
bool stillTasksRunning=true;
|
VenueDeviceUpgrade *current_job = *job_it;
|
||||||
while(stillTasksRunning) {
|
if (current_job != nullptr && current_job->done_) {
|
||||||
stillTasksRunning = false;
|
if (current_job->upgraded_)
|
||||||
for(auto &cur_task:Tasks) {
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
if(cur_task.task!= nullptr && cur_task.task->started_) {
|
else if (current_job->skipped_)
|
||||||
if(cur_task.thr_.isRunning()) {
|
N.content.skipped.push_back(current_job->SerialNumber);
|
||||||
stillTasksRunning = true;
|
else if (current_job->not_connected_)
|
||||||
continue;
|
N.content.not_connected.push_back(current_job->SerialNumber);
|
||||||
}
|
else if (current_job->no_firmware_)
|
||||||
if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
N.content.no_firmware.push_back(current_job->SerialNumber);
|
||||||
cur_task.thr_.join();
|
upgraded_ += current_job->upgraded_;
|
||||||
if(cur_task.task->upgraded_) {
|
skipped_ += current_job->skipped_;
|
||||||
upgraded_++;
|
no_firmware_ += current_job->no_firmware_;
|
||||||
N.content.success.push_back(cur_task.task->SerialNumber);
|
not_connected_ += current_job->not_connected_;
|
||||||
} else if(cur_task.task->failed_) {
|
job_it = JobList.erase(job_it);
|
||||||
failed_++;
|
delete current_job;
|
||||||
N.content.warning.push_back(cur_task.task->SerialNumber);
|
} else {
|
||||||
}
|
++job_it;
|
||||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
|
||||||
delete cur_task.task;
|
|
||||||
cur_task.task = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
|
Logger().debug("Waiting for outstanding upgrade threads to finish.");
|
||||||
JobId_, upgraded_ ,failed_);
|
Pool_.joinAll();
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N);
|
// std::cout << N.content.details << std::endl;
|
||||||
Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
|
WebSocketClientNotificationVenueUpgradeCompletionToUser(UserInfo().email,N);
|
||||||
JobId_, upgraded_ ,failed_));
|
Logger().information(N.content.details);
|
||||||
delete this;
|
Utils::SetThreadName("free");
|
||||||
|
Complete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,11 @@ 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"
|
||||||
@@ -238,6 +243,11 @@ 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) {
|
||||||
@@ -334,12 +344,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) {
|
||||||
@@ -374,7 +384,14 @@ namespace OpenWifi::RESTAPI_utils {
|
|||||||
|
|
||||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
|
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) {
|
||||||
@@ -643,6 +660,27 @@ 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,
|
||||||
@@ -665,6 +703,19 @@ namespace OpenWifi::Utils {
|
|||||||
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0);
|
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;
|
||||||
|
|
||||||
@@ -1167,6 +1218,7 @@ namespace OpenWifi {
|
|||||||
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
|
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
|
||||||
static const std::string uSERVICE_INSTALLER{ "owinst"};
|
static const std::string uSERVICE_INSTALLER{ "owinst"};
|
||||||
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
|
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
|
||||||
|
static const std::string uSERVICE_OWRRM{ "owrrm"};
|
||||||
|
|
||||||
class ConfigurationEntry {
|
class ConfigurationEntry {
|
||||||
public:
|
public:
|
||||||
@@ -1315,7 +1367,7 @@ namespace OpenWifi {
|
|||||||
inline void Start();
|
inline void Start();
|
||||||
inline void Stop();
|
inline void Stop();
|
||||||
private:
|
private:
|
||||||
std::atomic_bool Running_ = false;
|
mutable std::atomic_bool Running_ = false;
|
||||||
Poco::Thread Thread_;
|
Poco::Thread Thread_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1360,13 +1412,14 @@ 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 const std::string &KeyFile() const { return key_file_; };
|
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
|
||||||
[[nodiscard]] inline const std::string &CertFile() const { return cert_file_; };
|
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
|
||||||
[[nodiscard]] inline const std::string &RootCA() const { return root_ca_; };
|
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
|
||||||
[[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; };
|
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
|
||||||
[[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; };
|
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
|
||||||
[[nodiscard]] inline const std::string &Name() const { return name_; };
|
[[nodiscard]] inline auto 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;
|
||||||
@@ -1846,7 +1899,8 @@ namespace OpenWifi {
|
|||||||
Request = &RequestIn;
|
Request = &RequestIn;
|
||||||
Response = &ResponseIn;
|
Response = &ResponseIn;
|
||||||
|
|
||||||
Poco::Thread::current()->setName("WebServerThread_" + std::to_string(TransactionId_));
|
// std::string th_name = "restsvr_" + 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) {
|
||||||
@@ -1895,36 +1949,32 @@ namespace OpenWifi {
|
|||||||
[[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; }
|
[[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; }
|
||||||
[[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; }
|
[[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; }
|
||||||
|
|
||||||
/* [[nodiscard]] inline const Poco::JSON::Object::Ptr ParseStream() {
|
inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) {
|
||||||
return IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>();
|
bindings.clear();
|
||||||
}
|
auto PathItems = Poco::StringTokenizer(Request, "/");
|
||||||
*/
|
|
||||||
|
|
||||||
inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) {
|
for(const auto &EndPoint:EndPoints) {
|
||||||
bindings.clear();
|
auto ParamItems = Poco::StringTokenizer(EndPoint, "/");
|
||||||
std::vector<std::string> PathItems = Utils::Split(Request, '/');
|
if (PathItems.count() != ParamItems.count())
|
||||||
|
continue;
|
||||||
|
|
||||||
for(const auto &EndPoint:EndPoints) {
|
bool Matched = true;
|
||||||
std::vector<std::string> ParamItems = Utils::Split(EndPoint, '/');
|
for (size_t i = 0; i < PathItems.count(); i++) {
|
||||||
if (PathItems.size() != ParamItems.size())
|
if (PathItems[i] != ParamItems[i]) {
|
||||||
continue;
|
if (ParamItems[i][0] == '{') {
|
||||||
|
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
|
||||||
bool Matched = true;
|
bindings[Poco::toLower(ParamName)] = PathItems[i];
|
||||||
for (size_t i = 0; i != PathItems.size() && Matched; i++) {
|
} else {
|
||||||
if (PathItems[i] != ParamItems[i]) {
|
Matched = false;
|
||||||
if (ParamItems[i][0] == '{') {
|
break;
|
||||||
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
|
}
|
||||||
bindings[Poco::toLower(ParamName)] = PathItems[i];
|
}
|
||||||
} else {
|
}
|
||||||
Matched = false;
|
if(Matched)
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
if(Matched)
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void PrintBindings() {
|
inline void PrintBindings() {
|
||||||
for (const auto &[key, value] : Bindings_)
|
for (const auto &[key, value] : Bindings_)
|
||||||
@@ -2045,6 +2095,17 @@ 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;
|
||||||
@@ -2385,6 +2446,7 @@ 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_;
|
||||||
@@ -2401,6 +2463,7 @@ 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 {
|
||||||
@@ -2582,7 +2645,7 @@ namespace OpenWifi {
|
|||||||
private:
|
private:
|
||||||
std::recursive_mutex Mutex_;
|
std::recursive_mutex Mutex_;
|
||||||
Poco::Thread Worker_;
|
Poco::Thread Worker_;
|
||||||
std::atomic_bool Running_=false;
|
mutable std::atomic_bool Running_=false;
|
||||||
Poco::NotificationQueue Queue_;
|
Poco::NotificationQueue Queue_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2608,7 +2671,7 @@ namespace OpenWifi {
|
|||||||
private:
|
private:
|
||||||
std::recursive_mutex Mutex_;
|
std::recursive_mutex Mutex_;
|
||||||
Poco::Thread Worker_;
|
Poco::Thread Worker_;
|
||||||
std::atomic_bool Running_=false;
|
mutable std::atomic_bool Running_=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class KafkaDispatcher : public Poco::Runnable {
|
class KafkaDispatcher : public Poco::Runnable {
|
||||||
@@ -2665,6 +2728,7 @@ 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) {
|
||||||
@@ -2687,12 +2751,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_;
|
||||||
std::atomic_bool Running_=false;
|
mutable 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 {
|
||||||
@@ -2885,6 +2949,7 @@ 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 {}.",
|
||||||
@@ -2953,7 +3018,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;
|
||||||
std::atomic_bool Running_=false;
|
mutable std::atomic_bool Running_=false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
|
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
|
||||||
@@ -2973,7 +3038,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();
|
||||||
@@ -2981,22 +3046,23 @@ 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;
|
||||||
Poco::Thread::current()->setName(fmt::format("RESTAPI_ExtServer_{}",Id));
|
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
|
||||||
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_;
|
Poco::ThreadPool Pool_{"x-rest",2,32};
|
||||||
RESTAPI_GenericServer Server_;
|
RESTAPI_GenericServer Server_;
|
||||||
|
|
||||||
RESTAPI_ExtServer() noexcept:
|
RESTAPI_ExtServer() noexcept:
|
||||||
SubSystemServer("RESTAPI_ExtServer", "RESTAPIServer", "openwifi.restapi"),
|
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
|
||||||
Pool_("RESTAPI_ExtServer",4,50,120)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3009,7 +3075,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());
|
||||||
Poco::Thread::current()->setName(fmt::format("ExtWebServer_{}",TransactionId_));
|
Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str());
|
||||||
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
|
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
||||||
@@ -3107,7 +3173,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();
|
||||||
@@ -3118,17 +3184,18 @@ 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;
|
||||||
Poco::Thread::current()->setName(fmt::format("RESTAPI_IntServer_{}",Id));
|
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
|
||||||
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_;
|
Poco::ThreadPool Pool_{"i-rest",2,16};
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3139,6 +3206,7 @@ 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_);
|
||||||
}
|
}
|
||||||
@@ -3182,7 +3250,6 @@ 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_; }
|
||||||
@@ -3215,7 +3282,12 @@ namespace OpenWifi {
|
|||||||
return Poco::Logger::get(Name);
|
return Poco::Logger::get(Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Exit(int Reason);
|
virtual void GetExtraConfiguration(Poco::JSON::Object & Cfg) {
|
||||||
|
Cfg.set("additionalConfiguration",false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void Exit(int Reason);
|
||||||
inline void BusMessageReceived(const std::string &Key, const std::string & Payload);
|
inline 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();
|
||||||
@@ -3251,7 +3323,6 @@ 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();
|
||||||
@@ -3281,6 +3352,9 @@ 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;
|
||||||
@@ -3294,7 +3368,6 @@ 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_;
|
||||||
@@ -3315,6 +3388,7 @@ 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) {
|
||||||
@@ -3464,7 +3538,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_ = CreateHash(MyPublicEndPoint_);
|
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroServicePostInitialization();
|
void MicroServicePostInitialization();
|
||||||
@@ -3527,7 +3601,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();
|
||||||
|
|
||||||
@@ -3801,11 +3875,6 @@ 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);
|
||||||
@@ -3868,6 +3937,7 @@ 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()) {
|
||||||
@@ -3904,6 +3974,7 @@ 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()) {
|
||||||
@@ -3921,7 +3992,6 @@ 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);
|
||||||
|
|
||||||
@@ -4028,6 +4098,7 @@ 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();
|
||||||
}
|
}
|
||||||
@@ -4037,6 +4108,7 @@ 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_) {
|
||||||
@@ -4122,6 +4194,8 @@ 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") }
|
||||||
@@ -4160,6 +4234,8 @@ 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") },
|
||||||
@@ -4298,6 +4374,11 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4670,6 +4751,7 @@ 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={}",
|
||||||
@@ -4678,6 +4760,7 @@ 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,
|
||||||
@@ -4701,6 +4784,7 @@ 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,
|
||||||
@@ -4783,7 +4867,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);
|
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName);
|
||||||
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);
|
||||||
@@ -4818,8 +4902,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:
|
||||||
std::atomic_bool Running_ = false;
|
mutable 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_;
|
||||||
@@ -4834,18 +4918,22 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
class WebSocketClient {
|
class WebSocketClient {
|
||||||
public:
|
public:
|
||||||
explicit WebSocketClient(Poco::Net::WebSocket &WS, const std::string &Id, Poco::Logger &L,
|
explicit WebSocketClient(Poco::Net::WebSocket &WS,
|
||||||
WebSocketClientProcessor *Processor);
|
const std::string &Id,
|
||||||
|
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_;
|
||||||
Poco::Logger &Logger_;
|
std::string UserName_;
|
||||||
bool Authenticated_ = false;
|
Poco::Logger &Logger_;
|
||||||
|
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);
|
||||||
@@ -4853,33 +4941,9 @@ namespace OpenWifi {
|
|||||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* inline MyParallelSocketReactor::MyParallelSocketReactor(uint32_t NumReactors) :
|
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) {
|
||||||
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,Logger(), Processor_);
|
auto Client = new WebSocketClient(WS,Id,UserName,Logger(), Processor_);
|
||||||
Clients_[Id] = std::make_pair(Client,"");
|
Clients_[Id] = std::make_pair(Client,"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4909,12 +4973,13 @@ 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", "WSCLNT-SVR", "websocketclients")
|
SubSystemServer("WebSocketClientServer", "UI-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);
|
||||||
|
|
||||||
@@ -4962,8 +5027,12 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
for(const auto &client:Clients_) {
|
for(const auto &client:Clients_) {
|
||||||
if(client.second.second == UserName) {
|
if(client.second.second == UserName) {
|
||||||
if(client.second.first->Send(Payload))
|
try {
|
||||||
Sent++;
|
if (client.second.first->Send(Payload))
|
||||||
|
Sent++;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Sent>0;
|
return Sent>0;
|
||||||
@@ -4985,70 +5054,73 @@ namespace OpenWifi {
|
|||||||
int flags;
|
int flags;
|
||||||
int n;
|
int n;
|
||||||
bool Done=false;
|
bool Done=false;
|
||||||
Poco::Buffer<char> IncomingFrame(0);
|
try {
|
||||||
n = WS_->receiveFrame(IncomingFrame, flags);
|
Poco::Buffer<char> IncomingFrame(0);
|
||||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
n = WS_->receiveFrame(IncomingFrame, flags);
|
||||||
|
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||||
|
|
||||||
if(n==0) {
|
if (n == 0) {
|
||||||
return delete this;
|
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||||
}
|
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;
|
||||||
break;
|
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
} break;
|
||||||
}
|
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||||
break;
|
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
Done = true;
|
||||||
Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.",Id_));
|
} break;
|
||||||
Done=true;
|
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||||
}
|
IncomingFrame.append(0);
|
||||||
break;
|
if (!Authenticated_) {
|
||||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
std::string Frame{IncomingFrame.begin()};
|
||||||
IncomingFrame.append(0);
|
auto Tokens = Utils::Split(Frame, ':');
|
||||||
if(!Authenticated_) {
|
bool Expired = false, Contacted = false;
|
||||||
std::string Frame{IncomingFrame.begin()};
|
if (Tokens.size() == 2 &&
|
||||||
auto Tokens = Utils::Split(Frame,':');
|
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||||
bool Expired = false, Contacted = false;
|
Authenticated_ = true;
|
||||||
if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
UserName_ = UserInfo_.userinfo.email;
|
||||||
Authenticated_=true;
|
Logger().warning(Poco::format("START(%s): %s UI Client is starting WS connection.", Id_, UserName_));
|
||||||
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 = P.parse(IncomingFrame.begin())
|
auto Obj =
|
||||||
.extract<Poco::JSON::Object::Ptr>();
|
P.parse(IncomingFrame.begin()).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;
|
||||||
@@ -5060,9 +5132,10 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, const std::string &UserName, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
||||||
Reactor_(WebSocketClientServer()->Reactor()),
|
Reactor_(WebSocketClientServer()->Reactor()),
|
||||||
Id_(Id),
|
Id_(Id),
|
||||||
|
UserName_(UserName),
|
||||||
Logger_(L),
|
Logger_(L),
|
||||||
Processor_(Processor) {
|
Processor_(Processor) {
|
||||||
try {
|
try {
|
||||||
@@ -5142,9 +5215,8 @@ 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);
|
WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
std::cout << "Cannot create websocket client..." << std::endl;
|
std::cout << "Cannot create websocket client..." << std::endl;
|
||||||
|
|||||||
@@ -146,6 +146,10 @@ namespace OpenWifi {
|
|||||||
WebSocketClientServer()->SendUserNotification(User,N);
|
WebSocketClientServer()->SendUserNotification(User,N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////
|
||||||
|
/////
|
||||||
|
/////
|
||||||
|
|
||||||
struct WebSocketNotificationRebootList {
|
struct WebSocketNotificationRebootList {
|
||||||
std::string title,
|
std::string title,
|
||||||
details,
|
details,
|
||||||
@@ -189,5 +193,58 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -133,6 +133,37 @@ 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 };
|
||||||
|
|
||||||
|
|||||||
937
src/libs/croncpp.h
Normal file
937
src/libs/croncpp.h
Normal file
@@ -0,0 +1,937 @@
|
|||||||
|
/*
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/ow_version.h
Normal file
13
src/ow_version.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-12-06.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace OW_VERSION {
|
||||||
|
inline static const std::string VERSION{"2.6.0"};
|
||||||
|
inline static const std::string BUILD{"128"};
|
||||||
|
inline static const std::string HASH{"3b0f2a0"};
|
||||||
|
}
|
||||||
@@ -96,40 +96,42 @@ 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;
|
||||||
StorageService()->VenueDB().GetRecord("id",Node,E);
|
if(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;
|
||||||
StorageService()->EntityDB().GetRecord("id",Node,E);
|
if(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) {
|
||||||
|
|||||||
@@ -83,12 +83,13 @@ 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 &SerialNumber,
|
bool InventoryDB::CreateFromConnection( const std::string &SerialNumberRaw,
|
||||||
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();
|
||||||
@@ -223,7 +224,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=="yes")
|
if(Rules.rrm!="no" && Rules.rrm!="inherit")
|
||||||
DeviceList.push_back(SerialNumber);
|
DeviceList.push_back(SerialNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,51 +0,0 @@
|
|||||||
//
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//
|
|
||||||
// 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:
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -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 ${OWPROV}..."
|
echo "Using PROV=${OWPROV}..."
|
||||||
else
|
else
|
||||||
echo "OWPROV endpoint is not found:"
|
echo "OWPROV endpoint is not found:"
|
||||||
jq < ${result_file}
|
jq < ${result_file}
|
||||||
@@ -108,6 +108,33 @@ 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" \
|
||||||
@@ -499,6 +526,32 @@ listvenues() {
|
|||||||
jq < ${result_file}
|
jq < ${result_file}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getvenuedevices() {
|
||||||
|
curl ${FLAGS} -X GET "https://${OWPROV}/api/v1/venue/$1?getDevices=true&getChildren=true" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer ${token}" \
|
||||||
|
-H "Accept: application/json" > ${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 ;;
|
||||||
@@ -546,6 +599,9 @@ case "$1" in
|
|||||||
"getsignup") login; getsignup $2; logout;;
|
"getsignup") login; getsignup $2; logout;;
|
||||||
"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;;
|
||||||
|
"listrrmalgos") login; listrrmalgos; logout;;
|
||||||
|
"rrmprovider") login; rrmprovider; logout;;
|
||||||
*) help ;;
|
*) help ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user