mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov.git
synced 2025-10-30 02:02:36 +00:00
Compare commits
12 Commits
v2.7.0-RC1
...
v2.6.0-RC3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
439aa1d07a | ||
|
|
a9293a7717 | ||
|
|
80d5ae340f | ||
|
|
265ae7483b | ||
|
|
43c4ad2211 | ||
|
|
5cccd0b797 | ||
|
|
b8bcece4bf | ||
|
|
3132b964bd | ||
|
|
711dc59fa6 | ||
|
|
82fbfeebc6 | ||
|
|
77a4df5221 | ||
|
|
c749275ef8 |
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owprov VERSION 2.7.0)
|
||||
project(owprov VERSION 2.6.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -125,6 +125,7 @@ add_executable(owprov
|
||||
src/RESTAPI/RESTAPI_db_helpers.h
|
||||
src/JobController.cpp src/JobController.h
|
||||
src/JobRegistrations.cpp
|
||||
src/storage/storage_jobs.cpp src/storage/storage_jobs.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_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h
|
||||
@@ -134,14 +135,7 @@ add_executable(owprov
|
||||
src/storage/storage_variables.cpp src/storage/storage_variables.h
|
||||
src/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/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)
|
||||
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)
|
||||
|
||||
target_link_libraries(owprov PUBLIC
|
||||
${Poco_LIBRARIES}
|
||||
|
||||
54
Dockerfile
54
Dockerfile
@@ -1,10 +1,4 @@
|
||||
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
|
||||
FROM alpine:3.15 AS build-base
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
make cmake g++ git \
|
||||
@@ -15,10 +9,8 @@ RUN apk add --update --no-cache \
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -27,26 +19,10 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ARG FMTLIB_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS cppkafka-build
|
||||
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -57,10 +33,8 @@ RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ARG JSON_VALIDATOR_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
@@ -69,6 +43,18 @@ RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS fmtlib-build
|
||||
|
||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
||||
|
||||
WORKDIR /fmtlib
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS owprov-build
|
||||
|
||||
ADD CMakeLists.txt build /owprov/
|
||||
@@ -91,7 +77,7 @@ WORKDIR /owprov/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine:$ALPINE_VERSION
|
||||
FROM alpine:3.15
|
||||
|
||||
ENV OWPROV_USER=owprov \
|
||||
OWPROV_ROOT=/owprov-data \
|
||||
|
||||
@@ -5,7 +5,7 @@ if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
update-ca-certificates
|
||||
fi
|
||||
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWPROV_CONFIG"/owprov.properties ]]; then
|
||||
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWPROV_ROOT/certs/restapi-ca.pem"} \
|
||||
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16005"} \
|
||||
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWPROV_ROOT/certs/restapi-cert.pem"} \
|
||||
|
||||
2
helm/.gitignore
vendored
2
helm/.gitignore
vendored
@@ -1,3 +1 @@
|
||||
*.swp
|
||||
Chart.lock
|
||||
charts/
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -47,39 +46,6 @@ spec:
|
||||
- -timeout
|
||||
- 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:
|
||||
|
||||
- name: owprov
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owprov:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov
|
||||
tag: v2.7.0-RC1
|
||||
tag: v2.6.0-RC3
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
|
||||
@@ -27,13 +27,71 @@ components:
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
Unauthorized:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
Success:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||
description: The requested operation was performed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
Operation:
|
||||
type: string
|
||||
Details:
|
||||
type: string
|
||||
Code:
|
||||
type: integer
|
||||
|
||||
BadRequest:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||
description: The requested operation failed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: integer
|
||||
|
||||
schemas:
|
||||
|
||||
@@ -1958,6 +2016,11 @@ paths:
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: deviceType
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
- in: query
|
||||
description: Pagination start (starts at 1. If not specified, 1 is assumed)
|
||||
name: offset
|
||||
@@ -2029,21 +2092,6 @@ paths:
|
||||
type: string
|
||||
format: uuid
|
||||
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:
|
||||
200:
|
||||
description: Return a list of elements
|
||||
@@ -2265,6 +2313,12 @@ paths:
|
||||
type: string
|
||||
example: serial1,serial2,serial3
|
||||
required: false
|
||||
- in: query
|
||||
description: only serial numbers of full device details
|
||||
name: serialOnly
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
description: return the number of devices
|
||||
name: countOnly
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: OpenWiFi RRM Provider Model
|
||||
description: Definitions and APIs to manages an OpenWiFi RRM Providers.
|
||||
version: 1.0.0
|
||||
license:
|
||||
name: BSD3
|
||||
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
|
||||
servers:
|
||||
- url: 'https://localhost:16022/api/v1'
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
- ApiKeyAuth: []
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
ApiKeyAuth:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-API-KEY
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||
Unauthorized:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||
Success:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||
BadRequest:
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||
|
||||
schemas:
|
||||
|
||||
Provider:
|
||||
type: object
|
||||
properties:
|
||||
vendor:
|
||||
description: The name of the vendor for display.
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 128
|
||||
vendorShortname:
|
||||
description: A shortname for the vendor. Only letters and numbers are allowed. This is the name used internally.
|
||||
type: string
|
||||
minLength: 4
|
||||
maxLength: 16
|
||||
version:
|
||||
description: An identifier that will help users identify the version of the RRM module they are using.
|
||||
type: string
|
||||
about:
|
||||
description: A link to the Vendor page for this RRM Module
|
||||
type: string
|
||||
|
||||
|
||||
Algorithm:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: A display for this algorithm.
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 128
|
||||
description:
|
||||
description: A description of the algorithm.
|
||||
type: string
|
||||
shortName:
|
||||
description: This is the name used internally.
|
||||
type: string
|
||||
minLength: 4
|
||||
maxLength: 16
|
||||
parameterFormat:
|
||||
description: this is a Regex used to validate the input. If this is empty, no validation will be performed.
|
||||
type: string
|
||||
parameterSamples:
|
||||
description: These samples will be displayed in the UI to the user trying to configure the options
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
helper:
|
||||
description: A link to a web page or PDF document explaining the algorithm and its parameters
|
||||
type: string
|
||||
|
||||
Algorithms:
|
||||
description: The list of all algorithms supported by the vendor
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Algorithm'
|
||||
|
||||
paths:
|
||||
/provider:
|
||||
get:
|
||||
tags:
|
||||
- RRM
|
||||
operationId: getProvider
|
||||
summary: Retrieve information about the provider for this RRM Module
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/Provider'
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/algorithms:
|
||||
get:
|
||||
tags:
|
||||
- RRM
|
||||
operationId: getAlgorithms
|
||||
summary: Retrieve a lists of algorithms supported in the module.
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/Algorithms'
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/runRRM:
|
||||
put:
|
||||
tags:
|
||||
- RRM
|
||||
operationId: runRRMNow
|
||||
summary: Run a specific or default RRM algorithm. The UI user or CLI user will have the ability to run an algorithm on demand.
|
||||
parameters:
|
||||
- in: query
|
||||
description:
|
||||
name: venue
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
- in: query
|
||||
description: Perform RRM without updating anything. This may be used by an admin to see what RRM would do.
|
||||
name: mock
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
required: false
|
||||
- in: query
|
||||
description: Specify the RRM algorithm to use. If omitted, select the default algorithm.
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
- in: query
|
||||
description: Specify the parameters to use with the RRM algorithm to use. If omitted, select the default parameters.
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
description: Return the list of actions that were or would be performed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
@@ -153,62 +153,60 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
std::set<std::string> Sections;
|
||||
for (const auto &i: Config_) {
|
||||
Poco::JSON::Parser P;
|
||||
auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Names = O->getNames();
|
||||
for (const auto &SectionName: Names) {
|
||||
auto InsertInfo = Sections.insert(SectionName);
|
||||
if (InsertInfo.second) {
|
||||
if (O->isArray(SectionName)) {
|
||||
auto OriginalArray = O->getArray(SectionName);
|
||||
if (Explain_) {
|
||||
Poco::JSON::Object ExObj;
|
||||
ExObj.set("from-uuid", i.info.id);
|
||||
ExObj.set("from-name", i.info.name);
|
||||
ExObj.set("action", "added");
|
||||
ExObj.set("element", OriginalArray);
|
||||
Explanation_.add(ExObj);
|
||||
}
|
||||
auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>();
|
||||
ReplaceVariablesInArray(OriginalArray, ExpandedArray);
|
||||
Configuration->set(SectionName, ExpandedArray);
|
||||
} else if (O->isObject(SectionName)) {
|
||||
auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>();
|
||||
if (Explain_) {
|
||||
Poco::JSON::Object ExObj;
|
||||
ExObj.set("from-uuid", i.info.id);
|
||||
ExObj.set("from-name", i.info.name);
|
||||
ExObj.set("action", "added");
|
||||
ExObj.set("element", OriginalSection);
|
||||
Explanation_.add(ExObj);
|
||||
}
|
||||
auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>();
|
||||
ReplaceVariablesInObject(OriginalSection, ExpandedSection);
|
||||
Configuration->set(SectionName, ExpandedSection);
|
||||
} else {
|
||||
std::cout << " --- unknown element type --- " << O->get(SectionName).toString()
|
||||
<< std::endl;
|
||||
}
|
||||
} else {
|
||||
std::set<std::string> Sections;
|
||||
for(const auto &i:Config_) {
|
||||
Poco::JSON::Parser P;
|
||||
auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>();
|
||||
auto Names = O->getNames();
|
||||
for(const auto &SectionName:Names) {
|
||||
auto InsertInfo = Sections.insert(SectionName);
|
||||
if (InsertInfo.second) {
|
||||
if (O->isArray(SectionName)) {
|
||||
auto OriginalArray = O->getArray(SectionName);
|
||||
if (Explain_) {
|
||||
Poco::JSON::Object ExObj;
|
||||
ExObj.set("from-uuid", i.info.id);
|
||||
ExObj.set("from-name", i.info.name);
|
||||
ExObj.set("action", "ignored");
|
||||
ExObj.set("reason", "weight insufficient");
|
||||
ExObj.set("element", O->get(SectionName));
|
||||
ExObj.set("action", "added");
|
||||
ExObj.set("element", OriginalArray);
|
||||
Explanation_.add(ExObj);
|
||||
}
|
||||
auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>();
|
||||
ReplaceVariablesInArray(OriginalArray, ExpandedArray);
|
||||
Configuration->set(SectionName, ExpandedArray);
|
||||
} else if (O->isObject(SectionName)) {
|
||||
auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>();
|
||||
if (Explain_) {
|
||||
Poco::JSON::Object ExObj;
|
||||
ExObj.set("from-uuid", i.info.id);
|
||||
ExObj.set("from-name", i.info.name);
|
||||
ExObj.set("action", "added");
|
||||
ExObj.set("element", OriginalSection);
|
||||
Explanation_.add(ExObj);
|
||||
}
|
||||
auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>();
|
||||
ReplaceVariablesInObject(OriginalSection, ExpandedSection);
|
||||
Configuration->set(SectionName, ExpandedSection);
|
||||
} else {
|
||||
std::cout << " --- unknown element type --- " << O->get(SectionName).toString() << std::endl;
|
||||
}
|
||||
} else {
|
||||
if (Explain_) {
|
||||
Poco::JSON::Object ExObj;
|
||||
ExObj.set("from-uuid", i.info.id);
|
||||
ExObj.set("from-name", i.info.name);
|
||||
ExObj.set("action", "ignored");
|
||||
ExObj.set("reason", "weight insufficient");
|
||||
ExObj.set("element", O->get(SectionName));
|
||||
Explanation_.add(ExObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return !Config_.empty();
|
||||
if(Config_.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) {
|
||||
|
||||
@@ -26,7 +26,6 @@ namespace OpenWifi {
|
||||
|
||||
void AutoDiscovery::run() {
|
||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||
Utils::SetThreadName("auto-discovery");
|
||||
while(Note && Running_) {
|
||||
auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get());
|
||||
if(Msg!= nullptr) {
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace OpenWifi {
|
||||
void Stop() override;
|
||||
void ConnectionReceived( const std::string & Key, const std::string & Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
poco_debug(Logger(),Poco::format("Device(%s): Connection/Ping message.", Key));
|
||||
Logger().information(Poco::format("Device(%s): Connection/Ping message.", Key));
|
||||
Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload));
|
||||
}
|
||||
void run() override;
|
||||
|
||||
@@ -26,8 +26,6 @@ namespace OpenWifi {
|
||||
{"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" }
|
||||
};
|
||||
|
||||
Utils::SetThreadName("file-dmnldr");
|
||||
|
||||
for(const auto &[url,filename]:Files) {
|
||||
try {
|
||||
std::string FileContent;
|
||||
|
||||
@@ -27,32 +27,11 @@ namespace OpenWifi {
|
||||
|
||||
void JobController::run() {
|
||||
Running_ = true ;
|
||||
Utils::SetThreadName("job-controller");
|
||||
|
||||
while(Running_) {
|
||||
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,45 +7,99 @@
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class Job : public Poco::Runnable {
|
||||
public:
|
||||
Job(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) :
|
||||
jobId_(JobID),
|
||||
name_(name),
|
||||
parameters_(parameters),
|
||||
when_(when),
|
||||
userinfo_(UI),
|
||||
Logger_(L)
|
||||
{};
|
||||
class Job {
|
||||
public:
|
||||
struct Parameter {
|
||||
std::string name;
|
||||
std::string value;
|
||||
inline void to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"name",name);
|
||||
RESTAPI_utils::field_to_json(Obj,"value",value);
|
||||
}
|
||||
|
||||
virtual void run() = 0;
|
||||
[[nodiscard]] std::string Name() const { return name_; }
|
||||
const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; }
|
||||
Poco::Logger & Logger() { return Logger_; }
|
||||
const std::string & JobId() const { return jobId_; }
|
||||
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(); }
|
||||
inline bool from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"name",name);
|
||||
RESTAPI_utils::field_from_json(Obj,"value",value);
|
||||
return true;
|
||||
} catch (...) {
|
||||
|
||||
private:
|
||||
std::string jobId_;
|
||||
std::string name_;
|
||||
std::vector<std::string> parameters_;
|
||||
uint64_t when_=0;
|
||||
SecurityObjects::UserInfo userinfo_;
|
||||
Poco::Logger & Logger_;
|
||||
uint64_t started_=0;
|
||||
uint64_t completed_=0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct Status {
|
||||
Types::UUID_t UUID;
|
||||
uint64_t Start = 0 ;
|
||||
uint64_t Progress = 0 ;
|
||||
uint64_t Completed = 0 ;
|
||||
std::string CurrentDisplay;
|
||||
};
|
||||
|
||||
struct Result {
|
||||
int Error=0;
|
||||
std::string Reason;
|
||||
};
|
||||
|
||||
typedef std::vector<Parameter> Parameters;
|
||||
typedef std::vector<Parameters> ParametersVec;
|
||||
typedef std::function<bool(const Parameters &Parameters, Result &Result, bool &Retry)> WorkerFunction;
|
||||
typedef std::vector<Status> Statuses;
|
||||
|
||||
Job(std::string Title,
|
||||
std::string Description,
|
||||
std::string RegisteredName,
|
||||
ParametersVec Parameters,
|
||||
[[maybe_unused]] bool Parallel=true) :
|
||||
Title_(std::move(Title)),
|
||||
Description_(std::move(Description)),
|
||||
RegisteredName_(std::move(RegisteredName)),
|
||||
Parameters_(std::move(Parameters))
|
||||
{
|
||||
UUID_ = MicroService::instance().CreateUUID();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const Types::UUID_t & ID() const { return UUID_; }
|
||||
|
||||
private:
|
||||
Types::UUID_t UUID_;
|
||||
std::string Title_;
|
||||
std::string Description_;
|
||||
std::string RegisteredName_;
|
||||
ParametersVec Parameters_;
|
||||
};
|
||||
|
||||
class JobRegistry {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new JobRegistry;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
inline void RegisterJobType( const std::string & JobType, Job::WorkerFunction Function) {
|
||||
JobTypes_[JobType] = std::move(Function);
|
||||
}
|
||||
|
||||
inline bool Execute(const std::string &JobType, const Job::Parameters & Params, Job::Result &Result, bool & Retry) {
|
||||
auto Hint = JobTypes_.find(JobType);
|
||||
if(Hint != end(JobTypes_)) {
|
||||
Hint->second(Params, Result, Retry);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string,Job::WorkerFunction> JobTypes_;
|
||||
};
|
||||
|
||||
inline auto JobRegistry() { return JobRegistry::instance(); }
|
||||
|
||||
class JobController : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
static auto instance() {
|
||||
@@ -58,16 +112,11 @@ namespace OpenWifi {
|
||||
void run() override;
|
||||
inline void wakeup() { Thr_.wakeUp(); }
|
||||
|
||||
void AddJob( Job* newJob ) {
|
||||
std::lock_guard G(Mutex_);
|
||||
jobs_.push_back(newJob);
|
||||
}
|
||||
bool JobList(Job::Statuses & Statuses);
|
||||
|
||||
private:
|
||||
Poco::Thread Thr_;
|
||||
std::atomic_bool Running_=false;
|
||||
std::list<Job *> jobs_;
|
||||
Poco::ThreadPool Pool_;
|
||||
Poco::Thread Thr_;
|
||||
std::atomic_bool Running_=false;
|
||||
|
||||
JobController() noexcept:
|
||||
SubSystemServer("JobController", "JOB-SVR", "job")
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace OpenWifi {
|
||||
bool &Done, std::string &Answer) {
|
||||
Done = false;
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
Poco::toLowerInPlace(Prefix);
|
||||
Logger().information(Poco::format("serial_number_search: %s", Prefix));
|
||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||
std::vector<uint64_t> Numbers;
|
||||
@@ -84,7 +83,6 @@ namespace OpenWifi {
|
||||
Done = false;
|
||||
auto operatorId = O->get("operatorId").toString();
|
||||
auto Prefix = O->get("serial_prefix").toString();
|
||||
Poco::toLowerInPlace(Prefix);
|
||||
std::string Query;
|
||||
|
||||
if(Prefix[0]=='*') {
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/ConfigurationValidator.h"
|
||||
#include "sdks/SDK_sec.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include "libs/croncpp.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -408,9 +405,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) {
|
||||
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services",
|
||||
"unit", "definitions", "ethernet", "switch", "config-raw",
|
||||
"third-party" };
|
||||
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", "unit" };
|
||||
|
||||
for(const auto &i:Config.configuration) {
|
||||
Poco::JSON::Parser P;
|
||||
@@ -526,39 +521,12 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
return (ValidRRM(DR.rrm)) &&
|
||||
return (DR.rrm=="yes" || DR.rrm=="no" || DR.rrm=="inherit") &&
|
||||
(DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") &&
|
||||
(DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit");
|
||||
}
|
||||
|
||||
@@ -35,53 +35,36 @@ namespace OpenWifi{
|
||||
|
||||
void RESTAPI_inventory_handler::DoGet() {
|
||||
|
||||
ProvObjects::InventoryTag Existing;
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
Logger().debug(Poco::format("%s: Retrieving inventory information.", SerialNumber));
|
||||
if (SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) {
|
||||
ProvObjects::InventoryTag Existing;
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
|
||||
Logger().debug(Poco::format("%s: Retrieving inventory information.",SerialNumber));
|
||||
if(SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER,SerialNumber,Existing)) {
|
||||
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;
|
||||
if (HasParameter("config", Arg) && Arg == "true") {
|
||||
bool Explain = (HasParameter("explain", Arg) && Arg == "true");
|
||||
APConfig Device(SerialNumber, Existing.deviceType, Logger(), Explain);
|
||||
if(HasParameter("config",Arg) && Arg=="true") {
|
||||
bool Explain = (HasParameter("explain",Arg) && Arg == "true");
|
||||
APConfig Device(SerialNumber,Existing.deviceType,Logger(), Explain);
|
||||
|
||||
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
||||
if (Device.Get(Configuration)) {
|
||||
if(Device.Get(Configuration)) {
|
||||
Answer.set("config", Configuration);
|
||||
if (Explain)
|
||||
if(Explain)
|
||||
Answer.set("explanation", Device.Explanation());
|
||||
} else {
|
||||
Answer.set("config", "none");
|
||||
Answer.set("config","none");
|
||||
}
|
||||
return ReturnObject(Answer);
|
||||
} else if (GetBoolParameter("firmwareOptions", false)) {
|
||||
} else if(HasParameter("firmwareOptions", Arg) && Arg=="true") {
|
||||
ProvObjects::DeviceRules Rules;
|
||||
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules);
|
||||
Answer.set("firmwareUpgrade", Rules.firmwareUpgrade);
|
||||
Answer.set("firmwareRCOnly", Rules.rcOnly == "yes");
|
||||
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber,Rules);
|
||||
Answer.set("firmwareUpgrade",Rules.firmwareUpgrade);
|
||||
Answer.set("firmwareRCOnly", Rules.rcOnly == "yes" );
|
||||
return ReturnObject(Answer);
|
||||
} 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)) {
|
||||
} else if(HasParameter("applyConfiguration",Arg) && Arg=="true") {
|
||||
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>();
|
||||
@@ -108,19 +91,6 @@ namespace OpenWifi{
|
||||
}
|
||||
Results.to_json(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) {
|
||||
AddExtendedInfo(Existing,Answer);
|
||||
}
|
||||
@@ -166,7 +136,6 @@ namespace OpenWifi{
|
||||
|
||||
void RESTAPI_inventory_handler::DoPost() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
|
||||
Poco::toLowerInPlace(SerialNumber);
|
||||
if(SerialNumber.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace OpenWifi {
|
||||
{ "email", UserName },
|
||||
{ "signupUUID" , SignupUUID },
|
||||
{ "owner" , SignupOperator.info.id },
|
||||
{ "operatorName", SignupOperator.registrationId }
|
||||
|
||||
}, Body, 30000);
|
||||
|
||||
Poco::JSON::Object::Ptr Answer;
|
||||
|
||||
@@ -228,10 +228,10 @@ namespace OpenWifi{
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
SNL.serialNumbers = Existing.devices;
|
||||
auto JobId = MicroService::instance().CreateUUID();
|
||||
Types::StringVec Parameters{UUID};;
|
||||
auto NewJob = new VenueConfigUpdater(JobId,"VenueConfigurationUpdater", Parameters, 0, UserInfo_.userinfo, Logger());
|
||||
JobController()->AddJob(dynamic_cast<Job*>(NewJob));
|
||||
|
||||
auto Task = new VenueConfigUpdater(UUID,UserInfo_.userinfo,0,Logger());
|
||||
auto JobId = Task->Start();
|
||||
|
||||
SNL.to_json(Answer);
|
||||
Answer.set("jobId",JobId);
|
||||
return ReturnObject(Answer);
|
||||
@@ -242,10 +242,10 @@ namespace OpenWifi{
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
SNL.serialNumbers = Existing.devices;
|
||||
auto JobId = MicroService::instance().CreateUUID();
|
||||
Types::StringVec Parameters{UUID};;
|
||||
auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger());
|
||||
JobController()->AddJob(dynamic_cast<Job*>(NewJob));
|
||||
|
||||
auto Task = new VenueUpgrade(UUID,UserInfo_.userinfo,0,Logger());
|
||||
auto JobId = Task->Start();
|
||||
|
||||
SNL.to_json(Answer);
|
||||
Answer.set("jobId",JobId);
|
||||
return ReturnObject(Answer);
|
||||
@@ -256,10 +256,10 @@ namespace OpenWifi{
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
SNL.serialNumbers = Existing.devices;
|
||||
auto JobId = MicroService::instance().CreateUUID();
|
||||
Types::StringVec Parameters{UUID};;
|
||||
auto NewJob = new VenueRebooter(JobId,"VenueRebooter", Parameters, 0, UserInfo_.userinfo, Logger());
|
||||
JobController()->AddJob(dynamic_cast<Job*>(NewJob));
|
||||
|
||||
auto Task = new VenueRebooter(UUID,UserInfo_.userinfo,0,Logger());
|
||||
auto JobId = Task->Start();
|
||||
|
||||
SNL.to_json(Answer);
|
||||
Answer.set("jobId",JobId);
|
||||
return ReturnObject(Answer);
|
||||
|
||||
@@ -1159,40 +1159,5 @@ namespace OpenWifi::ProvObjects {
|
||||
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,21 +62,6 @@ namespace OpenWifi::ProvObjects {
|
||||
};
|
||||
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 {
|
||||
std::string rcOnly{"inherit"};
|
||||
std::string rrm{"inherit"};
|
||||
|
||||
@@ -42,7 +42,6 @@ namespace OpenWifi {
|
||||
|
||||
void Signup::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("signup-mgr");
|
||||
while(Running_) {
|
||||
Poco::Thread::trySleep(5000);
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void Storage::onTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("strg-janitor");
|
||||
}
|
||||
|
||||
void Storage::Stop() {
|
||||
@@ -195,24 +194,18 @@ namespace OpenWifi {
|
||||
// check that all inventory in venues and entities actually exists, if not, fix it.
|
||||
auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool {
|
||||
Types::UUIDvec_t NewDevices;
|
||||
bool modified=false;
|
||||
for(const auto &device:V.devices) {
|
||||
ProvObjects::InventoryTag T;
|
||||
if(InventoryDB().GetRecord("id", device, T)) {
|
||||
NewDevices.emplace_back(device);
|
||||
} else {
|
||||
modified=true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ProvObjects::Venue NewVenue = V;
|
||||
if(V.deviceRules.rrm=="yes") {
|
||||
NewVenue.deviceRules.rrm="inherit";
|
||||
modified=true;
|
||||
}
|
||||
|
||||
if(modified) {
|
||||
if(NewDevices!=V.devices) {
|
||||
Logger().warning(fmt::format(" fixing venue: {}", V.info.name));
|
||||
ProvObjects::Venue NewVenue = V;
|
||||
NewVenue.devices = NewDevices;
|
||||
VenueDB().UpdateRecord("id", V.info.id, NewVenue);
|
||||
}
|
||||
@@ -272,16 +265,10 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
ProvObjects::Entity NewEntity = E;
|
||||
|
||||
if(E.deviceRules.rrm=="yes") {
|
||||
NewEntity.deviceRules.rrm="inherit";
|
||||
Modified=true;
|
||||
}
|
||||
|
||||
if(Modified)
|
||||
{
|
||||
Logger().warning(fmt::format(" fixing entity: {}",E.info.name));
|
||||
ProvObjects::Entity NewEntity = E;
|
||||
NewEntity.devices = NewDevices;
|
||||
NewEntity.contacts = NewContacts;
|
||||
NewEntity.locations = NewLocations;
|
||||
@@ -292,103 +279,11 @@ namespace OpenWifi {
|
||||
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");
|
||||
VenueDB().Iterate(FixVenueDevices);
|
||||
Logger().information("Checking DB consistency: entities");
|
||||
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() {
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void TagServer::run() {
|
||||
Utils::SetThreadName("tag-server");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "APConfig.h"
|
||||
#include "sdks/SDK_gw.h"
|
||||
#include "framework/WebSocketClientNotifications.h"
|
||||
#include "JobController.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -20,6 +19,8 @@ namespace OpenWifi {
|
||||
auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>();
|
||||
auto Rejected = Status->getArray("rejected");
|
||||
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 (...) {
|
||||
}
|
||||
@@ -36,42 +37,35 @@ namespace OpenWifi {
|
||||
void run() final {
|
||||
ProvObjects::InventoryTag Device;
|
||||
started_=true;
|
||||
Utils::SetThreadName("venue-cfg");
|
||||
if(StorageService()->InventoryDB().GetRecord("id",uuid_,Device)) {
|
||||
SerialNumber = Device.serialNumber;
|
||||
// std::cout << "Starting push for " << Device.serialNumber << std::endl;
|
||||
Logger().debug(fmt::format("{}: Computing configuration.",Device.serialNumber));
|
||||
auto DeviceConfig = std::make_shared<APConfig>(Device.serialNumber, Device.deviceType, Logger(), false);
|
||||
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
||||
try {
|
||||
if (DeviceConfig->Get(Configuration)) {
|
||||
std::ostringstream OS;
|
||||
Configuration->stringify(OS);
|
||||
auto Response = Poco::makeShared<Poco::JSON::Object>();
|
||||
Logger().debug(fmt::format("{}: Pushing configuration.", Device.serialNumber));
|
||||
if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) {
|
||||
Logger().debug(fmt::format("{}: Configuration pushed.", Device.serialNumber));
|
||||
Logger().information(fmt::format("{}: Updated.", Device.serialNumber));
|
||||
// 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_++;
|
||||
}
|
||||
if (DeviceConfig->Get(Configuration)) {
|
||||
std::ostringstream OS;
|
||||
Configuration->stringify(OS);
|
||||
auto Response=Poco::makeShared<Poco::JSON::Object>();
|
||||
Logger().debug(fmt::format("{}: Pushing configuration.",Device.serialNumber));
|
||||
if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) {
|
||||
Logger().debug(fmt::format("{}: Configuration pushed.",Device.serialNumber));
|
||||
Logger().information(fmt::format("{}: Updated.", Device.serialNumber));
|
||||
// std::cout << Device.serialNumber << ": Updated" << std::endl;
|
||||
updated_++;
|
||||
} else {
|
||||
Logger().debug(fmt::format("{}: Configuration is bad.", Device.serialNumber));
|
||||
bad_config_++;
|
||||
// std::cout << Device.serialNumber << ": Bad config" << std::endl;
|
||||
Logger().information(fmt::format("{}: Not updated.", Device.serialNumber));
|
||||
// std::cout << Device.serialNumber << ": Failed" << std::endl;
|
||||
failed_++;
|
||||
}
|
||||
} catch (...) {
|
||||
Logger().debug(fmt::format("{}: Configuration is bad (caused an exception).", Device.serialNumber));
|
||||
} else {
|
||||
Logger().debug(fmt::format("{}: Configuration is bad.",Device.serialNumber));
|
||||
bad_config_++;
|
||||
// std::cout << Device.serialNumber << ": Bad config" << std::endl;
|
||||
}
|
||||
}
|
||||
done_ = true;
|
||||
// std::cout << "Done push for " << Device.serialNumber << std::endl;
|
||||
Utils::SetThreadName("free");
|
||||
}
|
||||
|
||||
uint64_t updated_=0, failed_=0, bad_config_=0;
|
||||
@@ -86,101 +80,133 @@ namespace OpenWifi {
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
|
||||
class VenueConfigUpdater: public Job {
|
||||
class VenueConfigUpdater: public Poco::Runnable {
|
||||
public:
|
||||
VenueConfigUpdater(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) :
|
||||
Job(JobID, name, parameters, when, UI, L) {
|
||||
explicit VenueConfigUpdater(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
|
||||
VenueUUID_(VenueUUID),
|
||||
UI_(UI),
|
||||
When_(When),
|
||||
Logger_(L)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline virtual void run() {
|
||||
std::string VenueUUID_;
|
||||
inline std::string Start() {
|
||||
JobId_ = MicroService::CreateUUID();
|
||||
Worker_.start(*this);
|
||||
return JobId_;
|
||||
}
|
||||
|
||||
Utils::SetThreadName("venue-update");
|
||||
VenueUUID_ = Parameter(0);
|
||||
private:
|
||||
std::string VenueUUID_;
|
||||
SecurityObjects::UserInfo UI_;
|
||||
uint64_t When_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Thread Worker_;
|
||||
std::string JobId_;
|
||||
Poco::ThreadPool Pool_{2,16,300};
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
inline void run() final {
|
||||
|
||||
if(When_ && When_>OpenWifi::Now())
|
||||
Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 );
|
||||
|
||||
WebSocketNotification<WebSocketNotificationJobContent> N;
|
||||
|
||||
Logger().information(fmt::format("Job {} Starting.", JobId_));
|
||||
|
||||
ProvObjects::Venue Venue;
|
||||
uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ;
|
||||
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.jobId = JobId();
|
||||
|
||||
Poco::ThreadPool Pool_;
|
||||
std::list<VenueDeviceConfigUpdater*> JobList;
|
||||
N.content.jobId = JobId_;
|
||||
|
||||
std::array<tState,MaxThreads> Tasks;
|
||||
|
||||
for(const auto &uuid:Venue.devices) {
|
||||
auto NewTask = new VenueDeviceConfigUpdater(uuid, Venue.info.name, Logger());
|
||||
bool TaskAdded=false;
|
||||
while(!TaskAdded) {
|
||||
if (Pool_.available()) {
|
||||
JobList.push_back(NewTask);
|
||||
Pool_.start(*NewTask);
|
||||
TaskAdded = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||
VenueDeviceConfigUpdater * current_job = *job_it;
|
||||
if(current_job!= nullptr && current_job->done_) {
|
||||
Updated += current_job->updated_;
|
||||
Failed += current_job->failed_;
|
||||
BadConfigs += current_job->bad_config_;
|
||||
if(current_job->updated_) {
|
||||
N.content.success.push_back(current_job->SerialNumber);
|
||||
} else if(current_job->failed_) {
|
||||
N.content.warning.push_back(current_job->SerialNumber);
|
||||
} else {
|
||||
N.content.error.push_back(current_job->SerialNumber);
|
||||
// std::cout << "Scheduling config push for " << uuid << std::endl;
|
||||
bool found_slot = false;
|
||||
while (!found_slot) {
|
||||
for (auto &cur_task: Tasks) {
|
||||
if (cur_task.task == nullptr) {
|
||||
cur_task.task = NewTask;
|
||||
cur_task.thr_.start(*NewTask);
|
||||
found_slot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's look for a slot...
|
||||
if (!found_slot) {
|
||||
for (auto &cur_task: Tasks) {
|
||||
if (cur_task.task != nullptr && cur_task.task->started_) {
|
||||
if (cur_task.thr_.isRunning())
|
||||
continue;
|
||||
if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
||||
cur_task.thr_.join();
|
||||
Updated += cur_task.task->updated_;
|
||||
Failed += cur_task.task->failed_;
|
||||
BadConfigs += cur_task.task->bad_config_;
|
||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
||||
delete cur_task.task;
|
||||
cur_task.task = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
job_it = JobList.erase(job_it);
|
||||
delete current_job;
|
||||
} else {
|
||||
++job_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger().debug("Waiting for outstanding update threads to finish.");
|
||||
Pool_.joinAll();
|
||||
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||
VenueDeviceConfigUpdater * current_job = *job_it;
|
||||
if(current_job!= nullptr && current_job->done_) {
|
||||
Updated += current_job->updated_;
|
||||
Failed += current_job->failed_;
|
||||
BadConfigs += current_job->bad_config_;
|
||||
if(current_job->updated_) {
|
||||
N.content.success.push_back(current_job->SerialNumber);
|
||||
} else if(current_job->failed_) {
|
||||
N.content.warning.push_back(current_job->SerialNumber);
|
||||
} else {
|
||||
N.content.error.push_back(current_job->SerialNumber);
|
||||
bool stillTasksRunning=true;
|
||||
while(stillTasksRunning) {
|
||||
stillTasksRunning = false;
|
||||
for(auto &cur_task:Tasks) {
|
||||
if(cur_task.task!= nullptr && cur_task.task->started_) {
|
||||
if(cur_task.thr_.isRunning()) {
|
||||
stillTasksRunning = true;
|
||||
continue;
|
||||
}
|
||||
if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
||||
cur_task.thr_.join();
|
||||
if(cur_task.task->updated_) {
|
||||
Updated++;
|
||||
N.content.success.push_back(cur_task.task->SerialNumber);
|
||||
} else if(cur_task.task->failed_) {
|
||||
Failed++;
|
||||
N.content.warning.push_back(cur_task.task->SerialNumber);
|
||||
} else {
|
||||
BadConfigs++;
|
||||
N.content.error.push_back(cur_task.task->SerialNumber);
|
||||
}
|
||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
||||
delete cur_task.task;
|
||||
cur_task.task = nullptr;
|
||||
}
|
||||
}
|
||||
job_it = JobList.erase(job_it);
|
||||
delete current_job;
|
||||
} else {
|
||||
++job_it;
|
||||
}
|
||||
}
|
||||
|
||||
N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ",
|
||||
JobId(), Updated ,Failed, BadConfigs);
|
||||
JobId_, Updated ,Failed, BadConfigs);
|
||||
|
||||
} else {
|
||||
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
|
||||
Logger().warning(N.content.details);
|
||||
}
|
||||
|
||||
// std::cout << N.content.details << std::endl;
|
||||
WebSocketClientNotificationVenueUpdateJobCompletionToUser(UserInfo().email, N);
|
||||
WebSocketClientNotificationVenueUpdateJobCompletionToUser(UI_.email, N);
|
||||
Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.",
|
||||
JobId(), Updated ,Failed, BadConfigs));
|
||||
Utils::SetThreadName("free");
|
||||
Complete();
|
||||
JobId_, Updated ,Failed, BadConfigs));
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include "StorageService.h"
|
||||
#include "APConfig.h"
|
||||
#include "sdks/SDK_gw.h"
|
||||
#include "JobController.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -49,90 +48,129 @@ namespace OpenWifi {
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
|
||||
class VenueRebooter: public Job {
|
||||
class VenueRebooter: public Poco::Runnable {
|
||||
public:
|
||||
VenueRebooter(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) :
|
||||
Job(JobID, name, parameters, when, UI, L) {
|
||||
explicit VenueRebooter(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
|
||||
VenueUUID_(VenueUUID),
|
||||
UI_(UI),
|
||||
When_(When),
|
||||
Logger_(L)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline virtual void run() final {
|
||||
inline std::string Start() {
|
||||
JobId_ = MicroService::CreateUUID();
|
||||
Worker_.start(*this);
|
||||
return JobId_;
|
||||
}
|
||||
|
||||
Utils::SetThreadName("venue-reboot");
|
||||
private:
|
||||
std::string VenueUUID_;
|
||||
SecurityObjects::UserInfo UI_;
|
||||
uint64_t When_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Thread Worker_;
|
||||
std::string JobId_;
|
||||
Poco::ThreadPool Pool_{2,16,300};
|
||||
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
inline void run() final {
|
||||
|
||||
if(When_ && When_>OpenWifi::Now())
|
||||
Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 );
|
||||
|
||||
WebSocketClientNotificationVenueRebootList_t N;
|
||||
auto VenueUUID_ = Parameter(0);
|
||||
|
||||
Logger().information(fmt::format("Job {} Starting.", JobId_));
|
||||
|
||||
ProvObjects::Venue Venue;
|
||||
uint64_t rebooted_ = 0, failed_ = 0;
|
||||
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.jobId = JobId();
|
||||
N.content.jobId = JobId_;
|
||||
|
||||
Poco::ThreadPool Pool_;
|
||||
std::list<VenueDeviceRebooter*> JobList;
|
||||
std::array<tState,MaxThreads> Tasks;
|
||||
|
||||
for(const auto &uuid:Venue.devices) {
|
||||
auto NewTask = new VenueDeviceRebooter(uuid, Venue.info.name, Logger());
|
||||
bool TaskAdded=false;
|
||||
while(!TaskAdded) {
|
||||
if (Pool_.available()) {
|
||||
JobList.push_back(NewTask);
|
||||
Pool_.start(*NewTask);
|
||||
TaskAdded = true;
|
||||
continue;
|
||||
// std::cout << "Scheduling config push for " << uuid << std::endl;
|
||||
bool found_slot = false;
|
||||
while (!found_slot) {
|
||||
for (auto &cur_task: Tasks) {
|
||||
if (cur_task.task == nullptr) {
|
||||
cur_task.task = NewTask;
|
||||
cur_task.thr_.start(*NewTask);
|
||||
found_slot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||
VenueDeviceRebooter * current_job = *job_it;
|
||||
if(current_job!= nullptr && current_job->done_) {
|
||||
if(current_job->rebooted_)
|
||||
N.content.success.push_back(current_job->SerialNumber);
|
||||
else
|
||||
N.content.warning.push_back(current_job->SerialNumber);
|
||||
rebooted_ += current_job->rebooted_;
|
||||
failed_ += current_job->failed_;
|
||||
job_it = JobList.erase(job_it);
|
||||
delete current_job;
|
||||
} else {
|
||||
++job_it;
|
||||
// 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();
|
||||
rebooted_ += cur_task.task->rebooted_;
|
||||
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.");
|
||||
Pool_.joinAll();
|
||||
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||
VenueDeviceRebooter * current_job = *job_it;
|
||||
if(current_job!= nullptr && current_job->done_) {
|
||||
if(current_job->rebooted_)
|
||||
N.content.success.push_back(current_job->SerialNumber);
|
||||
else
|
||||
N.content.warning.push_back(current_job->SerialNumber);
|
||||
rebooted_ += current_job->rebooted_;
|
||||
failed_ += current_job->failed_;
|
||||
job_it = JobList.erase(job_it);
|
||||
delete current_job;
|
||||
} else {
|
||||
++job_it;
|
||||
bool stillTasksRunning=true;
|
||||
while(stillTasksRunning) {
|
||||
stillTasksRunning = false;
|
||||
for(auto &cur_task:Tasks) {
|
||||
if(cur_task.task!= nullptr && cur_task.task->started_) {
|
||||
if(cur_task.thr_.isRunning()) {
|
||||
stillTasksRunning = true;
|
||||
continue;
|
||||
}
|
||||
if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
||||
cur_task.thr_.join();
|
||||
if(cur_task.task->rebooted_) {
|
||||
rebooted_++;
|
||||
N.content.success.push_back(cur_task.task->SerialNumber);
|
||||
} else if(cur_task.task->failed_) {
|
||||
failed_++;
|
||||
N.content.warning.push_back(cur_task.task->SerialNumber);
|
||||
}
|
||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
||||
delete cur_task.task;
|
||||
cur_task.task = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.",
|
||||
JobId(), rebooted_ ,failed_);
|
||||
JobId_, rebooted_ ,failed_);
|
||||
|
||||
} else {
|
||||
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
|
||||
Logger().warning(N.content.details);
|
||||
}
|
||||
|
||||
// std::cout << N.content.details << std::endl;
|
||||
WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N);
|
||||
WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N);
|
||||
Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.",
|
||||
JobId(), rebooted_ ,failed_));
|
||||
Utils::SetThreadName("free");
|
||||
Complete();
|
||||
JobId_, rebooted_ ,failed_));
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "APConfig.h"
|
||||
#include "sdks/SDK_gw.h"
|
||||
#include "sdks/SDK_fms.h"
|
||||
#include "JobController.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class VenueDeviceUpgrade : public Poco::Runnable {
|
||||
@@ -31,7 +30,7 @@ namespace OpenWifi {
|
||||
|
||||
Storage::ApplyRules(rules_,Device.deviceRules);
|
||||
if(Device.deviceRules.firmwareUpgrade=="no") {
|
||||
poco_debug(Logger(),fmt::format("Skipped Upgrade: {}", Device.serialNumber));
|
||||
std::cout << "Skipped Upgrade:" << Device.serialNumber << std::endl;
|
||||
skipped_++;
|
||||
done_=true;
|
||||
return;
|
||||
@@ -40,25 +39,24 @@ namespace OpenWifi {
|
||||
FMSObjects::Firmware F;
|
||||
if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) {
|
||||
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));
|
||||
upgraded_++;
|
||||
} else {
|
||||
std::cout << "Did not Upgrade:" << Device.serialNumber << " to " << F.uri << std::endl;
|
||||
Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber));
|
||||
not_connected_++;
|
||||
failed_++;
|
||||
}
|
||||
} else {
|
||||
Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber));
|
||||
no_firmware_++;
|
||||
std::cout << "Did not Upgrade:" << Device.serialNumber << " to <unknown>" << std::endl;
|
||||
failed_++;
|
||||
}
|
||||
}
|
||||
done_ = true;
|
||||
// std::cout << "Done push for " << Device.serialNumber << std::endl;
|
||||
}
|
||||
|
||||
std::uint64_t upgraded_ = 0,
|
||||
not_connected_ = 0,
|
||||
skipped_ = 0,
|
||||
no_firmware_ = 0;
|
||||
uint64_t upgraded_=0, failed_=0, skipped_=0;
|
||||
bool started_ = false,
|
||||
done_ = false;
|
||||
std::string SerialNumber;
|
||||
@@ -71,111 +69,132 @@ namespace OpenWifi {
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
};
|
||||
|
||||
class VenueUpgrade: public Job {
|
||||
class VenueUpgrade: public Poco::Runnable {
|
||||
public:
|
||||
VenueUpgrade(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) :
|
||||
Job(JobID, name, parameters, when, UI, L) {
|
||||
explicit VenueUpgrade(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) :
|
||||
VenueUUID_(VenueUUID),
|
||||
UI_(UI),
|
||||
When_(When),
|
||||
Logger_(L)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
inline virtual void run() final {
|
||||
inline std::string Start() {
|
||||
JobId_ = MicroService::CreateUUID();
|
||||
Worker_.start(*this);
|
||||
return JobId_;
|
||||
}
|
||||
|
||||
Utils::SetThreadName("venue-upgr");
|
||||
auto VenueUUID_ = Parameter(0);
|
||||
private:
|
||||
std::string VenueUUID_;
|
||||
SecurityObjects::UserInfo UI_;
|
||||
uint64_t When_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Thread Worker_;
|
||||
std::string JobId_;
|
||||
Poco::ThreadPool Pool_{2,16,300};
|
||||
|
||||
WebSocketClientNotificationVenueUpgradeList_t N;
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
inline void run() final {
|
||||
|
||||
if(When_ && When_>OpenWifi::Now())
|
||||
Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 );
|
||||
|
||||
WebSocketClientNotificationVenueRebootList_t N;
|
||||
|
||||
Logger().information(fmt::format("Job {} Starting.", JobId_));
|
||||
|
||||
ProvObjects::Venue Venue;
|
||||
uint64_t upgraded_ = 0,
|
||||
not_connected_ = 0,
|
||||
skipped_ = 0,
|
||||
no_firmware_ = 0;
|
||||
uint64_t upgraded_ = 0, failed_ = 0;
|
||||
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.jobId = JobId();
|
||||
N.content.jobId = JobId_;
|
||||
|
||||
Poco::ThreadPool Pool_;
|
||||
std::list<VenueDeviceUpgrade*> JobList;
|
||||
ProvObjects::DeviceRules Rules;
|
||||
std::array<tState,MaxThreads> Tasks;
|
||||
ProvObjects::DeviceRules Rules;
|
||||
|
||||
StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules);
|
||||
|
||||
for(const auto &uuid:Venue.devices) {
|
||||
auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules, Logger());
|
||||
bool TaskAdded = false;
|
||||
while (!TaskAdded) {
|
||||
if (Pool_.available()) {
|
||||
JobList.push_back(NewTask);
|
||||
Pool_.start(*NewTask);
|
||||
TaskAdded = true;
|
||||
continue;
|
||||
auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules,Logger());
|
||||
// std::cout << "Scheduling config push for " << uuid << std::endl;
|
||||
bool found_slot = false;
|
||||
while (!found_slot) {
|
||||
for (auto &cur_task: Tasks) {
|
||||
if (cur_task.task == nullptr) {
|
||||
cur_task.task = NewTask;
|
||||
cur_task.thr_.start(*NewTask);
|
||||
found_slot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's look for a slot...
|
||||
if (!found_slot) {
|
||||
for (auto &cur_task: Tasks) {
|
||||
if (cur_task.task != nullptr && cur_task.task->started_) {
|
||||
if (cur_task.thr_.isRunning())
|
||||
continue;
|
||||
if (!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
||||
cur_task.thr_.join();
|
||||
upgraded_ += cur_task.task->upgraded_;
|
||||
failed_ += cur_task.task->failed_;
|
||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
||||
delete cur_task.task;
|
||||
cur_task.task = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto job_it = JobList.begin(); job_it != JobList.end();) {
|
||||
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;
|
||||
}
|
||||
Logger().debug("Waiting for outstanding update threads to finish.");
|
||||
bool stillTasksRunning=true;
|
||||
while(stillTasksRunning) {
|
||||
stillTasksRunning = false;
|
||||
for(auto &cur_task:Tasks) {
|
||||
if(cur_task.task!= nullptr && cur_task.task->started_) {
|
||||
if(cur_task.thr_.isRunning()) {
|
||||
stillTasksRunning = true;
|
||||
continue;
|
||||
}
|
||||
if(!cur_task.thr_.isRunning() && cur_task.task->done_) {
|
||||
cur_task.thr_.join();
|
||||
if(cur_task.task->upgraded_) {
|
||||
upgraded_++;
|
||||
N.content.success.push_back(cur_task.task->SerialNumber);
|
||||
} else if(cur_task.task->failed_) {
|
||||
failed_++;
|
||||
N.content.warning.push_back(cur_task.task->SerialNumber);
|
||||
}
|
||||
cur_task.task->started_ = cur_task.task->done_ = false;
|
||||
delete cur_task.task;
|
||||
cur_task.task = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger().debug("Waiting for outstanding upgrade threads to finish.");
|
||||
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, {} failed to upgrade.",
|
||||
JobId_, upgraded_ ,failed_);
|
||||
|
||||
N.content.details = fmt::format("Job {} Completed: {} upgraded, {} not connected, {} skipped, {} no firmware.",
|
||||
JobId(),
|
||||
upgraded_ ,
|
||||
not_connected_,
|
||||
skipped_,
|
||||
no_firmware_);
|
||||
} else {
|
||||
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
|
||||
Logger().warning(N.content.details);
|
||||
}
|
||||
|
||||
// std::cout << N.content.details << std::endl;
|
||||
WebSocketClientNotificationVenueUpgradeCompletionToUser(UserInfo().email,N);
|
||||
Logger().information(N.content.details);
|
||||
Utils::SetThreadName("free");
|
||||
Complete();
|
||||
WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N);
|
||||
Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
|
||||
JobId_, upgraded_ ,failed_));
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string GitUCentralJSONSchemaFile{
|
||||
"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"};
|
||||
"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"};
|
||||
|
||||
static json DefaultUCentralSchema = R"(
|
||||
|
||||
|
||||
@@ -27,11 +27,6 @@ namespace OpenWifi {
|
||||
inline uint64_t Now() { return std::time(nullptr); };
|
||||
}
|
||||
|
||||
namespace OpenWifi::Utils {
|
||||
std::vector<unsigned char> base64decode(const std::string& input);
|
||||
std::string base64encode(const unsigned char *input, uint32_t size);
|
||||
}
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#include "Poco/Util/Application.h"
|
||||
@@ -243,11 +238,6 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
Obj.set(Field,Value);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) {
|
||||
auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size());
|
||||
Obj.set(Field,Result);
|
||||
}
|
||||
|
||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
|
||||
Poco::JSON::Array Array;
|
||||
for(const auto &i:S) {
|
||||
@@ -344,12 +334,12 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||
Value = (double)Obj->get(Field);
|
||||
Value = (double) Obj->get(Field);
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||
Value = (float)Obj->get(Field);
|
||||
Value = (float) Obj->get(Field);
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
|
||||
@@ -384,14 +374,7 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
|
||||
if(Obj->has(Field) && !Obj->isNull(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());
|
||||
}
|
||||
Value = (uint64_t ) Obj->get(Field);
|
||||
}
|
||||
|
||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
|
||||
@@ -660,27 +643,6 @@ namespace OpenWifi::RESTAPI_utils {
|
||||
|
||||
namespace OpenWifi::Utils {
|
||||
|
||||
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 {
|
||||
PLAIN,
|
||||
BINARY,
|
||||
@@ -703,19 +665,6 @@ namespace OpenWifi::Utils {
|
||||
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0);
|
||||
}
|
||||
|
||||
template <typename ...Args> std::string ComputeHash(Args&&... args) {
|
||||
Poco::SHA2Engine E;
|
||||
auto as_string = [](auto p) {
|
||||
if constexpr(std::is_arithmetic_v<decltype(p)>) {
|
||||
return std::to_string(p);
|
||||
} else {
|
||||
return p;
|
||||
}
|
||||
};
|
||||
(E.update(as_string(args)),...);
|
||||
return Poco::SHA2Engine::digestToHex(E.digest());
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) {
|
||||
std::vector<std::string> ReturnList;
|
||||
|
||||
@@ -1367,7 +1316,7 @@ namespace OpenWifi {
|
||||
inline void Start();
|
||||
inline void Stop();
|
||||
private:
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread Thread_;
|
||||
};
|
||||
|
||||
@@ -1412,14 +1361,13 @@ namespace OpenWifi {
|
||||
|
||||
[[nodiscard]] inline const std::string &Address() const { return address_; };
|
||||
[[nodiscard]] inline uint32_t Port() const { return port_; };
|
||||
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
|
||||
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
|
||||
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
|
||||
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
|
||||
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
|
||||
[[nodiscard]] inline auto Name() const { return name_; };
|
||||
[[nodiscard]] inline const std::string &KeyFile() const { return key_file_; };
|
||||
[[nodiscard]] inline const std::string &CertFile() const { return cert_file_; };
|
||||
[[nodiscard]] inline const std::string &RootCA() const { return root_ca_; };
|
||||
[[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; };
|
||||
[[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; };
|
||||
[[nodiscard]] inline const std::string &Name() const { return name_; };
|
||||
[[nodiscard]] inline int Backlog() const { return backlog_; }
|
||||
[[nodiscard]] inline auto Cas() const { return cas_; }
|
||||
|
||||
[[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const {
|
||||
Poco::Net::Context::Params P;
|
||||
@@ -1899,8 +1847,7 @@ namespace OpenWifi {
|
||||
Request = &RequestIn;
|
||||
Response = &ResponseIn;
|
||||
|
||||
// std::string th_name = "restsvr_" + std::to_string(TransactionId_);
|
||||
// Utils::SetThreadName(th_name.c_str());
|
||||
Poco::Thread::current()->setName("WebServerThread_" + std::to_string(TransactionId_));
|
||||
|
||||
if(Request->getContentLength()>0) {
|
||||
if(Request->getContentType().find("application/json")!=std::string::npos) {
|
||||
@@ -2095,17 +2042,6 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) {
|
||||
if(O->has(Field)) {
|
||||
std::string Content = O->get(Field).toString();
|
||||
auto DecodedBlob = Utils::base64decode(Content);
|
||||
Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
|
||||
if(O->has(Field)) {
|
||||
assignee = value;
|
||||
@@ -2446,7 +2382,6 @@ namespace OpenWifi {
|
||||
Poco::Net::HTTPServerResponse *Response= nullptr;
|
||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||
QueryBlock QB_;
|
||||
const std::string & Requester() const { return REST_Requester_; }
|
||||
protected:
|
||||
BindingMap Bindings_;
|
||||
Poco::URI::QueryParameters Parameters_;
|
||||
@@ -2463,7 +2398,6 @@ namespace OpenWifi {
|
||||
RateLimit MyRates_;
|
||||
uint64_t TransactionId_;
|
||||
Poco::JSON::Object::Ptr ParsedBody_;
|
||||
std::string REST_Requester_;
|
||||
};
|
||||
|
||||
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
||||
@@ -2645,7 +2579,7 @@ namespace OpenWifi {
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
std::atomic_bool Running_=false;
|
||||
Poco::NotificationQueue Queue_;
|
||||
};
|
||||
|
||||
@@ -2671,7 +2605,7 @@ namespace OpenWifi {
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
std::atomic_bool Running_=false;
|
||||
};
|
||||
|
||||
class KafkaDispatcher : public Poco::Runnable {
|
||||
@@ -2728,7 +2662,6 @@ namespace OpenWifi {
|
||||
|
||||
inline void run() override {
|
||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||
Utils::SetThreadName("kafka:dispatch");
|
||||
while(Note && Running_) {
|
||||
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
|
||||
if(Msg!= nullptr) {
|
||||
@@ -2751,12 +2684,12 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
uint64_t FunctionId_=1;
|
||||
Poco::NotificationQueue Queue_;
|
||||
std::recursive_mutex Mutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
std::atomic_bool Running_=false;
|
||||
uint64_t FunctionId_=1;
|
||||
Poco::NotificationQueue Queue_;
|
||||
};
|
||||
|
||||
class KafkaManager : public SubSystemServer {
|
||||
@@ -2949,7 +2882,6 @@ namespace OpenWifi {
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override
|
||||
{
|
||||
Utils::SetThreadName("alb-request");
|
||||
try {
|
||||
if((id_ % 100) == 0) {
|
||||
Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.",
|
||||
@@ -3018,7 +2950,7 @@ namespace OpenWifi {
|
||||
std::unique_ptr<Poco::Net::HTTPServer> Server_;
|
||||
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
|
||||
int Port_ = 0;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
std::atomic_bool Running_=false;
|
||||
};
|
||||
|
||||
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
|
||||
@@ -3038,7 +2970,7 @@ namespace OpenWifi {
|
||||
}
|
||||
int Start() override;
|
||||
inline void Stop() override {
|
||||
Logger().information("Stopping...");
|
||||
Logger().information("Stopping ");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stop();
|
||||
Pool_.stopAll();
|
||||
@@ -3046,23 +2978,22 @@ namespace OpenWifi {
|
||||
RESTServers_.clear();
|
||||
}
|
||||
|
||||
|
||||
inline void reinitialize(Poco::Util::Application &self) override;
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
|
||||
Poco::Thread::current()->setName(fmt::format("RESTAPI_ExtServer_{}",Id));
|
||||
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
|
||||
}
|
||||
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_{"x-rest",2,32};
|
||||
Poco::ThreadPool Pool_;
|
||||
RESTAPI_GenericServer Server_;
|
||||
|
||||
RESTAPI_ExtServer() noexcept:
|
||||
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
|
||||
SubSystemServer("RESTAPI_ExtServer", "RESTAPIServer", "openwifi.restapi"),
|
||||
Pool_("RESTAPI_ExtServer",4,50,120)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -3075,7 +3006,7 @@ namespace OpenWifi {
|
||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
||||
try {
|
||||
Poco::URI uri(Request.getURI());
|
||||
Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str());
|
||||
Poco::Thread::current()->setName(fmt::format("ExtWebServer_{}",TransactionId_));
|
||||
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
|
||||
} catch (...) {
|
||||
|
||||
@@ -3173,7 +3104,7 @@ namespace OpenWifi {
|
||||
|
||||
inline int Start() override;
|
||||
inline void Stop() override {
|
||||
Logger().information("Stopping...");
|
||||
Logger().information("Stopping ");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stop();
|
||||
Pool_.stopAll();
|
||||
@@ -3184,18 +3115,17 @@ namespace OpenWifi {
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
|
||||
Poco::Thread::current()->setName(fmt::format("RESTAPI_IntServer_{}",Id));
|
||||
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
|
||||
}
|
||||
|
||||
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_{"i-rest",2,16};
|
||||
Poco::ThreadPool Pool_;
|
||||
RESTAPI_GenericServer Server_;
|
||||
|
||||
RESTAPI_IntServer() noexcept:
|
||||
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi")
|
||||
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi"),
|
||||
Pool_("RESTAPI_IntServer",4,50,120)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -3206,7 +3136,6 @@ namespace OpenWifi {
|
||||
public:
|
||||
inline IntRequestHandlerFactory() = default;
|
||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
||||
Utils::SetThreadName(fmt::format("i-rest:{}",TransactionId_).c_str());
|
||||
Poco::URI uri(Request.getURI());
|
||||
return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_);
|
||||
}
|
||||
@@ -3250,6 +3179,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string Version() { return Version_; }
|
||||
// [[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
|
||||
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
|
||||
[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; }
|
||||
[[nodiscard]] bool Debug() const { return DebugMode_; }
|
||||
@@ -3282,12 +3212,7 @@ namespace OpenWifi {
|
||||
return Poco::Logger::get(Name);
|
||||
}
|
||||
|
||||
virtual void GetExtraConfiguration(Poco::JSON::Object & Cfg) {
|
||||
Cfg.set("additionalConfiguration",false);
|
||||
}
|
||||
|
||||
|
||||
static inline void Exit(int Reason);
|
||||
static inline void Exit(int Reason);
|
||||
inline void BusMessageReceived(const std::string &Key, const std::string & Payload);
|
||||
inline MicroServiceMetaVec GetServices(const std::string & Type);
|
||||
inline MicroServiceMetaVec GetServices();
|
||||
@@ -3323,6 +3248,7 @@ namespace OpenWifi {
|
||||
inline std::string ConfigPath(const std::string &Key);
|
||||
inline std::string Encrypt(const std::string &S);
|
||||
inline std::string Decrypt(const std::string &S);
|
||||
inline std::string CreateHash(const std::string &S);
|
||||
inline std::string MakeSystemEventMessage( const std::string & Type ) const;
|
||||
[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
|
||||
inline static void SavePID();
|
||||
@@ -3352,9 +3278,6 @@ namespace OpenWifi {
|
||||
return Signer_.sign(T,Algo);
|
||||
}
|
||||
}
|
||||
|
||||
inline Poco::ThreadPool & TimerPool() { return TimerPool_; }
|
||||
|
||||
private:
|
||||
static MicroService * instance_;
|
||||
bool HelpRequested_ = false;
|
||||
@@ -3368,6 +3291,7 @@ namespace OpenWifi {
|
||||
std::string WWWAssetsDir_;
|
||||
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
|
||||
Poco::Crypto::Cipher * Cipher_ = nullptr;
|
||||
Poco::SHA2Engine SHA2_;
|
||||
MicroServiceMetaMap Services_;
|
||||
std::string MyHash_;
|
||||
std::string MyPrivateEndPoint_;
|
||||
@@ -3388,7 +3312,6 @@ namespace OpenWifi {
|
||||
bool NoBuiltInCrypto_=false;
|
||||
Poco::JWT::Signer Signer_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::ThreadPool TimerPool_{"timer:pool",2,16};
|
||||
};
|
||||
|
||||
inline void MicroService::Exit(int Reason) {
|
||||
@@ -3538,7 +3461,7 @@ namespace OpenWifi {
|
||||
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
|
||||
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
|
||||
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
|
||||
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
|
||||
MyHash_ = CreateHash(MyPublicEndPoint_);
|
||||
}
|
||||
|
||||
void MicroServicePostInitialization();
|
||||
@@ -3601,7 +3524,7 @@ namespace OpenWifi {
|
||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||
|
||||
inline void MicroService::initialize(Poco::Util::Application &self) {
|
||||
// add the default services
|
||||
// add the default services
|
||||
LoadConfigurationFile();
|
||||
InitializeLoggingSystem();
|
||||
|
||||
@@ -3875,6 +3798,11 @@ namespace OpenWifi {
|
||||
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
||||
}
|
||||
|
||||
inline std::string MicroService::CreateHash(const std::string &S) {
|
||||
SHA2_.update(S);
|
||||
return Utils::ToHex(SHA2_.digest());
|
||||
}
|
||||
|
||||
inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
||||
Poco::JSON::Object Obj;
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
|
||||
@@ -3937,7 +3865,6 @@ namespace OpenWifi {
|
||||
Params->setMaxThreads(50);
|
||||
Params->setMaxQueued(200);
|
||||
Params->setKeepAlive(true);
|
||||
Params->setName("ws:xrest");
|
||||
|
||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
@@ -3974,7 +3901,6 @@ namespace OpenWifi {
|
||||
Params->setMaxThreads(50);
|
||||
Params->setMaxQueued(200);
|
||||
Params->setKeepAlive(true);
|
||||
Params->setName("ws:irest");
|
||||
|
||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||
if(MicroService::instance().NoAPISecurity()) {
|
||||
@@ -3992,6 +3918,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline int MicroService::main([[maybe_unused]] const ArgVec &args) {
|
||||
|
||||
MyErrorHandler ErrorHandler(*this);
|
||||
Poco::ErrorHandler::set(&ErrorHandler);
|
||||
|
||||
@@ -4098,7 +4025,6 @@ namespace OpenWifi {
|
||||
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
|
||||
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setName("ws:alb");
|
||||
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
|
||||
Server_->start();
|
||||
}
|
||||
@@ -4108,7 +4034,6 @@ namespace OpenWifi {
|
||||
|
||||
inline void BusEventManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false);
|
||||
while(Running_) {
|
||||
@@ -4194,8 +4119,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline void KafkaProducer::run() {
|
||||
|
||||
Utils::SetThreadName("Kafka:Prod");
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
||||
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
|
||||
@@ -4234,8 +4157,6 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
inline void KafkaConsumer::run() {
|
||||
Utils::SetThreadName("Kafka:Cons");
|
||||
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
||||
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") },
|
||||
@@ -4374,11 +4295,6 @@ namespace OpenWifi {
|
||||
Answer.set("certificates", Certificates);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
if(GetBoolParameter("extraConfiguration")) {
|
||||
Poco::JSON::Object Answer;
|
||||
MicroService::instance().GetExtraConfiguration(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||
}
|
||||
|
||||
@@ -4751,7 +4667,6 @@ namespace OpenWifi {
|
||||
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
|
||||
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
|
||||
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
|
||||
Contacted = true;
|
||||
if(!Allowed) {
|
||||
if(Server_.LogBadTokens(false)) {
|
||||
Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}",
|
||||
@@ -4760,7 +4675,6 @@ namespace OpenWifi {
|
||||
}
|
||||
} else {
|
||||
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
|
||||
REST_Requester_ = Id;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()), Id,
|
||||
@@ -4784,7 +4698,6 @@ namespace OpenWifi {
|
||||
#else
|
||||
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) {
|
||||
#endif
|
||||
REST_Requester_ = UserInfo_.userinfo.email;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}",
|
||||
UserInfo_.userinfo.email,
|
||||
@@ -4867,7 +4780,7 @@ namespace OpenWifi {
|
||||
void run() override;
|
||||
// MyParallelSocketReactor &ReactorPool();
|
||||
Poco::Net::SocketReactor & Reactor() { return Reactor_; }
|
||||
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName);
|
||||
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id);
|
||||
bool Register(WebSocketClient *Client, const std::string &Id);
|
||||
void SetProcessor(WebSocketClientProcessor *F);
|
||||
void UnRegister(const std::string &Id);
|
||||
@@ -4902,8 +4815,8 @@ namespace OpenWifi {
|
||||
[[nodiscard]] bool SendToUser(const std::string &userName, const std::string &Payload);
|
||||
void SendToAll(const std::string &Payload);
|
||||
private:
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
Poco::Thread Thr_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread Thr_;
|
||||
// std::unique_ptr<MyParallelSocketReactor> ReactorPool_;
|
||||
Poco::Net::SocketReactor Reactor_;
|
||||
Poco::Thread ReactorThread_;
|
||||
@@ -4918,22 +4831,18 @@ namespace OpenWifi {
|
||||
|
||||
class WebSocketClient {
|
||||
public:
|
||||
explicit WebSocketClient(Poco::Net::WebSocket &WS,
|
||||
const std::string &Id,
|
||||
const std::string &UserName,
|
||||
Poco::Logger &L,
|
||||
WebSocketClientProcessor *Processor);
|
||||
explicit WebSocketClient(Poco::Net::WebSocket &WS, const std::string &Id, Poco::Logger &L,
|
||||
WebSocketClientProcessor *Processor);
|
||||
virtual ~WebSocketClient();
|
||||
[[nodiscard]] inline const std::string &Id();
|
||||
[[nodiscard]] Poco::Logger &Logger();
|
||||
inline bool Send(const std::string &Payload);
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::string Id_;
|
||||
std::string UserName_;
|
||||
Poco::Logger &Logger_;
|
||||
std::atomic_bool Authenticated_ = false;
|
||||
Poco::Net::SocketReactor &Reactor_;
|
||||
std::string Id_;
|
||||
Poco::Logger &Logger_;
|
||||
bool Authenticated_ = false;
|
||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||
WebSocketClientProcessor *Processor_ = nullptr;
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||
@@ -4941,9 +4850,33 @@ namespace OpenWifi {
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
||||
};
|
||||
|
||||
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) {
|
||||
/* inline MyParallelSocketReactor::MyParallelSocketReactor(uint32_t NumReactors) :
|
||||
NumReactors_(NumReactors)
|
||||
{
|
||||
Reactors_ = new Poco::Net::SocketReactor[NumReactors_];
|
||||
for(uint32_t i=0;i<NumReactors_;i++) {
|
||||
ReactorPool_.start(Reactors_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
inline MyParallelSocketReactor::~MyParallelSocketReactor() {
|
||||
for(uint32_t i=0;i<NumReactors_;i++) {
|
||||
Reactors_[i].stop();
|
||||
}
|
||||
ReactorPool_.stopAll();
|
||||
ReactorPool_.joinAll();
|
||||
delete [] Reactors_;
|
||||
}
|
||||
|
||||
inline Poco::Net::SocketReactor & MyParallelSocketReactor::Reactor() {
|
||||
return Reactors_[ rand() % NumReactors_ ];
|
||||
}
|
||||
|
||||
// inline MyParallelSocketReactor & WebSocketClientServer::ReactorPool() { return *ReactorPool_; }
|
||||
*/
|
||||
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto Client = new WebSocketClient(WS,Id,UserName,Logger(), Processor_);
|
||||
auto Client = new WebSocketClient(WS,Id,Logger(), Processor_);
|
||||
Clients_[Id] = std::make_pair(Client,"");
|
||||
}
|
||||
|
||||
@@ -4973,13 +4906,12 @@ namespace OpenWifi {
|
||||
|
||||
[[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload);
|
||||
inline WebSocketClientServer::WebSocketClientServer() noexcept:
|
||||
SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients")
|
||||
SubSystemServer("WebSocketClientServer", "WSCLNT-SVR", "websocketclients")
|
||||
{
|
||||
}
|
||||
|
||||
inline void WebSocketClientServer::run() {
|
||||
Running_ = true ;
|
||||
Utils::SetThreadName("ws:uiclnt-svr");
|
||||
while(Running_) {
|
||||
Poco::Thread::trySleep(2000);
|
||||
|
||||
@@ -5027,12 +4959,8 @@ namespace OpenWifi {
|
||||
|
||||
for(const auto &client:Clients_) {
|
||||
if(client.second.second == UserName) {
|
||||
try {
|
||||
if (client.second.first->Send(Payload))
|
||||
Sent++;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
if(client.second.first->Send(Payload))
|
||||
Sent++;
|
||||
}
|
||||
}
|
||||
return Sent>0;
|
||||
@@ -5054,73 +4982,70 @@ namespace OpenWifi {
|
||||
int flags;
|
||||
int n;
|
||||
bool Done=false;
|
||||
try {
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
n = WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
n = WS_->receiveFrame(IncomingFrame, flags);
|
||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
if (n == 0) {
|
||||
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||
return delete this;
|
||||
}
|
||||
if(n==0) {
|
||||
return delete this;
|
||||
}
|
||||
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||
Done = true;
|
||||
} break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
IncomingFrame.append(0);
|
||||
if (!Authenticated_) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
auto Tokens = Utils::Split(Frame, ':');
|
||||
bool Expired = false, Contacted = false;
|
||||
if (Tokens.size() == 2 &&
|
||||
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||
Authenticated_ = true;
|
||||
UserName_ = UserInfo_.userinfo.email;
|
||||
Logger().warning(Poco::format("START(%s): %s UI Client is starting WS connection.", Id_, UserName_));
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
WS_->sendFrame(S.c_str(), S.size());
|
||||
WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email);
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
WS_->sendFrame(S.c_str(), S.size());
|
||||
Done = true;
|
||||
}
|
||||
switch(Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.",Id_));
|
||||
Done=true;
|
||||
}
|
||||
break;
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
IncomingFrame.append(0);
|
||||
if(!Authenticated_) {
|
||||
std::string Frame{IncomingFrame.begin()};
|
||||
auto Tokens = Utils::Split(Frame,':');
|
||||
bool Expired = false, Contacted = false;
|
||||
if(Tokens.size()==2 && AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||
Authenticated_=true;
|
||||
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||
WS_->sendFrame(S.c_str(),S.size());
|
||||
WebSocketClientServer()->SetUser(Id_,UserInfo_.userinfo.email);
|
||||
} else {
|
||||
std::string S{"Invalid token. Closing connection."};
|
||||
WS_->sendFrame(S.c_str(),S.size());
|
||||
Done=true;
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj =
|
||||
P.parse(IncomingFrame.begin()).extract<Poco::JSON::Object::Ptr>();
|
||||
std::string Answer;
|
||||
if (Processor_ != nullptr)
|
||||
Processor_->Processor(Obj, Answer, Done);
|
||||
if (!Answer.empty())
|
||||
WS_->sendFrame(Answer.c_str(), (int)Answer.size());
|
||||
else {
|
||||
WS_->sendFrame("{}", 2);
|
||||
}
|
||||
} catch (const Poco::JSON::JSONException &E) {
|
||||
Logger().log(E);
|
||||
Done=true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
Done=true;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Obj = P.parse(IncomingFrame.begin())
|
||||
.extract<Poco::JSON::Object::Ptr>();
|
||||
std::string Answer;
|
||||
if(Processor_!= nullptr)
|
||||
Processor_->Processor(Obj, Answer, Done);
|
||||
if (!Answer.empty())
|
||||
WS_->sendFrame(Answer.c_str(), (int) Answer.size());
|
||||
else {
|
||||
WS_->sendFrame("{}", 2);
|
||||
}
|
||||
} catch (const Poco::JSON::JSONException & E) {
|
||||
Logger().log(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(Done) {
|
||||
delete this;
|
||||
@@ -5132,10 +5057,9 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
|
||||
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, const std::string &UserName, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
||||
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
||||
Reactor_(WebSocketClientServer()->Reactor()),
|
||||
Id_(Id),
|
||||
UserName_(UserName),
|
||||
Logger_(L),
|
||||
Processor_(Processor) {
|
||||
try {
|
||||
@@ -5215,8 +5139,9 @@ namespace OpenWifi {
|
||||
try
|
||||
{
|
||||
Poco::Net::WebSocket WS(*Request, *Response);
|
||||
Logger().information("WebSocket connection established.");
|
||||
auto Id = MicroService::CreateUUID();
|
||||
WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email);
|
||||
WebSocketClientServer()->NewClient(WS,Id);
|
||||
}
|
||||
catch (...) {
|
||||
std::cout << "Cannot create websocket client..." << std::endl;
|
||||
|
||||
@@ -146,10 +146,6 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationRebootList {
|
||||
std::string title,
|
||||
details,
|
||||
@@ -193,58 +189,5 @@ namespace OpenWifi {
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
/////
|
||||
/////
|
||||
/////
|
||||
|
||||
struct WebSocketNotificationUpgradeList {
|
||||
std::string title,
|
||||
details,
|
||||
jobId;
|
||||
std::vector<std::string> success,
|
||||
skipped,
|
||||
no_firmware,
|
||||
not_connected;
|
||||
uint64_t timeStamp=OpenWifi::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t;
|
||||
|
||||
inline void WebSocketNotificationUpgradeList::to_json(Poco::JSON::Object &Obj) const {
|
||||
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_to_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_to_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||
}
|
||||
|
||||
inline bool WebSocketNotificationUpgradeList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||
RESTAPI_utils::field_from_json(Obj,"notConnected",not_connected);
|
||||
RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware);
|
||||
RESTAPI_utils::field_from_json(Obj,"skipped",skipped);
|
||||
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) {
|
||||
N.type = "venue_upgrader";
|
||||
WebSocketClientServer()->SendUserNotification(User,N);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
|
||||
@@ -133,37 +133,6 @@ namespace ORM {
|
||||
return R;
|
||||
}
|
||||
|
||||
inline std::string WHERE_AND_(std::string Result) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) {
|
||||
if constexpr(std::is_same_v<T,std::string>)
|
||||
{
|
||||
if(!Value.empty()) {
|
||||
if(!Result.empty())
|
||||
Result += " and ";
|
||||
Result += fieldName;
|
||||
Result += '=';
|
||||
Result += "'";
|
||||
Result += Escape(Value);
|
||||
Result += "'";
|
||||
}
|
||||
} else {
|
||||
if(!Result.empty())
|
||||
Result += " and ";
|
||||
Result += fieldName ;
|
||||
Result += '=';
|
||||
Result += std::to_string(Value);
|
||||
}
|
||||
return WHERE_AND_(Result,args...);
|
||||
}
|
||||
|
||||
template <typename... Args> std::string WHERE_AND(Args... args) {
|
||||
std::string Result;
|
||||
return WHERE_AND_(Result, args...);
|
||||
}
|
||||
|
||||
enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE };
|
||||
enum SqlBinaryOp { AND = 0 , OR };
|
||||
|
||||
|
||||
@@ -1,937 +0,0 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Marius Bancila
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
This file is from https://github.com/mariusbancila/croncpp.git.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <bitset>
|
||||
#include <cctype>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
#include <string_view>
|
||||
#define CRONCPP_IS_CPP17
|
||||
#endif
|
||||
|
||||
namespace cron
|
||||
{
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
#define CRONCPP_STRING_VIEW std::string_view
|
||||
#define CRONCPP_STRING_VIEW_NPOS std::string_view::npos
|
||||
#define CRONCPP_CONSTEXPTR constexpr
|
||||
#else
|
||||
#define CRONCPP_STRING_VIEW std::string const &
|
||||
#define CRONCPP_STRING_VIEW_NPOS std::string::npos
|
||||
#define CRONCPP_CONSTEXPTR
|
||||
#endif
|
||||
|
||||
using cron_int = uint8_t;
|
||||
|
||||
constexpr std::time_t INVALID_TIME = static_cast<std::time_t>(-1);
|
||||
|
||||
constexpr size_t INVALID_INDEX = static_cast<size_t>(-1);
|
||||
|
||||
class cronexpr;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
enum class cron_field
|
||||
{
|
||||
second,
|
||||
minute,
|
||||
hour_of_day,
|
||||
day_of_week,
|
||||
day_of_month,
|
||||
month,
|
||||
year
|
||||
};
|
||||
|
||||
template <typename Traits>
|
||||
static bool find_next(cronexpr const & cex,
|
||||
std::tm& date,
|
||||
size_t const dot);
|
||||
}
|
||||
|
||||
struct bad_cronexpr : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit bad_cronexpr(CRONCPP_STRING_VIEW message) :
|
||||
std::runtime_error(message.data())
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
struct cron_standard_traits
|
||||
{
|
||||
static const cron_int CRON_MIN_SECONDS = 0;
|
||||
static const cron_int CRON_MAX_SECONDS = 59;
|
||||
|
||||
static const cron_int CRON_MIN_MINUTES = 0;
|
||||
static const cron_int CRON_MAX_MINUTES = 59;
|
||||
|
||||
static const cron_int CRON_MIN_HOURS = 0;
|
||||
static const cron_int CRON_MAX_HOURS = 23;
|
||||
|
||||
static const cron_int CRON_MIN_DAYS_OF_WEEK = 0;
|
||||
static const cron_int CRON_MAX_DAYS_OF_WEEK = 6;
|
||||
|
||||
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
|
||||
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
|
||||
|
||||
static const cron_int CRON_MIN_MONTHS = 1;
|
||||
static const cron_int CRON_MAX_MONTHS = 12;
|
||||
|
||||
static const cron_int CRON_MAX_YEARS_DIFF = 4;
|
||||
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
static const inline std::vector<std::string> DAYS = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
#else
|
||||
static std::vector<std::string>& DAYS()
|
||||
{
|
||||
static std::vector<std::string> days = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
return days;
|
||||
}
|
||||
|
||||
static std::vector<std::string>& MONTHS()
|
||||
{
|
||||
static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
return months;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct cron_oracle_traits
|
||||
{
|
||||
static const cron_int CRON_MIN_SECONDS = 0;
|
||||
static const cron_int CRON_MAX_SECONDS = 59;
|
||||
|
||||
static const cron_int CRON_MIN_MINUTES = 0;
|
||||
static const cron_int CRON_MAX_MINUTES = 59;
|
||||
|
||||
static const cron_int CRON_MIN_HOURS = 0;
|
||||
static const cron_int CRON_MAX_HOURS = 23;
|
||||
|
||||
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
|
||||
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
|
||||
|
||||
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
|
||||
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
|
||||
|
||||
static const cron_int CRON_MIN_MONTHS = 0;
|
||||
static const cron_int CRON_MAX_MONTHS = 11;
|
||||
|
||||
static const cron_int CRON_MAX_YEARS_DIFF = 4;
|
||||
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
static const inline std::vector<std::string> MONTHS = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
#else
|
||||
|
||||
static std::vector<std::string>& DAYS()
|
||||
{
|
||||
static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
return days;
|
||||
}
|
||||
|
||||
static std::vector<std::string>& MONTHS()
|
||||
{
|
||||
static std::vector<std::string> months = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
return months;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
struct cron_quartz_traits
|
||||
{
|
||||
static const cron_int CRON_MIN_SECONDS = 0;
|
||||
static const cron_int CRON_MAX_SECONDS = 59;
|
||||
|
||||
static const cron_int CRON_MIN_MINUTES = 0;
|
||||
static const cron_int CRON_MAX_MINUTES = 59;
|
||||
|
||||
static const cron_int CRON_MIN_HOURS = 0;
|
||||
static const cron_int CRON_MAX_HOURS = 23;
|
||||
|
||||
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
|
||||
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
|
||||
|
||||
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
|
||||
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
|
||||
|
||||
static const cron_int CRON_MIN_MONTHS = 1;
|
||||
static const cron_int CRON_MAX_MONTHS = 12;
|
||||
|
||||
static const cron_int CRON_MAX_YEARS_DIFF = 4;
|
||||
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
#else
|
||||
static std::vector<std::string>& DAYS()
|
||||
{
|
||||
static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||
return days;
|
||||
}
|
||||
|
||||
static std::vector<std::string>& MONTHS()
|
||||
{
|
||||
static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||
return months;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class cronexpr;
|
||||
|
||||
template <typename Traits = cron_standard_traits>
|
||||
static cronexpr make_cron(CRONCPP_STRING_VIEW expr);
|
||||
|
||||
class cronexpr
|
||||
{
|
||||
std::bitset<60> seconds;
|
||||
std::bitset<60> minutes;
|
||||
std::bitset<24> hours;
|
||||
std::bitset<7> days_of_week;
|
||||
std::bitset<31> days_of_month;
|
||||
std::bitset<12> months;
|
||||
std::string expr;
|
||||
|
||||
friend bool operator==(cronexpr const & e1, cronexpr const & e2);
|
||||
friend bool operator!=(cronexpr const & e1, cronexpr const & e2);
|
||||
|
||||
template <typename Traits>
|
||||
friend bool detail::find_next(cronexpr const & cex,
|
||||
std::tm& date,
|
||||
size_t const dot);
|
||||
|
||||
friend std::string to_cronstr(cronexpr const& cex);
|
||||
friend std::string to_string(cronexpr const & cex);
|
||||
|
||||
template <typename Traits>
|
||||
friend cronexpr make_cron(CRONCPP_STRING_VIEW expr);
|
||||
};
|
||||
|
||||
inline bool operator==(cronexpr const & e1, cronexpr const & e2)
|
||||
{
|
||||
return
|
||||
e1.seconds == e2.seconds &&
|
||||
e1.minutes == e2.minutes &&
|
||||
e1.hours == e2.hours &&
|
||||
e1.days_of_week == e2.days_of_week &&
|
||||
e1.days_of_month == e2.days_of_month &&
|
||||
e1.months == e2.months;
|
||||
}
|
||||
|
||||
inline bool operator!=(cronexpr const & e1, cronexpr const & e2)
|
||||
{
|
||||
return !(e1 == e2);
|
||||
}
|
||||
|
||||
inline std::string to_string(cronexpr const & cex)
|
||||
{
|
||||
return
|
||||
cex.seconds.to_string() + " " +
|
||||
cex.minutes.to_string() + " " +
|
||||
cex.hours.to_string() + " " +
|
||||
cex.days_of_month.to_string() + " " +
|
||||
cex.months.to_string() + " " +
|
||||
cex.days_of_week.to_string();
|
||||
}
|
||||
|
||||
inline std::string to_cronstr(cronexpr const& cex)
|
||||
{
|
||||
return cex.expr;
|
||||
}
|
||||
|
||||
namespace utils
|
||||
{
|
||||
inline std::time_t tm_to_time(std::tm& date)
|
||||
{
|
||||
return std::mktime(&date);
|
||||
}
|
||||
|
||||
inline std::tm* time_to_tm(std::time_t const * date, std::tm* const out)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
errno_t err = localtime_s(out, date);
|
||||
return 0 == err ? out : nullptr;
|
||||
#else
|
||||
return localtime_r(date, out);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::tm to_tm(CRONCPP_STRING_VIEW time)
|
||||
{
|
||||
std::tm result;
|
||||
#if __cplusplus > 201103L
|
||||
std::istringstream str(time.data());
|
||||
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||
|
||||
str >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
|
||||
if (str.fail()) throw std::runtime_error("Parsing date failed!");
|
||||
#else
|
||||
int year = 1900;
|
||||
int month = 1;
|
||||
int day = 1;
|
||||
int hour = 0;
|
||||
int minute = 0;
|
||||
int second = 0;
|
||||
sscanf(time.data(), "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
|
||||
result.tm_year = year - 1900;
|
||||
result.tm_mon = month - 1;
|
||||
result.tm_mday = day;
|
||||
result.tm_hour = hour;
|
||||
result.tm_min = minute;
|
||||
result.tm_sec = second;
|
||||
#endif
|
||||
result.tm_isdst = -1; // DST info not available
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string to_string(std::tm const & tm)
|
||||
{
|
||||
#if __cplusplus > 201103L
|
||||
std::ostringstream str;
|
||||
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||
str << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
|
||||
if (str.fail()) throw std::runtime_error("Writing date failed!");
|
||||
|
||||
return str.str();
|
||||
#else
|
||||
char buff[70] = {0};
|
||||
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm);
|
||||
return std::string(buff);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::string to_upper(std::string text)
|
||||
{
|
||||
std::transform(std::begin(text), std::end(text),
|
||||
std::begin(text), [](char const c) { return static_cast<char>(std::toupper(c)); });
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static std::vector<std::string> split(CRONCPP_STRING_VIEW text, char const delimiter)
|
||||
{
|
||||
std::vector<std::string> tokens;
|
||||
std::string token;
|
||||
std::istringstream tokenStream(text.data());
|
||||
while (std::getline(tokenStream, token, delimiter))
|
||||
{
|
||||
tokens.push_back(token);
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
CRONCPP_CONSTEXPTR inline bool contains(CRONCPP_STRING_VIEW text, char const ch) noexcept
|
||||
{
|
||||
return CRONCPP_STRING_VIEW_NPOS != text.find_first_of(ch);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline cron_int to_cron_int(CRONCPP_STRING_VIEW text)
|
||||
{
|
||||
try
|
||||
{
|
||||
return static_cast<cron_int>(std::stoul(text.data()));
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
throw bad_cronexpr(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
static std::string replace_ordinals(
|
||||
std::string text,
|
||||
std::vector<std::string> const & replacement)
|
||||
{
|
||||
for (size_t i = 0; i < replacement.size(); ++i)
|
||||
{
|
||||
auto pos = text.find(replacement[i]);
|
||||
if (std::string::npos != pos)
|
||||
text.replace(pos, 3 ,std::to_string(i));
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static std::pair<cron_int, cron_int> make_range(
|
||||
CRONCPP_STRING_VIEW field,
|
||||
cron_int const minval,
|
||||
cron_int const maxval)
|
||||
{
|
||||
cron_int first = 0;
|
||||
cron_int last = 0;
|
||||
if (field.size() == 1 && field[0] == '*')
|
||||
{
|
||||
first = minval;
|
||||
last = maxval;
|
||||
}
|
||||
else if (!utils::contains(field, '-'))
|
||||
{
|
||||
first = to_cron_int(field);
|
||||
last = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto parts = utils::split(field, '-');
|
||||
if (parts.size() != 2)
|
||||
throw bad_cronexpr("Specified range requires two fields");
|
||||
|
||||
first = to_cron_int(parts[0]);
|
||||
last = to_cron_int(parts[1]);
|
||||
}
|
||||
|
||||
if (first > maxval || last > maxval)
|
||||
{
|
||||
throw bad_cronexpr("Specified range exceeds maximum");
|
||||
}
|
||||
if (first < minval || last < minval)
|
||||
{
|
||||
throw bad_cronexpr("Specified range is less than minimum");
|
||||
}
|
||||
if (first > last)
|
||||
{
|
||||
throw bad_cronexpr("Specified range start exceeds range end");
|
||||
}
|
||||
|
||||
return { first, last };
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
static void set_cron_field(
|
||||
CRONCPP_STRING_VIEW value,
|
||||
std::bitset<N>& target,
|
||||
cron_int const minval,
|
||||
cron_int const maxval)
|
||||
{
|
||||
if(value.length() > 0 && value[value.length()-1] == ',')
|
||||
throw bad_cronexpr("Value cannot end with comma");
|
||||
|
||||
auto fields = utils::split(value, ',');
|
||||
if (fields.empty())
|
||||
throw bad_cronexpr("Expression parsing error");
|
||||
|
||||
for (auto const & field : fields)
|
||||
{
|
||||
if (!utils::contains(field, '/'))
|
||||
{
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
auto[first, last] = detail::make_range(field, minval, maxval);
|
||||
#else
|
||||
auto range = detail::make_range(field, minval, maxval);
|
||||
auto first = range.first;
|
||||
auto last = range.second;
|
||||
#endif
|
||||
for (cron_int i = first - minval; i <= last - minval; ++i)
|
||||
{
|
||||
target.set(i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto parts = utils::split(field, '/');
|
||||
if (parts.size() != 2)
|
||||
throw bad_cronexpr("Incrementer must have two fields");
|
||||
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
auto[first, last] = detail::make_range(parts[0], minval, maxval);
|
||||
#else
|
||||
auto range = detail::make_range(parts[0], minval, maxval);
|
||||
auto first = range.first;
|
||||
auto last = range.second;
|
||||
#endif
|
||||
|
||||
if (!utils::contains(parts[0], '-'))
|
||||
{
|
||||
last = maxval;
|
||||
}
|
||||
|
||||
auto delta = detail::to_cron_int(parts[1]);
|
||||
if(delta <= 0)
|
||||
throw bad_cronexpr("Incrementer must be a positive value");
|
||||
|
||||
for (cron_int i = first - minval; i <= last - minval; i += delta)
|
||||
{
|
||||
target.set(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
static void set_cron_days_of_week(
|
||||
std::string value,
|
||||
std::bitset<7>& target)
|
||||
{
|
||||
auto days = utils::to_upper(value);
|
||||
auto days_replaced = detail::replace_ordinals(
|
||||
days,
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
Traits::DAYS
|
||||
#else
|
||||
Traits::DAYS()
|
||||
#endif
|
||||
);
|
||||
|
||||
if (days_replaced.size() == 1 && days_replaced[0] == '?')
|
||||
days_replaced[0] = '*';
|
||||
|
||||
set_cron_field(
|
||||
days_replaced,
|
||||
target,
|
||||
Traits::CRON_MIN_DAYS_OF_WEEK,
|
||||
Traits::CRON_MAX_DAYS_OF_WEEK);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
static void set_cron_days_of_month(
|
||||
std::string value,
|
||||
std::bitset<31>& target)
|
||||
{
|
||||
if (value.size() == 1 && value[0] == '?')
|
||||
value[0] = '*';
|
||||
|
||||
set_cron_field(
|
||||
value,
|
||||
target,
|
||||
Traits::CRON_MIN_DAYS_OF_MONTH,
|
||||
Traits::CRON_MAX_DAYS_OF_MONTH);
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
static void set_cron_month(
|
||||
std::string value,
|
||||
std::bitset<12>& target)
|
||||
{
|
||||
auto month = utils::to_upper(value);
|
||||
auto month_replaced = replace_ordinals(
|
||||
month,
|
||||
#ifdef CRONCPP_IS_CPP17
|
||||
Traits::MONTHS
|
||||
#else
|
||||
Traits::MONTHS()
|
||||
#endif
|
||||
);
|
||||
|
||||
set_cron_field(
|
||||
month_replaced,
|
||||
target,
|
||||
Traits::CRON_MIN_MONTHS,
|
||||
Traits::CRON_MAX_MONTHS);
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
inline size_t next_set_bit(
|
||||
std::bitset<N> const & target,
|
||||
size_t /*minimum*/,
|
||||
size_t /*maximum*/,
|
||||
size_t offset)
|
||||
{
|
||||
for (auto i = offset; i < N; ++i)
|
||||
{
|
||||
if (target.test(i)) return i;
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
inline void add_to_field(
|
||||
std::tm& date,
|
||||
cron_field const field,
|
||||
int const val)
|
||||
{
|
||||
switch (field)
|
||||
{
|
||||
case cron_field::second:
|
||||
date.tm_sec += val;
|
||||
break;
|
||||
case cron_field::minute:
|
||||
date.tm_min += val;
|
||||
break;
|
||||
case cron_field::hour_of_day:
|
||||
date.tm_hour += val;
|
||||
break;
|
||||
case cron_field::day_of_week:
|
||||
case cron_field::day_of_month:
|
||||
date.tm_mday += val;
|
||||
break;
|
||||
case cron_field::month:
|
||||
date.tm_mon += val;
|
||||
break;
|
||||
case cron_field::year:
|
||||
date.tm_year += val;
|
||||
break;
|
||||
}
|
||||
|
||||
if (INVALID_TIME == utils::tm_to_time(date))
|
||||
throw bad_cronexpr("Invalid time expression");
|
||||
}
|
||||
|
||||
inline void set_field(
|
||||
std::tm& date,
|
||||
cron_field const field,
|
||||
int const val)
|
||||
{
|
||||
switch (field)
|
||||
{
|
||||
case cron_field::second:
|
||||
date.tm_sec = val;
|
||||
break;
|
||||
case cron_field::minute:
|
||||
date.tm_min = val;
|
||||
break;
|
||||
case cron_field::hour_of_day:
|
||||
date.tm_hour = val;
|
||||
break;
|
||||
case cron_field::day_of_week:
|
||||
date.tm_wday = val;
|
||||
break;
|
||||
case cron_field::day_of_month:
|
||||
date.tm_mday = val;
|
||||
break;
|
||||
case cron_field::month:
|
||||
date.tm_mon = val;
|
||||
break;
|
||||
case cron_field::year:
|
||||
date.tm_year = val;
|
||||
break;
|
||||
}
|
||||
|
||||
if (INVALID_TIME == utils::tm_to_time(date))
|
||||
throw bad_cronexpr("Invalid time expression");
|
||||
}
|
||||
|
||||
inline void reset_field(
|
||||
std::tm& date,
|
||||
cron_field const field)
|
||||
{
|
||||
switch (field)
|
||||
{
|
||||
case cron_field::second:
|
||||
date.tm_sec = 0;
|
||||
break;
|
||||
case cron_field::minute:
|
||||
date.tm_min = 0;
|
||||
break;
|
||||
case cron_field::hour_of_day:
|
||||
date.tm_hour = 0;
|
||||
break;
|
||||
case cron_field::day_of_week:
|
||||
date.tm_wday = 0;
|
||||
break;
|
||||
case cron_field::day_of_month:
|
||||
date.tm_mday = 1;
|
||||
break;
|
||||
case cron_field::month:
|
||||
date.tm_mon = 0;
|
||||
break;
|
||||
case cron_field::year:
|
||||
date.tm_year = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (INVALID_TIME == utils::tm_to_time(date))
|
||||
throw bad_cronexpr("Invalid time expression");
|
||||
}
|
||||
|
||||
inline void reset_all_fields(
|
||||
std::tm& date,
|
||||
std::bitset<7> const & marked_fields)
|
||||
{
|
||||
for (size_t i = 0; i < marked_fields.size(); ++i)
|
||||
{
|
||||
if (marked_fields.test(i))
|
||||
reset_field(date, static_cast<cron_field>(i));
|
||||
}
|
||||
}
|
||||
|
||||
inline void mark_field(
|
||||
std::bitset<7> & orders,
|
||||
cron_field const field)
|
||||
{
|
||||
if (!orders.test(static_cast<size_t>(field)))
|
||||
orders.set(static_cast<size_t>(field));
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
static size_t find_next(
|
||||
std::bitset<N> const & target,
|
||||
std::tm& date,
|
||||
unsigned int const minimum,
|
||||
unsigned int const maximum,
|
||||
unsigned int const value,
|
||||
cron_field const field,
|
||||
cron_field const next_field,
|
||||
std::bitset<7> const & marked_fields)
|
||||
{
|
||||
auto next_value = next_set_bit(target, minimum, maximum, value);
|
||||
if (INVALID_INDEX == next_value)
|
||||
{
|
||||
add_to_field(date, next_field, 1);
|
||||
reset_field(date, field);
|
||||
next_value = next_set_bit(target, minimum, maximum, 0);
|
||||
}
|
||||
|
||||
if (INVALID_INDEX == next_value || next_value != value)
|
||||
{
|
||||
set_field(date, field, static_cast<int>(next_value));
|
||||
reset_all_fields(date, marked_fields);
|
||||
}
|
||||
|
||||
return next_value;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
static size_t find_next_day(
|
||||
std::tm& date,
|
||||
std::bitset<31> const & days_of_month,
|
||||
size_t day_of_month,
|
||||
std::bitset<7> const & days_of_week,
|
||||
size_t day_of_week,
|
||||
std::bitset<7> const & marked_fields)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
unsigned int maximum = 366;
|
||||
while (
|
||||
(!days_of_month.test(day_of_month - Traits::CRON_MIN_DAYS_OF_MONTH) ||
|
||||
!days_of_week.test(day_of_week - Traits::CRON_MIN_DAYS_OF_WEEK))
|
||||
&& count++ < maximum)
|
||||
{
|
||||
add_to_field(date, cron_field::day_of_month, 1);
|
||||
|
||||
day_of_month = date.tm_mday;
|
||||
day_of_week = date.tm_wday;
|
||||
|
||||
reset_all_fields(date, marked_fields);
|
||||
}
|
||||
|
||||
return day_of_month;
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
static bool find_next(cronexpr const & cex,
|
||||
std::tm& date,
|
||||
size_t const dot)
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
std::bitset<7> marked_fields{ 0 };
|
||||
std::bitset<7> empty_list{ 0 };
|
||||
|
||||
unsigned int second = date.tm_sec;
|
||||
auto updated_second = find_next(
|
||||
cex.seconds,
|
||||
date,
|
||||
Traits::CRON_MIN_SECONDS,
|
||||
Traits::CRON_MAX_SECONDS,
|
||||
second,
|
||||
cron_field::second,
|
||||
cron_field::minute,
|
||||
empty_list);
|
||||
|
||||
if (second == updated_second)
|
||||
{
|
||||
mark_field(marked_fields, cron_field::second);
|
||||
}
|
||||
|
||||
unsigned int minute = date.tm_min;
|
||||
auto update_minute = find_next(
|
||||
cex.minutes,
|
||||
date,
|
||||
Traits::CRON_MIN_MINUTES,
|
||||
Traits::CRON_MAX_MINUTES,
|
||||
minute,
|
||||
cron_field::minute,
|
||||
cron_field::hour_of_day,
|
||||
marked_fields);
|
||||
if (minute == update_minute)
|
||||
{
|
||||
mark_field(marked_fields, cron_field::minute);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = find_next<Traits>(cex, date, dot);
|
||||
if (!res) return res;
|
||||
}
|
||||
|
||||
unsigned int hour = date.tm_hour;
|
||||
auto updated_hour = find_next(
|
||||
cex.hours,
|
||||
date,
|
||||
Traits::CRON_MIN_HOURS,
|
||||
Traits::CRON_MAX_HOURS,
|
||||
hour,
|
||||
cron_field::hour_of_day,
|
||||
cron_field::day_of_week,
|
||||
marked_fields);
|
||||
if (hour == updated_hour)
|
||||
{
|
||||
mark_field(marked_fields, cron_field::hour_of_day);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = find_next<Traits>(cex, date, dot);
|
||||
if (!res) return res;
|
||||
}
|
||||
|
||||
unsigned int day_of_week = date.tm_wday;
|
||||
unsigned int day_of_month = date.tm_mday;
|
||||
auto updated_day_of_month = find_next_day<Traits>(
|
||||
date,
|
||||
cex.days_of_month,
|
||||
day_of_month,
|
||||
cex.days_of_week,
|
||||
day_of_week,
|
||||
marked_fields);
|
||||
if (day_of_month == updated_day_of_month)
|
||||
{
|
||||
mark_field(marked_fields, cron_field::day_of_month);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = find_next<Traits>(cex, date, dot);
|
||||
if (!res) return res;
|
||||
}
|
||||
|
||||
unsigned int month = date.tm_mon;
|
||||
auto updated_month = find_next(
|
||||
cex.months,
|
||||
date,
|
||||
Traits::CRON_MIN_MONTHS,
|
||||
Traits::CRON_MAX_MONTHS,
|
||||
month,
|
||||
cron_field::month,
|
||||
cron_field::year,
|
||||
marked_fields);
|
||||
if (month != updated_month)
|
||||
{
|
||||
if (date.tm_year - dot > Traits::CRON_MAX_YEARS_DIFF)
|
||||
return false;
|
||||
|
||||
res = find_next<Traits>(cex, date, dot);
|
||||
if (!res) return res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Traits>
|
||||
static cronexpr make_cron(CRONCPP_STRING_VIEW expr)
|
||||
{
|
||||
cronexpr cex;
|
||||
|
||||
if (expr.empty())
|
||||
throw bad_cronexpr("Invalid empty cron expression");
|
||||
|
||||
auto fields = utils::split(expr, ' ');
|
||||
fields.erase(
|
||||
std::remove_if(std::begin(fields), std::end(fields),
|
||||
[](CRONCPP_STRING_VIEW s) {return s.empty(); }),
|
||||
std::end(fields));
|
||||
if (fields.size() != 6)
|
||||
throw bad_cronexpr("cron expression must have six fields");
|
||||
|
||||
detail::set_cron_field(fields[0], cex.seconds, Traits::CRON_MIN_SECONDS, Traits::CRON_MAX_SECONDS);
|
||||
detail::set_cron_field(fields[1], cex.minutes, Traits::CRON_MIN_MINUTES, Traits::CRON_MAX_MINUTES);
|
||||
detail::set_cron_field(fields[2], cex.hours, Traits::CRON_MIN_HOURS, Traits::CRON_MAX_HOURS);
|
||||
|
||||
detail::set_cron_days_of_week<Traits>(fields[5], cex.days_of_week);
|
||||
|
||||
detail::set_cron_days_of_month<Traits>(fields[3], cex.days_of_month);
|
||||
|
||||
detail::set_cron_month<Traits>(fields[4], cex.months);
|
||||
|
||||
cex.expr = expr;
|
||||
|
||||
return cex;
|
||||
}
|
||||
|
||||
template <typename Traits = cron_standard_traits>
|
||||
static std::tm cron_next(cronexpr const & cex, std::tm date)
|
||||
{
|
||||
time_t original = utils::tm_to_time(date);
|
||||
if (INVALID_TIME == original) return {};
|
||||
|
||||
if (!detail::find_next<Traits>(cex, date, date.tm_year))
|
||||
return {};
|
||||
|
||||
time_t calculated = utils::tm_to_time(date);
|
||||
if (INVALID_TIME == calculated) return {};
|
||||
|
||||
if (calculated == original)
|
||||
{
|
||||
add_to_field(date, detail::cron_field::second, 1);
|
||||
if (!detail::find_next<Traits>(cex, date, date.tm_year))
|
||||
return {};
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
template <typename Traits = cron_standard_traits>
|
||||
static std::time_t cron_next(cronexpr const & cex, std::time_t const & date)
|
||||
{
|
||||
std::tm val;
|
||||
std::tm* dt = utils::time_to_tm(&date, &val);
|
||||
if (dt == nullptr) return INVALID_TIME;
|
||||
|
||||
time_t original = utils::tm_to_time(*dt);
|
||||
if (INVALID_TIME == original) return INVALID_TIME;
|
||||
|
||||
if(!detail::find_next<Traits>(cex, *dt, dt->tm_year))
|
||||
return INVALID_TIME;
|
||||
|
||||
time_t calculated = utils::tm_to_time(*dt);
|
||||
if (INVALID_TIME == calculated) return calculated;
|
||||
|
||||
if (calculated == original)
|
||||
{
|
||||
add_to_field(*dt, detail::cron_field::second, 1);
|
||||
if(!detail::find_next<Traits>(cex, *dt, dt->tm_year))
|
||||
return INVALID_TIME;
|
||||
}
|
||||
|
||||
return utils::tm_to_time(*dt);
|
||||
}
|
||||
|
||||
template <typename Traits = cron_standard_traits>
|
||||
static std::chrono::system_clock::time_point cron_next(cronexpr const & cex, std::chrono::system_clock::time_point const & time_point) {
|
||||
return std::chrono::system_clock::from_time_t(cron_next<Traits>(cex, std::chrono::system_clock::to_time_t(time_point)));
|
||||
}
|
||||
}
|
||||
@@ -96,42 +96,40 @@ namespace OpenWifi {
|
||||
void EntityDB::AddVenues(Poco::JSON::Object &Tree, const std::string & Node) {
|
||||
ProvObjects::Venue E;
|
||||
// std::cout << "Adding venue:" << Node << std::endl;
|
||||
if(StorageService()->VenueDB().GetRecord("id",Node,E)) {
|
||||
Poco::JSON::Array Venues;
|
||||
for (const auto &i: E.children) {
|
||||
Poco::JSON::Object Venue;
|
||||
AddVenues(Venue, i);
|
||||
Venues.add(Venue);
|
||||
}
|
||||
Tree.set("type", "venue");
|
||||
Tree.set("name", E.info.name);
|
||||
Tree.set("uuid", E.info.id);
|
||||
Tree.set("children", Venues);
|
||||
StorageService()->VenueDB().GetRecord("id",Node,E);
|
||||
Poco::JSON::Array Venues;
|
||||
for(const auto &i:E.children) {
|
||||
Poco::JSON::Object Venue;
|
||||
AddVenues(Venue, i);
|
||||
Venues.add(Venue);
|
||||
}
|
||||
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) {
|
||||
ProvObjects::Entity E;
|
||||
// std::cout << "Adding node:" << Node << std::endl;
|
||||
if(StorageService()->EntityDB().GetRecord("id",Node,E)) {
|
||||
Poco::JSON::Array Children;
|
||||
for (const auto &i: E.children) {
|
||||
Poco::JSON::Object Child;
|
||||
BuildTree(Child, i);
|
||||
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);
|
||||
StorageService()->EntityDB().GetRecord("id",Node,E);
|
||||
Poco::JSON::Array Children;
|
||||
for(const auto &i:E.children) {
|
||||
Poco::JSON::Object Child;
|
||||
BuildTree(Child,i);
|
||||
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);
|
||||
}
|
||||
|
||||
void EntityDB::ImportVenues(const Poco::JSON::Object::Ptr &O, const std::string &Parent) {
|
||||
|
||||
@@ -83,13 +83,12 @@ namespace OpenWifi {
|
||||
InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
|
||||
DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {}
|
||||
|
||||
bool InventoryDB::CreateFromConnection( const std::string &SerialNumberRaw,
|
||||
bool InventoryDB::CreateFromConnection( const std::string &SerialNumber,
|
||||
const std::string &ConnectionInfo,
|
||||
const std::string &DeviceType,
|
||||
const std::string &Locale) {
|
||||
|
||||
ProvObjects::InventoryTag ExistingDevice;
|
||||
auto SerialNumber = Poco::toLower(SerialNumberRaw);
|
||||
if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) {
|
||||
ProvObjects::InventoryTag NewDevice;
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
@@ -224,7 +223,7 @@ namespace OpenWifi {
|
||||
ProvObjects::DeviceRules Rules;
|
||||
std::string SerialNumber = Utils::IntToSerialNumber(i);
|
||||
if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) {
|
||||
if(Rules.rrm!="no" && Rules.rrm!="inherit")
|
||||
if(Rules.rrm=="yes")
|
||||
DeviceList.push_back(SerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
51
src/storage/storage_jobs.cpp
Normal file
51
src/storage/storage_jobs.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-10-28.
|
||||
//
|
||||
|
||||
#include "storage_jobs.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static ORM::FieldVec JobDB_Fields{
|
||||
// object info
|
||||
ORM::Field{"id",64, true},
|
||||
ORM::Field{"name",ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"description",ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"type",ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"progress",ORM::FieldType::FT_BIGINT},
|
||||
ORM::Field{"total",ORM::FieldType::FT_BIGINT},
|
||||
ORM::Field{"parameters",ORM::FieldType::FT_TEXT}
|
||||
};
|
||||
|
||||
static ORM::IndexVec JobDB_Indexes{
|
||||
{ std::string("job_name_index"),
|
||||
ORM::IndexEntryVec{
|
||||
{std::string("name"),
|
||||
ORM::Indextype::ASC} } }
|
||||
};
|
||||
|
||||
JobDB::JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
|
||||
DB(T, "jobs", JobDB_Fields, JobDB_Indexes, P, L, "job") {}
|
||||
}
|
||||
|
||||
template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobDBRecordType &In, OpenWifi::JobRecord &Out) {
|
||||
Out.id = In.get<0>();
|
||||
Out.name = In.get<1>();
|
||||
Out.description = In.get<2>();
|
||||
Out.type = In.get<3>();
|
||||
Out.progress = In.get<4>();
|
||||
Out.total = In.get<5>();
|
||||
Out.parameters = OpenWifi::RESTAPI_utils::to_array_of_array_of_object<OpenWifi::Job::Parameter>(In.get<3>());
|
||||
}
|
||||
|
||||
template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobRecord &In, OpenWifi::JobDBRecordType &Out) {
|
||||
Out.set<0>(In.id);
|
||||
Out.set<1>(In.name);
|
||||
Out.set<2>(In.description);
|
||||
Out.set<3>(In.type);
|
||||
Out.set<4>(In.progress);
|
||||
Out.set<5>(In.total);
|
||||
Out.set<6>(OpenWifi::RESTAPI_utils::to_string(In.parameters));
|
||||
}
|
||||
40
src/storage/storage_jobs.h
Normal file
40
src/storage/storage_jobs.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-10-28.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/orm.h"
|
||||
#include "JobController.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
typedef Poco::Tuple<
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
std::string,
|
||||
uint64_t,
|
||||
uint64_t,
|
||||
std::string
|
||||
> JobDBRecordType;
|
||||
|
||||
struct JobRecord {
|
||||
Types::UUID_t id;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string type;
|
||||
uint64_t progress;
|
||||
uint64_t total;
|
||||
Job::ParametersVec parameters;
|
||||
|
||||
// void from_string(const std::string &S);
|
||||
// std::string to_string() const;
|
||||
};
|
||||
|
||||
class JobDB : public ORM::DB<JobDBRecordType, JobRecord> {
|
||||
public:
|
||||
JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L);
|
||||
virtual ~JobDB() {};
|
||||
private:
|
||||
};
|
||||
}
|
||||
@@ -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')"
|
||||
path="$(echo $url | grep / | cut -d/ -f2-)"
|
||||
export OWPROV=${url}
|
||||
echo "Using PROV=${OWPROV}..."
|
||||
echo "Using ${OWPROV}..."
|
||||
else
|
||||
echo "OWPROV endpoint is not found:"
|
||||
jq < ${result_file}
|
||||
@@ -108,33 +108,6 @@ else
|
||||
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() {
|
||||
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
@@ -534,24 +507,6 @@ getvenuedevices() {
|
||||
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
|
||||
case "$1" in
|
||||
"login") login; echo "You are logged in..." ; logout ;;
|
||||
@@ -600,8 +555,6 @@ case "$1" in
|
||||
"getsubdevs") login; getsubdevs $2; logout;;
|
||||
"listvenues") login; listvenues $2; logout;;
|
||||
"getvenuedevices") login; getvenuedevices $2; logout;;
|
||||
"listrrmalgos") login; listrrmalgos; logout;;
|
||||
"rrmprovider") login; rrmprovider; logout;;
|
||||
*) help ;;
|
||||
esac
|
||||
|
||||
|
||||
Reference in New Issue
Block a user