mirror of
https://github.com/Telecominfraproject/wlan-cloud-owprov.git
synced 2025-10-30 18:18:03 +00:00
Compare commits
36 Commits
v2.6.0-RC5
...
v2.7.0-RC1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a33815096 | ||
|
|
f515bb8e30 | ||
|
|
02fd6d726a | ||
|
|
27ffb31a7c | ||
|
|
5fd9831d6b | ||
|
|
fed085cc4a | ||
|
|
121fee841e | ||
|
|
4c6f03ba14 | ||
|
|
0fb9478675 | ||
|
|
97c2af83fd | ||
|
|
599ba0793c | ||
|
|
6df780dba3 | ||
|
|
a00287ae85 | ||
|
|
c7a300b81e | ||
|
|
5dc507a82e | ||
|
|
8b3e1326b7 | ||
|
|
667f8bc4bd | ||
|
|
0168301d6b | ||
|
|
1a0b00e989 | ||
|
|
7c2229f3d6 | ||
|
|
541df429ec | ||
|
|
6f9fe6cd5d | ||
|
|
2594a2c5f2 | ||
|
|
2e02d96523 | ||
|
|
a1375f9468 | ||
|
|
777bc0f2aa | ||
|
|
bd0e99309c | ||
|
|
6cb6a60142 | ||
|
|
fc7947394d | ||
|
|
1341e15874 | ||
|
|
f065815df3 | ||
|
|
03ba51e869 | ||
|
|
efd7ef2a9b | ||
|
|
4b90a6e893 | ||
|
|
f5cb4a5a87 | ||
|
|
e3e4aac202 |
@@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(owprov VERSION 2.6.0)
|
project(owprov VERSION 2.7.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
@@ -134,7 +134,14 @@ add_executable(owprov
|
|||||||
src/storage/storage_variables.cpp src/storage/storage_variables.h
|
src/storage/storage_variables.cpp src/storage/storage_variables.h
|
||||||
src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h
|
src/RESTAPI/RESTAPI_variables_handler.cpp src/RESTAPI/RESTAPI_variables_handler.h
|
||||||
src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h
|
src/RESTAPI/RESTAPI_variables_list_handler.cpp src/RESTAPI/RESTAPI_variables_list_handler.h
|
||||||
src/FileDownloader.cpp src/FileDownloader.h src/Tasks/VenueConfigUpdater.h src/Kafka_ProvUpdater.cpp src/Kafka_ProvUpdater.h src/storage/storage_operataor.cpp src/storage/storage_operataor.h src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h src/storage/storage_service_class.cpp src/storage/storage_service_class.h src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h src/RESTAPI/RESTAPI_service_class_handler.cpp src/RESTAPI/RESTAPI_service_class_handler.h src/RESTAPI/RESTAPI_operators_list_handler.cpp src/RESTAPI/RESTAPI_operators_list_handler.h src/RESTAPI/RESTAPI_operators_handler.cpp src/RESTAPI/RESTAPI_operators_handler.h src/storage/storage_op_contacts.cpp src/storage/storage_op_contacts.h src/storage/storage_op_locations.cpp src/storage/storage_op_locations.h src/RESTAPI/RESTAPI_op_contact_list_handler.cpp src/RESTAPI/RESTAPI_op_contact_list_handler.h src/RESTAPI/RESTAPI_op_contact_handler.cpp src/RESTAPI/RESTAPI_op_contact_handler.h src/RESTAPI/RESTAPI_op_location_list_handler.cpp src/RESTAPI/RESTAPI_op_location_list_handler.h src/RESTAPI/RESTAPI_op_location_handler.cpp src/RESTAPI/RESTAPI_op_location_handler.h src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h)
|
src/FileDownloader.cpp src/FileDownloader.h
|
||||||
|
src/Tasks/VenueConfigUpdater.h
|
||||||
|
src/libs/croncpp.h
|
||||||
|
src/Kafka_ProvUpdater.cpp src/Kafka_ProvUpdater.h
|
||||||
|
src/storage/storage_operataor.cpp src/storage/storage_operataor.h
|
||||||
|
src/storage/storage_sub_devices.cpp src/storage/storage_sub_devices.h
|
||||||
|
src/storage/storage_service_class.cpp src/storage/storage_service_class.h
|
||||||
|
src/RESTAPI/RESTAPI_sub_devices_list_handler.cpp src/RESTAPI/RESTAPI_sub_devices_list_handler.h src/RESTAPI/RESTAPI_sub_devices_handler.cpp src/RESTAPI/RESTAPI_sub_devices_handler.h src/RESTAPI/RESTAPI_service_class_list_handler.cpp src/RESTAPI/RESTAPI_service_class_list_handler.h src/RESTAPI/RESTAPI_service_class_handler.cpp src/RESTAPI/RESTAPI_service_class_handler.h src/RESTAPI/RESTAPI_operators_list_handler.cpp src/RESTAPI/RESTAPI_operators_list_handler.h src/RESTAPI/RESTAPI_operators_handler.cpp src/RESTAPI/RESTAPI_operators_handler.h src/storage/storage_op_contacts.cpp src/storage/storage_op_contacts.h src/storage/storage_op_locations.cpp src/storage/storage_op_locations.h src/RESTAPI/RESTAPI_op_contact_list_handler.cpp src/RESTAPI/RESTAPI_op_contact_list_handler.h src/RESTAPI/RESTAPI_op_contact_handler.cpp src/RESTAPI/RESTAPI_op_contact_handler.h src/RESTAPI/RESTAPI_op_location_list_handler.cpp src/RESTAPI/RESTAPI_op_location_list_handler.h src/RESTAPI/RESTAPI_op_location_handler.cpp src/RESTAPI/RESTAPI_op_location_handler.h src/ProvWebSocketClient.cpp src/ProvWebSocketClient.h src/Tasks/VenueRebooter.h src/Tasks/VenueUpgrade.h src/sdks/SDK_fms.cpp src/sdks/SDK_fms.h)
|
||||||
|
|
||||||
target_link_libraries(owprov PUBLIC
|
target_link_libraries(owprov PUBLIC
|
||||||
${Poco_LIBRARIES}
|
${Poco_LIBRARIES}
|
||||||
|
|||||||
54
Dockerfile
54
Dockerfile
@@ -1,4 +1,10 @@
|
|||||||
FROM alpine:3.15 AS build-base
|
ARG ALPINE_VERSION=3.16.2
|
||||||
|
ARG POCO_VERSION=poco-tip-v1
|
||||||
|
ARG FMTLIB_VERSION=9.0.0
|
||||||
|
ARG CPPKAFKA_VERSION=tip-v1
|
||||||
|
ARG JSON_VALIDATOR_VERSION=2.1.0
|
||||||
|
|
||||||
|
FROM alpine:$ALPINE_VERSION AS build-base
|
||||||
|
|
||||||
RUN apk add --update --no-cache \
|
RUN apk add --update --no-cache \
|
||||||
make cmake g++ git \
|
make cmake g++ git \
|
||||||
@@ -9,8 +15,10 @@ RUN apk add --update --no-cache \
|
|||||||
|
|
||||||
FROM build-base AS poco-build
|
FROM build-base AS poco-build
|
||||||
|
|
||||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
ARG POCO_VERSION
|
||||||
RUN git clone https://github.com/stephb9959/poco /poco
|
|
||||||
|
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||||
|
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||||
|
|
||||||
WORKDIR /poco
|
WORKDIR /poco
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
@@ -19,10 +27,26 @@ RUN cmake ..
|
|||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
RUN cmake --build . --target install
|
RUN cmake --build . --target install
|
||||||
|
|
||||||
|
FROM build-base AS fmtlib-build
|
||||||
|
|
||||||
|
ARG FMTLIB_VERSION
|
||||||
|
|
||||||
|
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
||||||
|
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
||||||
|
|
||||||
|
WORKDIR /fmtlib
|
||||||
|
RUN mkdir cmake-build
|
||||||
|
WORKDIR cmake-build
|
||||||
|
RUN cmake ..
|
||||||
|
RUN make
|
||||||
|
RUN make install
|
||||||
|
|
||||||
FROM build-base AS cppkafka-build
|
FROM build-base AS cppkafka-build
|
||||||
|
|
||||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
ARG CPPKAFKA_VERSION
|
||||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
|
||||||
|
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||||
|
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||||
|
|
||||||
WORKDIR /cppkafka
|
WORKDIR /cppkafka
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
@@ -33,8 +57,10 @@ RUN cmake --build . --target install
|
|||||||
|
|
||||||
FROM build-base AS json-schema-validator-build
|
FROM build-base AS json-schema-validator-build
|
||||||
|
|
||||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
ARG JSON_VALIDATOR_VERSION
|
||||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
|
||||||
|
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
||||||
|
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
||||||
|
|
||||||
WORKDIR /json-schema-validator
|
WORKDIR /json-schema-validator
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
@@ -43,18 +69,6 @@ RUN cmake ..
|
|||||||
RUN make
|
RUN make
|
||||||
RUN make install
|
RUN make install
|
||||||
|
|
||||||
FROM build-base AS fmtlib-build
|
|
||||||
|
|
||||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
|
|
||||||
RUN git clone https://github.com/fmtlib/fmt /fmtlib
|
|
||||||
|
|
||||||
WORKDIR /fmtlib
|
|
||||||
RUN mkdir cmake-build
|
|
||||||
WORKDIR cmake-build
|
|
||||||
RUN cmake ..
|
|
||||||
RUN make
|
|
||||||
RUN make install
|
|
||||||
|
|
||||||
FROM build-base AS owprov-build
|
FROM build-base AS owprov-build
|
||||||
|
|
||||||
ADD CMakeLists.txt build /owprov/
|
ADD CMakeLists.txt build /owprov/
|
||||||
@@ -77,7 +91,7 @@ WORKDIR /owprov/cmake-build
|
|||||||
RUN cmake ..
|
RUN cmake ..
|
||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
|
|
||||||
FROM alpine:3.15
|
FROM alpine:$ALPINE_VERSION
|
||||||
|
|
||||||
ENV OWPROV_USER=owprov \
|
ENV OWPROV_USER=owprov \
|
||||||
OWPROV_ROOT=/owprov-data \
|
OWPROV_ROOT=/owprov-data \
|
||||||
|
|||||||
2
helm/.gitignore
vendored
2
helm/.gitignore
vendored
@@ -1 +1,3 @@
|
|||||||
*.swp
|
*.swp
|
||||||
|
Chart.lock
|
||||||
|
charts/
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{{- $root := . -}}
|
{{- $root := . -}}
|
||||||
|
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -46,6 +47,39 @@ spec:
|
|||||||
- -timeout
|
- -timeout
|
||||||
- 600s
|
- 600s
|
||||||
|
|
||||||
|
{{- if eq $storageType "postgresql" }}
|
||||||
|
- name: wait-postgres
|
||||||
|
image: "{{ .Values.images.owprov.repository }}:{{ .Values.images.owprov.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.images.owprov.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- /wait-for-postgres.sh
|
||||||
|
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
|
||||||
|
- echo
|
||||||
|
- "PostgreSQL is ready"
|
||||||
|
env:
|
||||||
|
- name: KUBERNETES_DEPLOYED
|
||||||
|
value: "{{ now }}"
|
||||||
|
{{- range $key, $value := .Values.public_env_variables }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
value: {{ $value | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $key, $value := .Values.secret_env_variables }}
|
||||||
|
- name: {{ $key }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "owprov.fullname" $root }}-env
|
||||||
|
key: {{ $key }}
|
||||||
|
{{- end }}
|
||||||
|
volumeMounts:
|
||||||
|
{{- range .Values.volumes.owprov }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
mountPath: {{ .mountPath }}
|
||||||
|
{{- if .subPath }}
|
||||||
|
subPath: {{ .subPath }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
containers:
|
containers:
|
||||||
|
|
||||||
- name: owprov
|
- name: owprov
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
|||||||
images:
|
images:
|
||||||
owprov:
|
owprov:
|
||||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov
|
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owprov
|
||||||
tag: main
|
tag: v2.7.0-RC1
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
# regcred:
|
# regcred:
|
||||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||||
|
|||||||
@@ -1958,11 +1958,6 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
type: boolean
|
type: boolean
|
||||||
required: false
|
required: false
|
||||||
- in: query
|
|
||||||
name: deviceType
|
|
||||||
schema:
|
|
||||||
type: string
|
|
||||||
required: false
|
|
||||||
- in: query
|
- in: query
|
||||||
description: Pagination start (starts at 1. If not specified, 1 is assumed)
|
description: Pagination start (starts at 1. If not specified, 1 is assumed)
|
||||||
name: offset
|
name: offset
|
||||||
@@ -2034,6 +2029,21 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
required: false
|
required: false
|
||||||
|
- in: query
|
||||||
|
description: return RRM settings for a specific device
|
||||||
|
name: rrmSettings
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
required: false
|
||||||
|
- in: query
|
||||||
|
description: return the resolved configuration for a specific device
|
||||||
|
name: resolveConfig
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
required: false
|
||||||
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Return a list of elements
|
description: Return a list of elements
|
||||||
@@ -2255,12 +2265,6 @@ paths:
|
|||||||
type: string
|
type: string
|
||||||
example: serial1,serial2,serial3
|
example: serial1,serial2,serial3
|
||||||
required: false
|
required: false
|
||||||
- in: query
|
|
||||||
description: only serial numbers of full device details
|
|
||||||
name: serialOnly
|
|
||||||
schema:
|
|
||||||
type: boolean
|
|
||||||
required: false
|
|
||||||
- in: query
|
- in: query
|
||||||
description: return the number of devices
|
description: return the number of devices
|
||||||
name: countOnly
|
name: countOnly
|
||||||
|
|||||||
174
openapi/rrm_provider.yaml
Normal file
174
openapi/rrm_provider.yaml
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
openapi: 3.0.1
|
||||||
|
info:
|
||||||
|
title: OpenWiFi RRM Provider Model
|
||||||
|
description: Definitions and APIs to manages an OpenWiFi RRM Providers.
|
||||||
|
version: 1.0.0
|
||||||
|
license:
|
||||||
|
name: BSD3
|
||||||
|
url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||||
|
|
||||||
|
servers:
|
||||||
|
- url: 'https://localhost:16022/api/v1'
|
||||||
|
|
||||||
|
security:
|
||||||
|
- bearerAuth: []
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
|
||||||
|
components:
|
||||||
|
securitySchemes:
|
||||||
|
ApiKeyAuth:
|
||||||
|
type: apiKey
|
||||||
|
in: header
|
||||||
|
name: X-API-KEY
|
||||||
|
bearerAuth:
|
||||||
|
type: http
|
||||||
|
scheme: bearer
|
||||||
|
bearerFormat: JWT
|
||||||
|
|
||||||
|
responses:
|
||||||
|
NotFound:
|
||||||
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||||
|
Unauthorized:
|
||||||
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||||
|
Success:
|
||||||
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
|
||||||
|
BadRequest:
|
||||||
|
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
|
||||||
|
|
||||||
|
schemas:
|
||||||
|
|
||||||
|
Provider:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
vendor:
|
||||||
|
description: The name of the vendor for display.
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 128
|
||||||
|
vendorShortname:
|
||||||
|
description: A shortname for the vendor. Only letters and numbers are allowed. This is the name used internally.
|
||||||
|
type: string
|
||||||
|
minLength: 4
|
||||||
|
maxLength: 16
|
||||||
|
version:
|
||||||
|
description: An identifier that will help users identify the version of the RRM module they are using.
|
||||||
|
type: string
|
||||||
|
about:
|
||||||
|
description: A link to the Vendor page for this RRM Module
|
||||||
|
type: string
|
||||||
|
|
||||||
|
|
||||||
|
Algorithm:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: A display for this algorithm.
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 128
|
||||||
|
description:
|
||||||
|
description: A description of the algorithm.
|
||||||
|
type: string
|
||||||
|
shortName:
|
||||||
|
description: This is the name used internally.
|
||||||
|
type: string
|
||||||
|
minLength: 4
|
||||||
|
maxLength: 16
|
||||||
|
parameterFormat:
|
||||||
|
description: this is a Regex used to validate the input. If this is empty, no validation will be performed.
|
||||||
|
type: string
|
||||||
|
parameterSamples:
|
||||||
|
description: These samples will be displayed in the UI to the user trying to configure the options
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
helper:
|
||||||
|
description: A link to a web page or PDF document explaining the algorithm and its parameters
|
||||||
|
type: string
|
||||||
|
|
||||||
|
Algorithms:
|
||||||
|
description: The list of all algorithms supported by the vendor
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Algorithm'
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/provider:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- RRM
|
||||||
|
operationId: getProvider
|
||||||
|
summary: Retrieve information about the provider for this RRM Module
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
$ref: '#/components/schemas/Provider'
|
||||||
|
400:
|
||||||
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
404:
|
||||||
|
$ref: '#/components/responses/NotFound'
|
||||||
|
|
||||||
|
/algorithms:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- RRM
|
||||||
|
operationId: getAlgorithms
|
||||||
|
summary: Retrieve a lists of algorithms supported in the module.
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
$ref: '#/components/schemas/Algorithms'
|
||||||
|
400:
|
||||||
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
404:
|
||||||
|
$ref: '#/components/responses/NotFound'
|
||||||
|
|
||||||
|
/runRRM:
|
||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- RRM
|
||||||
|
operationId: runRRMNow
|
||||||
|
summary: Run a specific or default RRM algorithm. The UI user or CLI user will have the ability to run an algorithm on demand.
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
description:
|
||||||
|
name: venue
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
required: true
|
||||||
|
- in: query
|
||||||
|
description: Perform RRM without updating anything. This may be used by an admin to see what RRM would do.
|
||||||
|
name: mock
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
required: false
|
||||||
|
- in: query
|
||||||
|
description: Specify the RRM algorithm to use. If omitted, select the default algorithm.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
- in: query
|
||||||
|
description: Specify the parameters to use with the RRM algorithm to use. If omitted, select the default parameters.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Return the list of actions that were or would be performed.
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
400:
|
||||||
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
403:
|
||||||
|
$ref: '#/components/responses/Unauthorized'
|
||||||
|
404:
|
||||||
|
$ref: '#/components/responses/NotFound'
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ namespace OpenWifi {
|
|||||||
bool &Done, std::string &Answer) {
|
bool &Done, std::string &Answer) {
|
||||||
Done = false;
|
Done = false;
|
||||||
auto Prefix = O->get("serial_prefix").toString();
|
auto Prefix = O->get("serial_prefix").toString();
|
||||||
|
Poco::toLowerInPlace(Prefix);
|
||||||
Logger().information(Poco::format("serial_number_search: %s", Prefix));
|
Logger().information(Poco::format("serial_number_search: %s", Prefix));
|
||||||
if (!Prefix.empty() && Prefix.length() < 13) {
|
if (!Prefix.empty() && Prefix.length() < 13) {
|
||||||
std::vector<uint64_t> Numbers;
|
std::vector<uint64_t> Numbers;
|
||||||
@@ -83,6 +84,7 @@ namespace OpenWifi {
|
|||||||
Done = false;
|
Done = false;
|
||||||
auto operatorId = O->get("operatorId").toString();
|
auto operatorId = O->get("operatorId").toString();
|
||||||
auto Prefix = O->get("serial_prefix").toString();
|
auto Prefix = O->get("serial_prefix").toString();
|
||||||
|
Poco::toLowerInPlace(Prefix);
|
||||||
std::string Query;
|
std::string Query;
|
||||||
|
|
||||||
if(Prefix[0]=='*') {
|
if(Prefix[0]=='*') {
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#include "framework/MicroService.h"
|
#include "framework/MicroService.h"
|
||||||
#include "framework/ConfigurationValidator.h"
|
#include "framework/ConfigurationValidator.h"
|
||||||
#include "sdks/SDK_sec.h"
|
#include "sdks/SDK_sec.h"
|
||||||
|
#include "Poco/StringTokenizer.h"
|
||||||
|
|
||||||
|
#include "libs/croncpp.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
@@ -405,7 +408,9 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) {
|
inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) {
|
||||||
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", "unit" };
|
static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services",
|
||||||
|
"unit", "definitions", "ethernet", "switch", "config-raw",
|
||||||
|
"third-party" };
|
||||||
|
|
||||||
for(const auto &i:Config.configuration) {
|
for(const auto &i:Config.configuration) {
|
||||||
Poco::JSON::Parser P;
|
Poco::JSON::Parser P;
|
||||||
@@ -521,12 +526,39 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool ValidSchedule(const std::string &v) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto cron = cron::make_cron(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (cron::bad_cronexpr const & ex)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ValidRRM(const std::string &v) {
|
||||||
|
if((v=="no") || (v=="inherit")) return true;
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto O = P.parse(v).extract<Poco::JSON::Object::Ptr>();
|
||||||
|
|
||||||
|
ProvObjects::RRMDetails D;
|
||||||
|
if(D.from_json(O)) {
|
||||||
|
return ValidSchedule(D.schedule);
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
inline bool ValidDeviceRules(const ProvObjects::DeviceRules & DR) {
|
inline bool ValidDeviceRules(const ProvObjects::DeviceRules & DR) {
|
||||||
return (DR.rrm=="yes" || DR.rrm=="no" || DR.rrm=="inherit") &&
|
return (ValidRRM(DR.rrm)) &&
|
||||||
(DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") &&
|
(DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") &&
|
||||||
(DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit");
|
(DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,35 +36,52 @@ namespace OpenWifi{
|
|||||||
void RESTAPI_inventory_handler::DoGet() {
|
void RESTAPI_inventory_handler::DoGet() {
|
||||||
|
|
||||||
ProvObjects::InventoryTag Existing;
|
ProvObjects::InventoryTag Existing;
|
||||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
|
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||||
Logger().debug(Poco::format("%s: Retrieving inventory information.",SerialNumber));
|
Logger().debug(Poco::format("%s: Retrieving inventory information.", SerialNumber));
|
||||||
if(SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER,SerialNumber,Existing)) {
|
if (SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) {
|
||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
Logger().debug(Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id ));
|
Logger().debug(
|
||||||
|
Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id));
|
||||||
|
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
std::string Arg;
|
std::string Arg;
|
||||||
if(HasParameter("config",Arg) && Arg=="true") {
|
if (HasParameter("config", Arg) && Arg == "true") {
|
||||||
bool Explain = (HasParameter("explain",Arg) && Arg == "true");
|
bool Explain = (HasParameter("explain", Arg) && Arg == "true");
|
||||||
APConfig Device(SerialNumber,Existing.deviceType,Logger(), Explain);
|
APConfig Device(SerialNumber, Existing.deviceType, Logger(), Explain);
|
||||||
|
|
||||||
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
||||||
if(Device.Get(Configuration)) {
|
if (Device.Get(Configuration)) {
|
||||||
Answer.set("config", Configuration);
|
Answer.set("config", Configuration);
|
||||||
if(Explain)
|
if (Explain)
|
||||||
Answer.set("explanation", Device.Explanation());
|
Answer.set("explanation", Device.Explanation());
|
||||||
} else {
|
} else {
|
||||||
Answer.set("config","none");
|
Answer.set("config", "none");
|
||||||
}
|
}
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
} else if(HasParameter("firmwareOptions", Arg) && Arg=="true") {
|
} else if (GetBoolParameter("firmwareOptions", false)) {
|
||||||
ProvObjects::DeviceRules Rules;
|
ProvObjects::DeviceRules Rules;
|
||||||
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber,Rules);
|
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules);
|
||||||
Answer.set("firmwareUpgrade",Rules.firmwareUpgrade);
|
Answer.set("firmwareUpgrade", Rules.firmwareUpgrade);
|
||||||
Answer.set("firmwareRCOnly", Rules.rcOnly == "yes" );
|
Answer.set("firmwareRCOnly", Rules.rcOnly == "yes");
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
} else if(HasParameter("applyConfiguration",Arg) && Arg=="true") {
|
} else if(GetBoolParameter("rrmSettings",false)) {
|
||||||
|
ProvObjects::DeviceRules Rules;
|
||||||
|
StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules);
|
||||||
|
if(Rules.rrm=="no" || Rules.rrm=="inherit") {
|
||||||
|
Answer.set("rrm", Rules.rrm);
|
||||||
|
} else {
|
||||||
|
ProvObjects::RRMDetails D;
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
try {
|
||||||
|
auto Obj = P.parse(Rules.rrm).extract<Poco::JSON::Object::Ptr>();
|
||||||
|
Answer.set("rrm", Obj);
|
||||||
|
} catch (...) {
|
||||||
|
Answer.set("rrm", "invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
} else if(GetBoolParameter("applyConfiguration", false)) {
|
||||||
Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber));
|
Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber));
|
||||||
auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false);
|
auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false);
|
||||||
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
||||||
@@ -91,6 +108,19 @@ namespace OpenWifi{
|
|||||||
}
|
}
|
||||||
Results.to_json(Answer);
|
Results.to_json(Answer);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
|
} else if(GetBoolParameter("resolveConfig", false)) {
|
||||||
|
Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber));
|
||||||
|
auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false);
|
||||||
|
auto Configuration = Poco::makeShared<Poco::JSON::Object>();
|
||||||
|
Poco::JSON::Object ErrorsObj, WarningsObj;
|
||||||
|
ProvObjects::InventoryConfigApplyResult Results;
|
||||||
|
Logger().debug(Poco::format("%s: Computing configuration.",Existing.serialNumber));
|
||||||
|
if (Device->Get(Configuration)) {
|
||||||
|
Answer.set("configuration", Configuration);
|
||||||
|
} else {
|
||||||
|
Answer.set("error", 1);
|
||||||
|
}
|
||||||
|
return ReturnObject(Answer);
|
||||||
} else if(QB_.AdditionalInfo) {
|
} else if(QB_.AdditionalInfo) {
|
||||||
AddExtendedInfo(Existing,Answer);
|
AddExtendedInfo(Existing,Answer);
|
||||||
}
|
}
|
||||||
@@ -136,6 +166,7 @@ namespace OpenWifi{
|
|||||||
|
|
||||||
void RESTAPI_inventory_handler::DoPost() {
|
void RESTAPI_inventory_handler::DoPost() {
|
||||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
|
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,"");
|
||||||
|
Poco::toLowerInPlace(SerialNumber);
|
||||||
if(SerialNumber.empty()) {
|
if(SerialNumber.empty()) {
|
||||||
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
return BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace OpenWifi {
|
|||||||
{ "email", UserName },
|
{ "email", UserName },
|
||||||
{ "signupUUID" , SignupUUID },
|
{ "signupUUID" , SignupUUID },
|
||||||
{ "owner" , SignupOperator.info.id },
|
{ "owner" , SignupOperator.info.id },
|
||||||
|
{ "operatorName", SignupOperator.registrationId }
|
||||||
}, Body, 30000);
|
}, Body, 30000);
|
||||||
|
|
||||||
Poco::JSON::Object::Ptr Answer;
|
Poco::JSON::Object::Ptr Answer;
|
||||||
|
|||||||
@@ -1159,5 +1159,40 @@ namespace OpenWifi::ProvObjects {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RRMAlgorithmDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
field_to_json(Obj,"name",name);
|
||||||
|
field_to_json(Obj,"parameters",parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RRMAlgorithmDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
try {
|
||||||
|
field_from_json(Obj,"name",name);
|
||||||
|
field_from_json(Obj,"parameters",parameters);
|
||||||
|
return true;
|
||||||
|
} catch(...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RRMDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
field_to_json(Obj,"vendor",vendor);
|
||||||
|
field_to_json(Obj,"schedule",schedule);
|
||||||
|
field_to_json(Obj,"algorithms",algorithms);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RRMDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
try {
|
||||||
|
field_from_json(Obj,"vendor",vendor);
|
||||||
|
field_from_json(Obj,"schedule",schedule);
|
||||||
|
field_from_json(Obj,"algorithms",algorithms);
|
||||||
|
return true;
|
||||||
|
} catch(...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,21 @@ namespace OpenWifi::ProvObjects {
|
|||||||
};
|
};
|
||||||
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
||||||
|
|
||||||
|
struct RRMAlgorithmDetails {
|
||||||
|
std::string name;
|
||||||
|
std::string parameters;
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RRMDetails {
|
||||||
|
std::string vendor;
|
||||||
|
std::string schedule;
|
||||||
|
std::vector<RRMAlgorithmDetails> algorithms;
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
};
|
||||||
|
|
||||||
struct DeviceRules {
|
struct DeviceRules {
|
||||||
std::string rcOnly{"inherit"};
|
std::string rcOnly{"inherit"};
|
||||||
std::string rrm{"inherit"};
|
std::string rrm{"inherit"};
|
||||||
|
|||||||
@@ -195,18 +195,24 @@ namespace OpenWifi {
|
|||||||
// check that all inventory in venues and entities actually exists, if not, fix it.
|
// check that all inventory in venues and entities actually exists, if not, fix it.
|
||||||
auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool {
|
auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool {
|
||||||
Types::UUIDvec_t NewDevices;
|
Types::UUIDvec_t NewDevices;
|
||||||
|
bool modified=false;
|
||||||
for(const auto &device:V.devices) {
|
for(const auto &device:V.devices) {
|
||||||
ProvObjects::InventoryTag T;
|
ProvObjects::InventoryTag T;
|
||||||
if(InventoryDB().GetRecord("id", device, T)) {
|
if(InventoryDB().GetRecord("id", device, T)) {
|
||||||
NewDevices.emplace_back(device);
|
NewDevices.emplace_back(device);
|
||||||
} else {
|
} else {
|
||||||
|
modified=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(NewDevices!=V.devices) {
|
|
||||||
Logger().warning(fmt::format(" fixing venue: {}", V.info.name));
|
|
||||||
ProvObjects::Venue NewVenue = V;
|
ProvObjects::Venue NewVenue = V;
|
||||||
|
if(V.deviceRules.rrm=="yes") {
|
||||||
|
NewVenue.deviceRules.rrm="inherit";
|
||||||
|
modified=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(modified) {
|
||||||
|
Logger().warning(fmt::format(" fixing venue: {}", V.info.name));
|
||||||
NewVenue.devices = NewDevices;
|
NewVenue.devices = NewDevices;
|
||||||
VenueDB().UpdateRecord("id", V.info.id, NewVenue);
|
VenueDB().UpdateRecord("id", V.info.id, NewVenue);
|
||||||
}
|
}
|
||||||
@@ -266,10 +272,16 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProvObjects::Entity NewEntity = E;
|
||||||
|
|
||||||
|
if(E.deviceRules.rrm=="yes") {
|
||||||
|
NewEntity.deviceRules.rrm="inherit";
|
||||||
|
Modified=true;
|
||||||
|
}
|
||||||
|
|
||||||
if(Modified)
|
if(Modified)
|
||||||
{
|
{
|
||||||
Logger().warning(fmt::format(" fixing entity: {}",E.info.name));
|
Logger().warning(fmt::format(" fixing entity: {}",E.info.name));
|
||||||
ProvObjects::Entity NewEntity = E;
|
|
||||||
NewEntity.devices = NewDevices;
|
NewEntity.devices = NewDevices;
|
||||||
NewEntity.contacts = NewContacts;
|
NewEntity.contacts = NewContacts;
|
||||||
NewEntity.locations = NewLocations;
|
NewEntity.locations = NewLocations;
|
||||||
@@ -304,6 +316,11 @@ namespace OpenWifi {
|
|||||||
modified=true;
|
modified=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(T.deviceRules.rrm=="yes") {
|
||||||
|
NewTag.deviceRules.rrm = "inherit";
|
||||||
|
modified=true;
|
||||||
|
}
|
||||||
|
|
||||||
if(modified) {
|
if(modified) {
|
||||||
Logger().warning(fmt::format(" fixing entity: {}",T.info.name));
|
Logger().warning(fmt::format(" fixing entity: {}",T.info.name));
|
||||||
InventoryDB().UpdateRecord("id", T.info.id, NewTag);
|
InventoryDB().UpdateRecord("id", T.info.id, NewTag);
|
||||||
@@ -311,12 +328,67 @@ namespace OpenWifi {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto FixConfiguration = [&](const ProvObjects::DeviceConfiguration &C) -> bool {
|
||||||
|
ProvObjects::DeviceConfiguration NewConfig{C};
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
if (C.deviceRules.rrm == "yes") {
|
||||||
|
NewConfig.deviceRules.rrm = "inherit";
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
Logger().warning(fmt::format(" fixing configuration: {}", C.info.name));
|
||||||
|
ConfigurationDB().UpdateRecord("id", C.info.id, NewConfig);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto FixOperator = [&](const ProvObjects::Operator &O) -> bool {
|
||||||
|
ProvObjects::Operator NewOp{O};
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
if (O.deviceRules.rrm == "yes") {
|
||||||
|
NewOp.deviceRules.rrm = "inherit";
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
Logger().warning(fmt::format(" fixing operator: {}", O.info.name));
|
||||||
|
OperatorDB().UpdateRecord("id", O.info.id, NewOp);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto FixSubscriber = [&](const ProvObjects::SubscriberDevice &O) -> bool {
|
||||||
|
ProvObjects::SubscriberDevice NewSub{O};
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
if (O.deviceRules.rrm == "yes") {
|
||||||
|
NewSub.deviceRules.rrm = "inherit";
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
Logger().warning(fmt::format(" fixing subscriber: {}", O.info.name));
|
||||||
|
SubscriberDeviceDB().UpdateRecord("id", O.info.id, NewSub);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
Logger().information("Checking DB consistency: venues");
|
Logger().information("Checking DB consistency: venues");
|
||||||
VenueDB().Iterate(FixVenueDevices);
|
VenueDB().Iterate(FixVenueDevices);
|
||||||
Logger().information("Checking DB consistency: entities");
|
Logger().information("Checking DB consistency: entities");
|
||||||
EntityDB().Iterate(FixEntity);
|
EntityDB().Iterate(FixEntity);
|
||||||
Logger().information("Checking DB consistency: inventory");
|
Logger().information("Checking DB consistency: inventory");
|
||||||
InventoryDB().Iterate(FixInventory);
|
InventoryDB().Iterate(FixInventory);
|
||||||
|
Logger().information("Checking DB consistency: configurations");
|
||||||
|
ConfigurationDB().Iterate(FixConfiguration);
|
||||||
|
Logger().information("Checking DB consistency: operators");
|
||||||
|
OperatorDB().Iterate(FixOperator);
|
||||||
|
Logger().information("Checking DB consistency: subscribers");
|
||||||
|
SubscriberDeviceDB().Iterate(FixSubscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Storage::InitializeSystemDBs() {
|
void Storage::InitializeSystemDBs() {
|
||||||
|
|||||||
@@ -44,18 +44,21 @@ namespace OpenWifi {
|
|||||||
upgraded_++;
|
upgraded_++;
|
||||||
} else {
|
} else {
|
||||||
Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber));
|
Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber));
|
||||||
failed_++;
|
not_connected_++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber));
|
Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber));
|
||||||
failed_++;
|
no_firmware_++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done_ = true;
|
done_ = true;
|
||||||
// std::cout << "Done push for " << Device.serialNumber << std::endl;
|
// std::cout << "Done push for " << Device.serialNumber << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t upgraded_=0, failed_=0, skipped_=0;
|
std::uint64_t upgraded_ = 0,
|
||||||
|
not_connected_ = 0,
|
||||||
|
skipped_ = 0,
|
||||||
|
no_firmware_ = 0;
|
||||||
bool started_ = false,
|
bool started_ = false,
|
||||||
done_ = false;
|
done_ = false;
|
||||||
std::string SerialNumber;
|
std::string SerialNumber;
|
||||||
@@ -80,10 +83,13 @@ namespace OpenWifi {
|
|||||||
Utils::SetThreadName("venue-upgr");
|
Utils::SetThreadName("venue-upgr");
|
||||||
auto VenueUUID_ = Parameter(0);
|
auto VenueUUID_ = Parameter(0);
|
||||||
|
|
||||||
WebSocketClientNotificationVenueRebootList_t N;
|
WebSocketClientNotificationVenueUpgradeList_t N;
|
||||||
|
|
||||||
ProvObjects::Venue Venue;
|
ProvObjects::Venue Venue;
|
||||||
uint64_t upgraded_ = 0, failed_ = 0;
|
uint64_t upgraded_ = 0,
|
||||||
|
not_connected_ = 0,
|
||||||
|
skipped_ = 0,
|
||||||
|
no_firmware_ = 0;
|
||||||
if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) {
|
if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) {
|
||||||
|
|
||||||
N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name);
|
N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name);
|
||||||
@@ -112,10 +118,16 @@ namespace OpenWifi {
|
|||||||
if (current_job != nullptr && current_job->done_) {
|
if (current_job != nullptr && current_job->done_) {
|
||||||
if (current_job->upgraded_)
|
if (current_job->upgraded_)
|
||||||
N.content.success.push_back(current_job->SerialNumber);
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
else
|
else if (current_job->skipped_)
|
||||||
N.content.warning.push_back(current_job->SerialNumber);
|
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_;
|
upgraded_ += current_job->upgraded_;
|
||||||
failed_ += current_job->failed_;
|
skipped_ += current_job->skipped_;
|
||||||
|
no_firmware_ += current_job->no_firmware_;
|
||||||
|
not_connected_ += current_job->not_connected_;
|
||||||
job_it = JobList.erase(job_it);
|
job_it = JobList.erase(job_it);
|
||||||
delete current_job;
|
delete current_job;
|
||||||
} else {
|
} else {
|
||||||
@@ -129,12 +141,18 @@ namespace OpenWifi {
|
|||||||
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
for(auto job_it = JobList.begin(); job_it !=JobList.end();) {
|
||||||
VenueDeviceUpgrade * current_job = *job_it;
|
VenueDeviceUpgrade * current_job = *job_it;
|
||||||
if(current_job!= nullptr && current_job->done_) {
|
if(current_job!= nullptr && current_job->done_) {
|
||||||
if(current_job->upgraded_)
|
if (current_job->upgraded_)
|
||||||
N.content.success.push_back(current_job->SerialNumber);
|
N.content.success.push_back(current_job->SerialNumber);
|
||||||
else
|
else if (current_job->skipped_)
|
||||||
N.content.warning.push_back(current_job->SerialNumber);
|
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_;
|
upgraded_ += current_job->upgraded_;
|
||||||
failed_ += current_job->failed_;
|
skipped_ += current_job->skipped_;
|
||||||
|
no_firmware_ += current_job->no_firmware_;
|
||||||
|
not_connected_ += current_job->not_connected_;
|
||||||
job_it = JobList.erase(job_it);
|
job_it = JobList.erase(job_it);
|
||||||
delete current_job;
|
delete current_job;
|
||||||
} else {
|
} else {
|
||||||
@@ -142,19 +160,21 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
|
N.content.details = fmt::format("Job {} Completed: {} upgraded, {} not connected, {} skipped, {} no firmware.",
|
||||||
JobId(), upgraded_ ,failed_);
|
JobId(),
|
||||||
|
upgraded_ ,
|
||||||
|
not_connected_,
|
||||||
|
skipped_,
|
||||||
|
no_firmware_);
|
||||||
} else {
|
} else {
|
||||||
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
|
N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_);
|
||||||
Logger().warning(N.content.details);
|
Logger().warning(N.content.details);
|
||||||
}
|
}
|
||||||
|
|
||||||
// std::cout << N.content.details << std::endl;
|
// std::cout << N.content.details << std::endl;
|
||||||
WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N);
|
WebSocketClientNotificationVenueUpgradeCompletionToUser(UserInfo().email,N);
|
||||||
Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.",
|
Logger().information(N.content.details);
|
||||||
JobId(), upgraded_ ,failed_));
|
|
||||||
Utils::SetThreadName("free");
|
Utils::SetThreadName("free");
|
||||||
|
|
||||||
Complete();
|
Complete();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ namespace OpenWifi {
|
|||||||
inline uint64_t Now() { return std::time(nullptr); };
|
inline uint64_t Now() { return std::time(nullptr); };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace OpenWifi::Utils {
|
||||||
|
std::vector<unsigned char> base64decode(const std::string& input);
|
||||||
|
std::string base64encode(const unsigned char *input, uint32_t size);
|
||||||
|
}
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
#include "Poco/Util/Application.h"
|
#include "Poco/Util/Application.h"
|
||||||
@@ -238,6 +243,11 @@ namespace OpenWifi::RESTAPI_utils {
|
|||||||
Obj.set(Field,Value);
|
Obj.set(Field,Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) {
|
||||||
|
auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size());
|
||||||
|
Obj.set(Field,Result);
|
||||||
|
}
|
||||||
|
|
||||||
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
|
||||||
Poco::JSON::Array Array;
|
Poco::JSON::Array Array;
|
||||||
for(const auto &i:S) {
|
for(const auto &i:S) {
|
||||||
@@ -334,12 +344,12 @@ namespace OpenWifi::RESTAPI_utils {
|
|||||||
|
|
||||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
|
||||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
Value = (double) Obj->get(Field);
|
Value = (double)Obj->get(Field);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
|
||||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
Value = (float) Obj->get(Field);
|
Value = (float)Obj->get(Field);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
|
||||||
@@ -374,7 +384,14 @@ namespace OpenWifi::RESTAPI_utils {
|
|||||||
|
|
||||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
|
||||||
if(Obj->has(Field) && !Obj->isNull(Field))
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
Value = (uint64_t ) Obj->get(Field);
|
Value = (uint64_t)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field)) {
|
||||||
|
auto Result = Utils::base64decode(Obj->get(Field).toString());
|
||||||
|
Value.assignRaw((const unsigned char *)&Result[0],Result.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
|
||||||
@@ -686,6 +703,19 @@ namespace OpenWifi::Utils {
|
|||||||
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0);
|
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> std::string ComputeHash(Args&&... args) {
|
||||||
|
Poco::SHA2Engine E;
|
||||||
|
auto as_string = [](auto p) {
|
||||||
|
if constexpr(std::is_arithmetic_v<decltype(p)>) {
|
||||||
|
return std::to_string(p);
|
||||||
|
} else {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(E.update(as_string(args)),...);
|
||||||
|
return Poco::SHA2Engine::digestToHex(E.digest());
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) {
|
[[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) {
|
||||||
std::vector<std::string> ReturnList;
|
std::vector<std::string> ReturnList;
|
||||||
|
|
||||||
@@ -1382,13 +1412,14 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
[[nodiscard]] inline const std::string &Address() const { return address_; };
|
[[nodiscard]] inline const std::string &Address() const { return address_; };
|
||||||
[[nodiscard]] inline uint32_t Port() const { return port_; };
|
[[nodiscard]] inline uint32_t Port() const { return port_; };
|
||||||
[[nodiscard]] inline const std::string &KeyFile() const { return key_file_; };
|
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
|
||||||
[[nodiscard]] inline const std::string &CertFile() const { return cert_file_; };
|
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
|
||||||
[[nodiscard]] inline const std::string &RootCA() const { return root_ca_; };
|
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
|
||||||
[[nodiscard]] inline const std::string &KeyFilePassword() const { return key_file_password_; };
|
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
|
||||||
[[nodiscard]] inline const std::string &IssuerCertFile() const { return issuer_cert_file_; };
|
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
|
||||||
[[nodiscard]] inline const std::string &Name() const { return name_; };
|
[[nodiscard]] inline auto Name() const { return name_; };
|
||||||
[[nodiscard]] inline int Backlog() const { return backlog_; }
|
[[nodiscard]] inline int Backlog() const { return backlog_; }
|
||||||
|
[[nodiscard]] inline auto Cas() const { return cas_; }
|
||||||
|
|
||||||
[[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const {
|
[[nodiscard]] inline Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const {
|
||||||
Poco::Net::Context::Params P;
|
Poco::Net::Context::Params P;
|
||||||
@@ -1868,8 +1899,8 @@ namespace OpenWifi {
|
|||||||
Request = &RequestIn;
|
Request = &RequestIn;
|
||||||
Response = &ResponseIn;
|
Response = &ResponseIn;
|
||||||
|
|
||||||
std::string th_name = "restsvr_" + std::to_string(TransactionId_);
|
// std::string th_name = "restsvr_" + std::to_string(TransactionId_);
|
||||||
Utils::SetThreadName(th_name.c_str());
|
// Utils::SetThreadName(th_name.c_str());
|
||||||
|
|
||||||
if(Request->getContentLength()>0) {
|
if(Request->getContentLength()>0) {
|
||||||
if(Request->getContentType().find("application/json")!=std::string::npos) {
|
if(Request->getContentType().find("application/json")!=std::string::npos) {
|
||||||
@@ -2064,6 +2095,17 @@ namespace OpenWifi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) {
|
||||||
|
if(O->has(Field)) {
|
||||||
|
std::string Content = O->get(Field).toString();
|
||||||
|
auto DecodedBlob = Utils::base64decode(Content);
|
||||||
|
Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
|
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
|
||||||
if(O->has(Field)) {
|
if(O->has(Field)) {
|
||||||
assignee = value;
|
assignee = value;
|
||||||
@@ -2404,6 +2446,7 @@ namespace OpenWifi {
|
|||||||
Poco::Net::HTTPServerResponse *Response= nullptr;
|
Poco::Net::HTTPServerResponse *Response= nullptr;
|
||||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||||
QueryBlock QB_;
|
QueryBlock QB_;
|
||||||
|
const std::string & Requester() const { return REST_Requester_; }
|
||||||
protected:
|
protected:
|
||||||
BindingMap Bindings_;
|
BindingMap Bindings_;
|
||||||
Poco::URI::QueryParameters Parameters_;
|
Poco::URI::QueryParameters Parameters_;
|
||||||
@@ -2420,6 +2463,7 @@ namespace OpenWifi {
|
|||||||
RateLimit MyRates_;
|
RateLimit MyRates_;
|
||||||
uint64_t TransactionId_;
|
uint64_t TransactionId_;
|
||||||
Poco::JSON::Object::Ptr ParsedBody_;
|
Poco::JSON::Object::Ptr ParsedBody_;
|
||||||
|
std::string REST_Requester_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
||||||
@@ -2684,7 +2728,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
inline void run() override {
|
inline void run() override {
|
||||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||||
Utils::SetThreadName("kafka-dispatch");
|
Utils::SetThreadName("kafka:dispatch");
|
||||||
while(Note && Running_) {
|
while(Note && Running_) {
|
||||||
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
|
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
|
||||||
if(Msg!= nullptr) {
|
if(Msg!= nullptr) {
|
||||||
@@ -2994,7 +3038,7 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
int Start() override;
|
int Start() override;
|
||||||
inline void Stop() override {
|
inline void Stop() override {
|
||||||
Logger().information("Stopping ");
|
Logger().information("Stopping...");
|
||||||
for( const auto & svr : RESTServers_ )
|
for( const auto & svr : RESTServers_ )
|
||||||
svr->stop();
|
svr->stop();
|
||||||
Pool_.stopAll();
|
Pool_.stopAll();
|
||||||
@@ -3002,22 +3046,23 @@ namespace OpenWifi {
|
|||||||
RESTServers_.clear();
|
RESTServers_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void reinitialize(Poco::Util::Application &self) override;
|
inline void reinitialize(Poco::Util::Application &self) override;
|
||||||
|
|
||||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||||
RESTAPIHandler::BindingMap Bindings;
|
RESTAPIHandler::BindingMap Bindings;
|
||||||
Utils::SetThreadName(fmt::format("rest_ext_{}",Id).c_str());
|
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
|
||||||
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
|
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
|
||||||
}
|
}
|
||||||
|
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||||
Poco::ThreadPool Pool_;
|
Poco::ThreadPool Pool_{"x-rest",2,32};
|
||||||
RESTAPI_GenericServer Server_;
|
RESTAPI_GenericServer Server_;
|
||||||
|
|
||||||
RESTAPI_ExtServer() noexcept:
|
RESTAPI_ExtServer() noexcept:
|
||||||
SubSystemServer("RESTAPI_ExtServer", "RESTAPIServer", "openwifi.restapi"),
|
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
|
||||||
Pool_("RESTAPI_ExtServer",4,50,120)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3030,7 +3075,7 @@ namespace OpenWifi {
|
|||||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
||||||
try {
|
try {
|
||||||
Poco::URI uri(Request.getURI());
|
Poco::URI uri(Request.getURI());
|
||||||
Utils::SetThreadName(fmt::format("rest_ext_{}",TransactionId_).c_str());
|
Utils::SetThreadName(fmt::format("x-rest:{}",TransactionId_).c_str());
|
||||||
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
|
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TransactionId_++);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
||||||
@@ -3128,7 +3173,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
inline int Start() override;
|
inline int Start() override;
|
||||||
inline void Stop() override {
|
inline void Stop() override {
|
||||||
Logger().information("Stopping ");
|
Logger().information("Stopping...");
|
||||||
for( const auto & svr : RESTServers_ )
|
for( const auto & svr : RESTServers_ )
|
||||||
svr->stop();
|
svr->stop();
|
||||||
Pool_.stopAll();
|
Pool_.stopAll();
|
||||||
@@ -3139,17 +3184,18 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||||
RESTAPIHandler::BindingMap Bindings;
|
RESTAPIHandler::BindingMap Bindings;
|
||||||
Utils::SetThreadName(fmt::format("rest_int_{}",Id).c_str());
|
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
|
||||||
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
|
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||||
Poco::ThreadPool Pool_;
|
Poco::ThreadPool Pool_{"i-rest",2,16};
|
||||||
RESTAPI_GenericServer Server_;
|
RESTAPI_GenericServer Server_;
|
||||||
|
|
||||||
RESTAPI_IntServer() noexcept:
|
RESTAPI_IntServer() noexcept:
|
||||||
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi"),
|
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi")
|
||||||
Pool_("RESTAPI_IntServer",4,50,120)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -3160,6 +3206,7 @@ namespace OpenWifi {
|
|||||||
public:
|
public:
|
||||||
inline IntRequestHandlerFactory() = default;
|
inline IntRequestHandlerFactory() = default;
|
||||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override {
|
||||||
|
Utils::SetThreadName(fmt::format("i-rest:{}",TransactionId_).c_str());
|
||||||
Poco::URI uri(Request.getURI());
|
Poco::URI uri(Request.getURI());
|
||||||
return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_);
|
return RESTAPI_IntServer()->CallServer(uri.getPath(), TransactionId_);
|
||||||
}
|
}
|
||||||
@@ -3203,7 +3250,6 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::string Version() { return Version_; }
|
[[nodiscard]] std::string Version() { return Version_; }
|
||||||
// [[nodiscard]] const Poco::SharedPtr<Poco::Crypto::RSAKey> & Key() { return AppKey_; }
|
|
||||||
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
|
[[nodiscard]] inline const std::string & DataDir() { return DataDir_; }
|
||||||
[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; }
|
[[nodiscard]] inline const std::string & WWWAssetsDir() { return WWWAssetsDir_; }
|
||||||
[[nodiscard]] bool Debug() const { return DebugMode_; }
|
[[nodiscard]] bool Debug() const { return DebugMode_; }
|
||||||
@@ -3236,6 +3282,11 @@ namespace OpenWifi {
|
|||||||
return Poco::Logger::get(Name);
|
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 void BusMessageReceived(const std::string &Key, const std::string & Payload);
|
||||||
inline MicroServiceMetaVec GetServices(const std::string & Type);
|
inline MicroServiceMetaVec GetServices(const std::string & Type);
|
||||||
@@ -3272,7 +3323,6 @@ namespace OpenWifi {
|
|||||||
inline std::string ConfigPath(const std::string &Key);
|
inline std::string ConfigPath(const std::string &Key);
|
||||||
inline std::string Encrypt(const std::string &S);
|
inline std::string Encrypt(const std::string &S);
|
||||||
inline std::string Decrypt(const std::string &S);
|
inline std::string Decrypt(const std::string &S);
|
||||||
inline std::string CreateHash(const std::string &S);
|
|
||||||
inline std::string MakeSystemEventMessage( const std::string & Type ) const;
|
inline std::string MakeSystemEventMessage( const std::string & Type ) const;
|
||||||
[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
|
[[nodiscard]] inline bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
|
||||||
inline static void SavePID();
|
inline static void SavePID();
|
||||||
@@ -3302,6 +3352,9 @@ namespace OpenWifi {
|
|||||||
return Signer_.sign(T,Algo);
|
return Signer_.sign(T,Algo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Poco::ThreadPool & TimerPool() { return TimerPool_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static MicroService * instance_;
|
static MicroService * instance_;
|
||||||
bool HelpRequested_ = false;
|
bool HelpRequested_ = false;
|
||||||
@@ -3315,7 +3368,6 @@ namespace OpenWifi {
|
|||||||
std::string WWWAssetsDir_;
|
std::string WWWAssetsDir_;
|
||||||
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
|
Poco::Crypto::CipherFactory & CipherFactory_ = Poco::Crypto::CipherFactory::defaultFactory();
|
||||||
Poco::Crypto::Cipher * Cipher_ = nullptr;
|
Poco::Crypto::Cipher * Cipher_ = nullptr;
|
||||||
Poco::SHA2Engine SHA2_;
|
|
||||||
MicroServiceMetaMap Services_;
|
MicroServiceMetaMap Services_;
|
||||||
std::string MyHash_;
|
std::string MyHash_;
|
||||||
std::string MyPrivateEndPoint_;
|
std::string MyPrivateEndPoint_;
|
||||||
@@ -3336,6 +3388,7 @@ namespace OpenWifi {
|
|||||||
bool NoBuiltInCrypto_=false;
|
bool NoBuiltInCrypto_=false;
|
||||||
Poco::JWT::Signer Signer_;
|
Poco::JWT::Signer Signer_;
|
||||||
Poco::Logger &Logger_;
|
Poco::Logger &Logger_;
|
||||||
|
Poco::ThreadPool TimerPool_{"timer:pool",2,16};
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void MicroService::Exit(int Reason) {
|
inline void MicroService::Exit(int Reason) {
|
||||||
@@ -3485,7 +3538,7 @@ namespace OpenWifi {
|
|||||||
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
|
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
|
||||||
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
|
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
|
||||||
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
|
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
|
||||||
MyHash_ = CreateHash(MyPublicEndPoint_);
|
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroServicePostInitialization();
|
void MicroServicePostInitialization();
|
||||||
@@ -3548,8 +3601,6 @@ namespace OpenWifi {
|
|||||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||||
|
|
||||||
inline void MicroService::initialize(Poco::Util::Application &self) {
|
inline void MicroService::initialize(Poco::Util::Application &self) {
|
||||||
// Utils::SetThreadName("microservice");
|
|
||||||
|
|
||||||
// add the default services
|
// add the default services
|
||||||
LoadConfigurationFile();
|
LoadConfigurationFile();
|
||||||
InitializeLoggingSystem();
|
InitializeLoggingSystem();
|
||||||
@@ -3824,11 +3875,6 @@ namespace OpenWifi {
|
|||||||
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string MicroService::CreateHash(const std::string &S) {
|
|
||||||
SHA2_.update(S);
|
|
||||||
return Utils::ToHex(SHA2_.digest());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
inline std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
||||||
Poco::JSON::Object Obj;
|
Poco::JSON::Object Obj;
|
||||||
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
|
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
|
||||||
@@ -3891,6 +3937,7 @@ namespace OpenWifi {
|
|||||||
Params->setMaxThreads(50);
|
Params->setMaxThreads(50);
|
||||||
Params->setMaxQueued(200);
|
Params->setMaxQueued(200);
|
||||||
Params->setKeepAlive(true);
|
Params->setKeepAlive(true);
|
||||||
|
Params->setName("ws:xrest");
|
||||||
|
|
||||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||||
if(MicroService::instance().NoAPISecurity()) {
|
if(MicroService::instance().NoAPISecurity()) {
|
||||||
@@ -3927,6 +3974,7 @@ namespace OpenWifi {
|
|||||||
Params->setMaxThreads(50);
|
Params->setMaxThreads(50);
|
||||||
Params->setMaxQueued(200);
|
Params->setMaxQueued(200);
|
||||||
Params->setKeepAlive(true);
|
Params->setKeepAlive(true);
|
||||||
|
Params->setName("ws:irest");
|
||||||
|
|
||||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||||
if(MicroService::instance().NoAPISecurity()) {
|
if(MicroService::instance().NoAPISecurity()) {
|
||||||
@@ -3944,8 +3992,6 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline int MicroService::main([[maybe_unused]] const ArgVec &args) {
|
inline int MicroService::main([[maybe_unused]] const ArgVec &args) {
|
||||||
|
|
||||||
// Utils::SetThreadName("main");
|
|
||||||
MyErrorHandler ErrorHandler(*this);
|
MyErrorHandler ErrorHandler(*this);
|
||||||
Poco::ErrorHandler::set(&ErrorHandler);
|
Poco::ErrorHandler::set(&ErrorHandler);
|
||||||
|
|
||||||
@@ -4052,6 +4098,7 @@ namespace OpenWifi {
|
|||||||
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
|
Port_ = (int)MicroService::instance().ConfigGetInt("alb.port",15015);
|
||||||
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
|
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
|
||||||
auto Params = new Poco::Net::HTTPServerParams;
|
auto Params = new Poco::Net::HTTPServerParams;
|
||||||
|
Params->setName("ws:alb");
|
||||||
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
|
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
|
||||||
Server_->start();
|
Server_->start();
|
||||||
}
|
}
|
||||||
@@ -4061,7 +4108,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
inline void BusEventManager::run() {
|
inline void BusEventManager::run() {
|
||||||
Running_ = true;
|
Running_ = true;
|
||||||
Utils::SetThreadName("BusEventManager");
|
Utils::SetThreadName("fmwk:EventMgr");
|
||||||
auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
|
auto Msg = MicroService::instance().MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
|
||||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false);
|
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroService::instance().PrivateEndPoint(),Msg, false);
|
||||||
while(Running_) {
|
while(Running_) {
|
||||||
@@ -4148,7 +4195,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
inline void KafkaProducer::run() {
|
inline void KafkaProducer::run() {
|
||||||
|
|
||||||
Utils::SetThreadName("KafkaProducer");
|
Utils::SetThreadName("Kafka:Prod");
|
||||||
cppkafka::Configuration Config({
|
cppkafka::Configuration Config({
|
||||||
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
||||||
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
|
{ "metadata.broker.list", MicroService::instance().ConfigGetString("openwifi.kafka.brokerlist") }
|
||||||
@@ -4187,7 +4234,7 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline void KafkaConsumer::run() {
|
inline void KafkaConsumer::run() {
|
||||||
Utils::SetThreadName("KafkaConsumer");
|
Utils::SetThreadName("Kafka:Cons");
|
||||||
|
|
||||||
cppkafka::Configuration Config({
|
cppkafka::Configuration Config({
|
||||||
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
{ "client.id", MicroService::instance().ConfigGetString("openwifi.kafka.client.id") },
|
||||||
@@ -4327,6 +4374,11 @@ namespace OpenWifi {
|
|||||||
Answer.set("certificates", Certificates);
|
Answer.set("certificates", Certificates);
|
||||||
return ReturnObject(Answer);
|
return ReturnObject(Answer);
|
||||||
}
|
}
|
||||||
|
if(GetBoolParameter("extraConfiguration")) {
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
MicroService::instance().GetExtraConfiguration(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
BadRequest(RESTAPI::Errors::InvalidCommand);
|
BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4699,6 +4751,7 @@ namespace OpenWifi {
|
|||||||
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
|
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
|
||||||
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
|
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
|
||||||
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
|
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
|
||||||
|
Contacted = true;
|
||||||
if(!Allowed) {
|
if(!Allowed) {
|
||||||
if(Server_.LogBadTokens(false)) {
|
if(Server_.LogBadTokens(false)) {
|
||||||
Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}",
|
Logger_.debug(fmt::format("I-REQ-DENIED({}): Method={} Path={}",
|
||||||
@@ -4707,6 +4760,7 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
|
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
|
||||||
|
REST_Requester_ = Id;
|
||||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||||
Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}",
|
Logger_.debug(fmt::format("I-REQ-ALLOWED({}): User='{}' Method={} Path={}",
|
||||||
Utils::FormatIPv6(Request->clientAddress().toString()), Id,
|
Utils::FormatIPv6(Request->clientAddress().toString()), Id,
|
||||||
@@ -4730,6 +4784,7 @@ namespace OpenWifi {
|
|||||||
#else
|
#else
|
||||||
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) {
|
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Contacted, Sub)) {
|
||||||
#endif
|
#endif
|
||||||
|
REST_Requester_ = UserInfo_.userinfo.email;
|
||||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||||
Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}",
|
Logger_.debug(fmt::format("X-REQ-ALLOWED({}): User='{}@{}' Method={} Path={}",
|
||||||
UserInfo_.userinfo.email,
|
UserInfo_.userinfo.email,
|
||||||
@@ -4812,7 +4867,7 @@ namespace OpenWifi {
|
|||||||
void run() override;
|
void run() override;
|
||||||
// MyParallelSocketReactor &ReactorPool();
|
// MyParallelSocketReactor &ReactorPool();
|
||||||
Poco::Net::SocketReactor & Reactor() { return Reactor_; }
|
Poco::Net::SocketReactor & Reactor() { return Reactor_; }
|
||||||
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id);
|
void NewClient(Poco::Net::WebSocket &WS, const std::string &Id, const std::string &UserName);
|
||||||
bool Register(WebSocketClient *Client, const std::string &Id);
|
bool Register(WebSocketClient *Client, const std::string &Id);
|
||||||
void SetProcessor(WebSocketClientProcessor *F);
|
void SetProcessor(WebSocketClientProcessor *F);
|
||||||
void UnRegister(const std::string &Id);
|
void UnRegister(const std::string &Id);
|
||||||
@@ -4863,7 +4918,10 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
class WebSocketClient {
|
class WebSocketClient {
|
||||||
public:
|
public:
|
||||||
explicit WebSocketClient(Poco::Net::WebSocket &WS, const std::string &Id, Poco::Logger &L,
|
explicit WebSocketClient(Poco::Net::WebSocket &WS,
|
||||||
|
const std::string &Id,
|
||||||
|
const std::string &UserName,
|
||||||
|
Poco::Logger &L,
|
||||||
WebSocketClientProcessor *Processor);
|
WebSocketClientProcessor *Processor);
|
||||||
virtual ~WebSocketClient();
|
virtual ~WebSocketClient();
|
||||||
[[nodiscard]] inline const std::string &Id();
|
[[nodiscard]] inline const std::string &Id();
|
||||||
@@ -4873,8 +4931,9 @@ namespace OpenWifi {
|
|||||||
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
std::unique_ptr<Poco::Net::WebSocket> WS_;
|
||||||
Poco::Net::SocketReactor &Reactor_;
|
Poco::Net::SocketReactor &Reactor_;
|
||||||
std::string Id_;
|
std::string Id_;
|
||||||
|
std::string UserName_;
|
||||||
Poco::Logger &Logger_;
|
Poco::Logger &Logger_;
|
||||||
bool Authenticated_ = false;
|
std::atomic_bool Authenticated_ = false;
|
||||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||||
WebSocketClientProcessor *Processor_ = nullptr;
|
WebSocketClientProcessor *Processor_ = nullptr;
|
||||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification> &pNf);
|
||||||
@@ -4882,33 +4941,9 @@ namespace OpenWifi {
|
|||||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification> &pNf);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* inline MyParallelSocketReactor::MyParallelSocketReactor(uint32_t NumReactors) :
|
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id, const std::string &UserName ) {
|
||||||
NumReactors_(NumReactors)
|
|
||||||
{
|
|
||||||
Reactors_ = new Poco::Net::SocketReactor[NumReactors_];
|
|
||||||
for(uint32_t i=0;i<NumReactors_;i++) {
|
|
||||||
ReactorPool_.start(Reactors_[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline MyParallelSocketReactor::~MyParallelSocketReactor() {
|
|
||||||
for(uint32_t i=0;i<NumReactors_;i++) {
|
|
||||||
Reactors_[i].stop();
|
|
||||||
}
|
|
||||||
ReactorPool_.stopAll();
|
|
||||||
ReactorPool_.joinAll();
|
|
||||||
delete [] Reactors_;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Poco::Net::SocketReactor & MyParallelSocketReactor::Reactor() {
|
|
||||||
return Reactors_[ rand() % NumReactors_ ];
|
|
||||||
}
|
|
||||||
|
|
||||||
// inline MyParallelSocketReactor & WebSocketClientServer::ReactorPool() { return *ReactorPool_; }
|
|
||||||
*/
|
|
||||||
inline void WebSocketClientServer::NewClient(Poco::Net::WebSocket & WS, const std::string &Id) {
|
|
||||||
std::lock_guard G(Mutex_);
|
std::lock_guard G(Mutex_);
|
||||||
auto Client = new WebSocketClient(WS,Id,Logger(), Processor_);
|
auto Client = new WebSocketClient(WS,Id,UserName,Logger(), Processor_);
|
||||||
Clients_[Id] = std::make_pair(Client,"");
|
Clients_[Id] = std::make_pair(Client,"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4938,13 +4973,13 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
[[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload);
|
[[nodiscard]] inline bool SendToUser(const std::string &userName, const std::string &Payload);
|
||||||
inline WebSocketClientServer::WebSocketClientServer() noexcept:
|
inline WebSocketClientServer::WebSocketClientServer() noexcept:
|
||||||
SubSystemServer("WebSocketClientServer", "WSCLNT-SVR", "websocketclients")
|
SubSystemServer("WebSocketClientServer", "UI-WSCLNT-SVR", "websocketclients")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void WebSocketClientServer::run() {
|
inline void WebSocketClientServer::run() {
|
||||||
Running_ = true ;
|
Running_ = true ;
|
||||||
Utils::SetThreadName("ws:clnt-svr");
|
Utils::SetThreadName("ws:uiclnt-svr");
|
||||||
while(Running_) {
|
while(Running_) {
|
||||||
Poco::Thread::trySleep(2000);
|
Poco::Thread::trySleep(2000);
|
||||||
|
|
||||||
@@ -5025,6 +5060,7 @@ namespace OpenWifi {
|
|||||||
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
auto Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||||
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
|
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||||
return delete this;
|
return delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5037,7 +5073,7 @@ namespace OpenWifi {
|
|||||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||||
} break;
|
} break;
|
||||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||||
Logger().warning(Poco::format("CLOSE(%s): Client is closing its connection.", Id_));
|
Logger().warning(Poco::format("CLOSE(%s): %s UI Client is closing WS connection.", Id_, UserName_));
|
||||||
Done = true;
|
Done = true;
|
||||||
} break;
|
} break;
|
||||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||||
@@ -5049,6 +5085,8 @@ namespace OpenWifi {
|
|||||||
if (Tokens.size() == 2 &&
|
if (Tokens.size() == 2 &&
|
||||||
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
AuthClient()->IsAuthorized(Tokens[1], UserInfo_, Expired, Contacted)) {
|
||||||
Authenticated_ = true;
|
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!"};
|
std::string S{"Welcome! Bienvenue! Bienvenidos!"};
|
||||||
WS_->sendFrame(S.c_str(), S.size());
|
WS_->sendFrame(S.c_str(), S.size());
|
||||||
WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email);
|
WebSocketClientServer()->SetUser(Id_, UserInfo_.userinfo.email);
|
||||||
@@ -5094,9 +5132,10 @@ namespace OpenWifi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
inline WebSocketClient::WebSocketClient( Poco::Net::WebSocket & WS , const std::string &Id, const std::string &UserName, Poco::Logger & L, WebSocketClientProcessor * Processor) :
|
||||||
Reactor_(WebSocketClientServer()->Reactor()),
|
Reactor_(WebSocketClientServer()->Reactor()),
|
||||||
Id_(Id),
|
Id_(Id),
|
||||||
|
UserName_(UserName),
|
||||||
Logger_(L),
|
Logger_(L),
|
||||||
Processor_(Processor) {
|
Processor_(Processor) {
|
||||||
try {
|
try {
|
||||||
@@ -5176,9 +5215,8 @@ namespace OpenWifi {
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
Poco::Net::WebSocket WS(*Request, *Response);
|
Poco::Net::WebSocket WS(*Request, *Response);
|
||||||
Logger().information("WebSocket connection established.");
|
|
||||||
auto Id = MicroService::CreateUUID();
|
auto Id = MicroService::CreateUUID();
|
||||||
WebSocketClientServer()->NewClient(WS,Id);
|
WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email);
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
std::cout << "Cannot create websocket client..." << std::endl;
|
std::cout << "Cannot create websocket client..." << std::endl;
|
||||||
|
|||||||
@@ -146,6 +146,10 @@ namespace OpenWifi {
|
|||||||
WebSocketClientServer()->SendUserNotification(User,N);
|
WebSocketClientServer()->SendUserNotification(User,N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////
|
||||||
|
/////
|
||||||
|
/////
|
||||||
|
|
||||||
struct WebSocketNotificationRebootList {
|
struct WebSocketNotificationRebootList {
|
||||||
std::string title,
|
std::string title,
|
||||||
details,
|
details,
|
||||||
@@ -189,5 +193,58 @@ namespace OpenWifi {
|
|||||||
WebSocketClientServer()->SendUserNotification(User,N);
|
WebSocketClientServer()->SendUserNotification(User,N);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////
|
||||||
|
/////
|
||||||
|
/////
|
||||||
|
|
||||||
|
struct WebSocketNotificationUpgradeList {
|
||||||
|
std::string title,
|
||||||
|
details,
|
||||||
|
jobId;
|
||||||
|
std::vector<std::string> success,
|
||||||
|
skipped,
|
||||||
|
no_firmware,
|
||||||
|
not_connected;
|
||||||
|
uint64_t timeStamp=OpenWifi::Now();
|
||||||
|
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t;
|
||||||
|
|
||||||
|
inline void WebSocketNotificationUpgradeList::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"title",title);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"jobId",jobId);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"success",success);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"notConnected",not_connected);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"skipped",skipped);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp);
|
||||||
|
RESTAPI_utils::field_to_json(Obj,"details",details);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool WebSocketNotificationUpgradeList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
try {
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"title",title);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"jobId",jobId);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"success",success);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"notConnected",not_connected);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"skipped",skipped);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp);
|
||||||
|
RESTAPI_utils::field_from_json(Obj,"details",details);
|
||||||
|
return true;
|
||||||
|
} catch(...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) {
|
||||||
|
N.type = "venue_upgrader";
|
||||||
|
WebSocketClientServer()->SendUserNotification(User,N);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace OpenWifi
|
} // namespace OpenWifi
|
||||||
|
|
||||||
|
|||||||
937
src/libs/croncpp.h
Normal file
937
src/libs/croncpp.h
Normal file
@@ -0,0 +1,937 @@
|
|||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Marius Bancila
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
This file is from https://github.com/mariusbancila/croncpp.git.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <bitset>
|
||||||
|
#include <cctype>
|
||||||
|
#include <ctime>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#if __cplusplus > 201402L
|
||||||
|
#include <string_view>
|
||||||
|
#define CRONCPP_IS_CPP17
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace cron
|
||||||
|
{
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
#define CRONCPP_STRING_VIEW std::string_view
|
||||||
|
#define CRONCPP_STRING_VIEW_NPOS std::string_view::npos
|
||||||
|
#define CRONCPP_CONSTEXPTR constexpr
|
||||||
|
#else
|
||||||
|
#define CRONCPP_STRING_VIEW std::string const &
|
||||||
|
#define CRONCPP_STRING_VIEW_NPOS std::string::npos
|
||||||
|
#define CRONCPP_CONSTEXPTR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using cron_int = uint8_t;
|
||||||
|
|
||||||
|
constexpr std::time_t INVALID_TIME = static_cast<std::time_t>(-1);
|
||||||
|
|
||||||
|
constexpr size_t INVALID_INDEX = static_cast<size_t>(-1);
|
||||||
|
|
||||||
|
class cronexpr;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
enum class cron_field
|
||||||
|
{
|
||||||
|
second,
|
||||||
|
minute,
|
||||||
|
hour_of_day,
|
||||||
|
day_of_week,
|
||||||
|
day_of_month,
|
||||||
|
month,
|
||||||
|
year
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static bool find_next(cronexpr const & cex,
|
||||||
|
std::tm& date,
|
||||||
|
size_t const dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bad_cronexpr : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit bad_cronexpr(CRONCPP_STRING_VIEW message) :
|
||||||
|
std::runtime_error(message.data())
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct cron_standard_traits
|
||||||
|
{
|
||||||
|
static const cron_int CRON_MIN_SECONDS = 0;
|
||||||
|
static const cron_int CRON_MAX_SECONDS = 59;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_MINUTES = 0;
|
||||||
|
static const cron_int CRON_MAX_MINUTES = 59;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_HOURS = 0;
|
||||||
|
static const cron_int CRON_MAX_HOURS = 23;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_DAYS_OF_WEEK = 0;
|
||||||
|
static const cron_int CRON_MAX_DAYS_OF_WEEK = 6;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
|
||||||
|
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_MONTHS = 1;
|
||||||
|
static const cron_int CRON_MAX_MONTHS = 12;
|
||||||
|
|
||||||
|
static const cron_int CRON_MAX_YEARS_DIFF = 4;
|
||||||
|
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
static const inline std::vector<std::string> DAYS = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||||
|
static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||||
|
#else
|
||||||
|
static std::vector<std::string>& DAYS()
|
||||||
|
{
|
||||||
|
static std::vector<std::string> days = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string>& MONTHS()
|
||||||
|
{
|
||||||
|
static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||||
|
return months;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cron_oracle_traits
|
||||||
|
{
|
||||||
|
static const cron_int CRON_MIN_SECONDS = 0;
|
||||||
|
static const cron_int CRON_MAX_SECONDS = 59;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_MINUTES = 0;
|
||||||
|
static const cron_int CRON_MAX_MINUTES = 59;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_HOURS = 0;
|
||||||
|
static const cron_int CRON_MAX_HOURS = 23;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
|
||||||
|
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
|
||||||
|
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_MONTHS = 0;
|
||||||
|
static const cron_int CRON_MAX_MONTHS = 11;
|
||||||
|
|
||||||
|
static const cron_int CRON_MAX_YEARS_DIFF = 4;
|
||||||
|
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||||
|
static const inline std::vector<std::string> MONTHS = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||||
|
#else
|
||||||
|
|
||||||
|
static std::vector<std::string>& DAYS()
|
||||||
|
{
|
||||||
|
static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string>& MONTHS()
|
||||||
|
{
|
||||||
|
static std::vector<std::string> months = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||||
|
return months;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cron_quartz_traits
|
||||||
|
{
|
||||||
|
static const cron_int CRON_MIN_SECONDS = 0;
|
||||||
|
static const cron_int CRON_MAX_SECONDS = 59;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_MINUTES = 0;
|
||||||
|
static const cron_int CRON_MAX_MINUTES = 59;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_HOURS = 0;
|
||||||
|
static const cron_int CRON_MAX_HOURS = 23;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_DAYS_OF_WEEK = 1;
|
||||||
|
static const cron_int CRON_MAX_DAYS_OF_WEEK = 7;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_DAYS_OF_MONTH = 1;
|
||||||
|
static const cron_int CRON_MAX_DAYS_OF_MONTH = 31;
|
||||||
|
|
||||||
|
static const cron_int CRON_MIN_MONTHS = 1;
|
||||||
|
static const cron_int CRON_MAX_MONTHS = 12;
|
||||||
|
|
||||||
|
static const cron_int CRON_MAX_YEARS_DIFF = 4;
|
||||||
|
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||||
|
static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||||
|
#else
|
||||||
|
static std::vector<std::string>& DAYS()
|
||||||
|
{
|
||||||
|
static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string>& MONTHS()
|
||||||
|
{
|
||||||
|
static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
|
||||||
|
return months;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class cronexpr;
|
||||||
|
|
||||||
|
template <typename Traits = cron_standard_traits>
|
||||||
|
static cronexpr make_cron(CRONCPP_STRING_VIEW expr);
|
||||||
|
|
||||||
|
class cronexpr
|
||||||
|
{
|
||||||
|
std::bitset<60> seconds;
|
||||||
|
std::bitset<60> minutes;
|
||||||
|
std::bitset<24> hours;
|
||||||
|
std::bitset<7> days_of_week;
|
||||||
|
std::bitset<31> days_of_month;
|
||||||
|
std::bitset<12> months;
|
||||||
|
std::string expr;
|
||||||
|
|
||||||
|
friend bool operator==(cronexpr const & e1, cronexpr const & e2);
|
||||||
|
friend bool operator!=(cronexpr const & e1, cronexpr const & e2);
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
friend bool detail::find_next(cronexpr const & cex,
|
||||||
|
std::tm& date,
|
||||||
|
size_t const dot);
|
||||||
|
|
||||||
|
friend std::string to_cronstr(cronexpr const& cex);
|
||||||
|
friend std::string to_string(cronexpr const & cex);
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
friend cronexpr make_cron(CRONCPP_STRING_VIEW expr);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(cronexpr const & e1, cronexpr const & e2)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
e1.seconds == e2.seconds &&
|
||||||
|
e1.minutes == e2.minutes &&
|
||||||
|
e1.hours == e2.hours &&
|
||||||
|
e1.days_of_week == e2.days_of_week &&
|
||||||
|
e1.days_of_month == e2.days_of_month &&
|
||||||
|
e1.months == e2.months;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(cronexpr const & e1, cronexpr const & e2)
|
||||||
|
{
|
||||||
|
return !(e1 == e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_string(cronexpr const & cex)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
cex.seconds.to_string() + " " +
|
||||||
|
cex.minutes.to_string() + " " +
|
||||||
|
cex.hours.to_string() + " " +
|
||||||
|
cex.days_of_month.to_string() + " " +
|
||||||
|
cex.months.to_string() + " " +
|
||||||
|
cex.days_of_week.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_cronstr(cronexpr const& cex)
|
||||||
|
{
|
||||||
|
return cex.expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
inline std::time_t tm_to_time(std::tm& date)
|
||||||
|
{
|
||||||
|
return std::mktime(&date);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::tm* time_to_tm(std::time_t const * date, std::tm* const out)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
errno_t err = localtime_s(out, date);
|
||||||
|
return 0 == err ? out : nullptr;
|
||||||
|
#else
|
||||||
|
return localtime_r(date, out);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::tm to_tm(CRONCPP_STRING_VIEW time)
|
||||||
|
{
|
||||||
|
std::tm result;
|
||||||
|
#if __cplusplus > 201103L
|
||||||
|
std::istringstream str(time.data());
|
||||||
|
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||||
|
|
||||||
|
str >> std::get_time(&result, "%Y-%m-%d %H:%M:%S");
|
||||||
|
if (str.fail()) throw std::runtime_error("Parsing date failed!");
|
||||||
|
#else
|
||||||
|
int year = 1900;
|
||||||
|
int month = 1;
|
||||||
|
int day = 1;
|
||||||
|
int hour = 0;
|
||||||
|
int minute = 0;
|
||||||
|
int second = 0;
|
||||||
|
sscanf(time.data(), "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
|
||||||
|
result.tm_year = year - 1900;
|
||||||
|
result.tm_mon = month - 1;
|
||||||
|
result.tm_mday = day;
|
||||||
|
result.tm_hour = hour;
|
||||||
|
result.tm_min = minute;
|
||||||
|
result.tm_sec = second;
|
||||||
|
#endif
|
||||||
|
result.tm_isdst = -1; // DST info not available
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_string(std::tm const & tm)
|
||||||
|
{
|
||||||
|
#if __cplusplus > 201103L
|
||||||
|
std::ostringstream str;
|
||||||
|
str.imbue(std::locale(setlocale(LC_ALL, nullptr)));
|
||||||
|
str << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
|
||||||
|
if (str.fail()) throw std::runtime_error("Writing date failed!");
|
||||||
|
|
||||||
|
return str.str();
|
||||||
|
#else
|
||||||
|
char buff[70] = {0};
|
||||||
|
strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm);
|
||||||
|
return std::string(buff);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_upper(std::string text)
|
||||||
|
{
|
||||||
|
std::transform(std::begin(text), std::end(text),
|
||||||
|
std::begin(text), [](char const c) { return static_cast<char>(std::toupper(c)); });
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> split(CRONCPP_STRING_VIEW text, char const delimiter)
|
||||||
|
{
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
std::string token;
|
||||||
|
std::istringstream tokenStream(text.data());
|
||||||
|
while (std::getline(tokenStream, token, delimiter))
|
||||||
|
{
|
||||||
|
tokens.push_back(token);
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRONCPP_CONSTEXPTR inline bool contains(CRONCPP_STRING_VIEW text, char const ch) noexcept
|
||||||
|
{
|
||||||
|
return CRONCPP_STRING_VIEW_NPOS != text.find_first_of(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
inline cron_int to_cron_int(CRONCPP_STRING_VIEW text)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return static_cast<cron_int>(std::stoul(text.data()));
|
||||||
|
}
|
||||||
|
catch (std::exception const & ex)
|
||||||
|
{
|
||||||
|
throw bad_cronexpr(ex.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string replace_ordinals(
|
||||||
|
std::string text,
|
||||||
|
std::vector<std::string> const & replacement)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < replacement.size(); ++i)
|
||||||
|
{
|
||||||
|
auto pos = text.find(replacement[i]);
|
||||||
|
if (std::string::npos != pos)
|
||||||
|
text.replace(pos, 3 ,std::to_string(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<cron_int, cron_int> make_range(
|
||||||
|
CRONCPP_STRING_VIEW field,
|
||||||
|
cron_int const minval,
|
||||||
|
cron_int const maxval)
|
||||||
|
{
|
||||||
|
cron_int first = 0;
|
||||||
|
cron_int last = 0;
|
||||||
|
if (field.size() == 1 && field[0] == '*')
|
||||||
|
{
|
||||||
|
first = minval;
|
||||||
|
last = maxval;
|
||||||
|
}
|
||||||
|
else if (!utils::contains(field, '-'))
|
||||||
|
{
|
||||||
|
first = to_cron_int(field);
|
||||||
|
last = first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto parts = utils::split(field, '-');
|
||||||
|
if (parts.size() != 2)
|
||||||
|
throw bad_cronexpr("Specified range requires two fields");
|
||||||
|
|
||||||
|
first = to_cron_int(parts[0]);
|
||||||
|
last = to_cron_int(parts[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first > maxval || last > maxval)
|
||||||
|
{
|
||||||
|
throw bad_cronexpr("Specified range exceeds maximum");
|
||||||
|
}
|
||||||
|
if (first < minval || last < minval)
|
||||||
|
{
|
||||||
|
throw bad_cronexpr("Specified range is less than minimum");
|
||||||
|
}
|
||||||
|
if (first > last)
|
||||||
|
{
|
||||||
|
throw bad_cronexpr("Specified range start exceeds range end");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { first, last };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
static void set_cron_field(
|
||||||
|
CRONCPP_STRING_VIEW value,
|
||||||
|
std::bitset<N>& target,
|
||||||
|
cron_int const minval,
|
||||||
|
cron_int const maxval)
|
||||||
|
{
|
||||||
|
if(value.length() > 0 && value[value.length()-1] == ',')
|
||||||
|
throw bad_cronexpr("Value cannot end with comma");
|
||||||
|
|
||||||
|
auto fields = utils::split(value, ',');
|
||||||
|
if (fields.empty())
|
||||||
|
throw bad_cronexpr("Expression parsing error");
|
||||||
|
|
||||||
|
for (auto const & field : fields)
|
||||||
|
{
|
||||||
|
if (!utils::contains(field, '/'))
|
||||||
|
{
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
auto[first, last] = detail::make_range(field, minval, maxval);
|
||||||
|
#else
|
||||||
|
auto range = detail::make_range(field, minval, maxval);
|
||||||
|
auto first = range.first;
|
||||||
|
auto last = range.second;
|
||||||
|
#endif
|
||||||
|
for (cron_int i = first - minval; i <= last - minval; ++i)
|
||||||
|
{
|
||||||
|
target.set(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto parts = utils::split(field, '/');
|
||||||
|
if (parts.size() != 2)
|
||||||
|
throw bad_cronexpr("Incrementer must have two fields");
|
||||||
|
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
auto[first, last] = detail::make_range(parts[0], minval, maxval);
|
||||||
|
#else
|
||||||
|
auto range = detail::make_range(parts[0], minval, maxval);
|
||||||
|
auto first = range.first;
|
||||||
|
auto last = range.second;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!utils::contains(parts[0], '-'))
|
||||||
|
{
|
||||||
|
last = maxval;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto delta = detail::to_cron_int(parts[1]);
|
||||||
|
if(delta <= 0)
|
||||||
|
throw bad_cronexpr("Incrementer must be a positive value");
|
||||||
|
|
||||||
|
for (cron_int i = first - minval; i <= last - minval; i += delta)
|
||||||
|
{
|
||||||
|
target.set(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static void set_cron_days_of_week(
|
||||||
|
std::string value,
|
||||||
|
std::bitset<7>& target)
|
||||||
|
{
|
||||||
|
auto days = utils::to_upper(value);
|
||||||
|
auto days_replaced = detail::replace_ordinals(
|
||||||
|
days,
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
Traits::DAYS
|
||||||
|
#else
|
||||||
|
Traits::DAYS()
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
if (days_replaced.size() == 1 && days_replaced[0] == '?')
|
||||||
|
days_replaced[0] = '*';
|
||||||
|
|
||||||
|
set_cron_field(
|
||||||
|
days_replaced,
|
||||||
|
target,
|
||||||
|
Traits::CRON_MIN_DAYS_OF_WEEK,
|
||||||
|
Traits::CRON_MAX_DAYS_OF_WEEK);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static void set_cron_days_of_month(
|
||||||
|
std::string value,
|
||||||
|
std::bitset<31>& target)
|
||||||
|
{
|
||||||
|
if (value.size() == 1 && value[0] == '?')
|
||||||
|
value[0] = '*';
|
||||||
|
|
||||||
|
set_cron_field(
|
||||||
|
value,
|
||||||
|
target,
|
||||||
|
Traits::CRON_MIN_DAYS_OF_MONTH,
|
||||||
|
Traits::CRON_MAX_DAYS_OF_MONTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static void set_cron_month(
|
||||||
|
std::string value,
|
||||||
|
std::bitset<12>& target)
|
||||||
|
{
|
||||||
|
auto month = utils::to_upper(value);
|
||||||
|
auto month_replaced = replace_ordinals(
|
||||||
|
month,
|
||||||
|
#ifdef CRONCPP_IS_CPP17
|
||||||
|
Traits::MONTHS
|
||||||
|
#else
|
||||||
|
Traits::MONTHS()
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
set_cron_field(
|
||||||
|
month_replaced,
|
||||||
|
target,
|
||||||
|
Traits::CRON_MIN_MONTHS,
|
||||||
|
Traits::CRON_MAX_MONTHS);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
inline size_t next_set_bit(
|
||||||
|
std::bitset<N> const & target,
|
||||||
|
size_t /*minimum*/,
|
||||||
|
size_t /*maximum*/,
|
||||||
|
size_t offset)
|
||||||
|
{
|
||||||
|
for (auto i = offset; i < N; ++i)
|
||||||
|
{
|
||||||
|
if (target.test(i)) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_to_field(
|
||||||
|
std::tm& date,
|
||||||
|
cron_field const field,
|
||||||
|
int const val)
|
||||||
|
{
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case cron_field::second:
|
||||||
|
date.tm_sec += val;
|
||||||
|
break;
|
||||||
|
case cron_field::minute:
|
||||||
|
date.tm_min += val;
|
||||||
|
break;
|
||||||
|
case cron_field::hour_of_day:
|
||||||
|
date.tm_hour += val;
|
||||||
|
break;
|
||||||
|
case cron_field::day_of_week:
|
||||||
|
case cron_field::day_of_month:
|
||||||
|
date.tm_mday += val;
|
||||||
|
break;
|
||||||
|
case cron_field::month:
|
||||||
|
date.tm_mon += val;
|
||||||
|
break;
|
||||||
|
case cron_field::year:
|
||||||
|
date.tm_year += val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INVALID_TIME == utils::tm_to_time(date))
|
||||||
|
throw bad_cronexpr("Invalid time expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void set_field(
|
||||||
|
std::tm& date,
|
||||||
|
cron_field const field,
|
||||||
|
int const val)
|
||||||
|
{
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case cron_field::second:
|
||||||
|
date.tm_sec = val;
|
||||||
|
break;
|
||||||
|
case cron_field::minute:
|
||||||
|
date.tm_min = val;
|
||||||
|
break;
|
||||||
|
case cron_field::hour_of_day:
|
||||||
|
date.tm_hour = val;
|
||||||
|
break;
|
||||||
|
case cron_field::day_of_week:
|
||||||
|
date.tm_wday = val;
|
||||||
|
break;
|
||||||
|
case cron_field::day_of_month:
|
||||||
|
date.tm_mday = val;
|
||||||
|
break;
|
||||||
|
case cron_field::month:
|
||||||
|
date.tm_mon = val;
|
||||||
|
break;
|
||||||
|
case cron_field::year:
|
||||||
|
date.tm_year = val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INVALID_TIME == utils::tm_to_time(date))
|
||||||
|
throw bad_cronexpr("Invalid time expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void reset_field(
|
||||||
|
std::tm& date,
|
||||||
|
cron_field const field)
|
||||||
|
{
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case cron_field::second:
|
||||||
|
date.tm_sec = 0;
|
||||||
|
break;
|
||||||
|
case cron_field::minute:
|
||||||
|
date.tm_min = 0;
|
||||||
|
break;
|
||||||
|
case cron_field::hour_of_day:
|
||||||
|
date.tm_hour = 0;
|
||||||
|
break;
|
||||||
|
case cron_field::day_of_week:
|
||||||
|
date.tm_wday = 0;
|
||||||
|
break;
|
||||||
|
case cron_field::day_of_month:
|
||||||
|
date.tm_mday = 1;
|
||||||
|
break;
|
||||||
|
case cron_field::month:
|
||||||
|
date.tm_mon = 0;
|
||||||
|
break;
|
||||||
|
case cron_field::year:
|
||||||
|
date.tm_year = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INVALID_TIME == utils::tm_to_time(date))
|
||||||
|
throw bad_cronexpr("Invalid time expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void reset_all_fields(
|
||||||
|
std::tm& date,
|
||||||
|
std::bitset<7> const & marked_fields)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < marked_fields.size(); ++i)
|
||||||
|
{
|
||||||
|
if (marked_fields.test(i))
|
||||||
|
reset_field(date, static_cast<cron_field>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void mark_field(
|
||||||
|
std::bitset<7> & orders,
|
||||||
|
cron_field const field)
|
||||||
|
{
|
||||||
|
if (!orders.test(static_cast<size_t>(field)))
|
||||||
|
orders.set(static_cast<size_t>(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
static size_t find_next(
|
||||||
|
std::bitset<N> const & target,
|
||||||
|
std::tm& date,
|
||||||
|
unsigned int const minimum,
|
||||||
|
unsigned int const maximum,
|
||||||
|
unsigned int const value,
|
||||||
|
cron_field const field,
|
||||||
|
cron_field const next_field,
|
||||||
|
std::bitset<7> const & marked_fields)
|
||||||
|
{
|
||||||
|
auto next_value = next_set_bit(target, minimum, maximum, value);
|
||||||
|
if (INVALID_INDEX == next_value)
|
||||||
|
{
|
||||||
|
add_to_field(date, next_field, 1);
|
||||||
|
reset_field(date, field);
|
||||||
|
next_value = next_set_bit(target, minimum, maximum, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (INVALID_INDEX == next_value || next_value != value)
|
||||||
|
{
|
||||||
|
set_field(date, field, static_cast<int>(next_value));
|
||||||
|
reset_all_fields(date, marked_fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static size_t find_next_day(
|
||||||
|
std::tm& date,
|
||||||
|
std::bitset<31> const & days_of_month,
|
||||||
|
size_t day_of_month,
|
||||||
|
std::bitset<7> const & days_of_week,
|
||||||
|
size_t day_of_week,
|
||||||
|
std::bitset<7> const & marked_fields)
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
unsigned int maximum = 366;
|
||||||
|
while (
|
||||||
|
(!days_of_month.test(day_of_month - Traits::CRON_MIN_DAYS_OF_MONTH) ||
|
||||||
|
!days_of_week.test(day_of_week - Traits::CRON_MIN_DAYS_OF_WEEK))
|
||||||
|
&& count++ < maximum)
|
||||||
|
{
|
||||||
|
add_to_field(date, cron_field::day_of_month, 1);
|
||||||
|
|
||||||
|
day_of_month = date.tm_mday;
|
||||||
|
day_of_week = date.tm_wday;
|
||||||
|
|
||||||
|
reset_all_fields(date, marked_fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
return day_of_month;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static bool find_next(cronexpr const & cex,
|
||||||
|
std::tm& date,
|
||||||
|
size_t const dot)
|
||||||
|
{
|
||||||
|
bool res = true;
|
||||||
|
|
||||||
|
std::bitset<7> marked_fields{ 0 };
|
||||||
|
std::bitset<7> empty_list{ 0 };
|
||||||
|
|
||||||
|
unsigned int second = date.tm_sec;
|
||||||
|
auto updated_second = find_next(
|
||||||
|
cex.seconds,
|
||||||
|
date,
|
||||||
|
Traits::CRON_MIN_SECONDS,
|
||||||
|
Traits::CRON_MAX_SECONDS,
|
||||||
|
second,
|
||||||
|
cron_field::second,
|
||||||
|
cron_field::minute,
|
||||||
|
empty_list);
|
||||||
|
|
||||||
|
if (second == updated_second)
|
||||||
|
{
|
||||||
|
mark_field(marked_fields, cron_field::second);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int minute = date.tm_min;
|
||||||
|
auto update_minute = find_next(
|
||||||
|
cex.minutes,
|
||||||
|
date,
|
||||||
|
Traits::CRON_MIN_MINUTES,
|
||||||
|
Traits::CRON_MAX_MINUTES,
|
||||||
|
minute,
|
||||||
|
cron_field::minute,
|
||||||
|
cron_field::hour_of_day,
|
||||||
|
marked_fields);
|
||||||
|
if (minute == update_minute)
|
||||||
|
{
|
||||||
|
mark_field(marked_fields, cron_field::minute);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = find_next<Traits>(cex, date, dot);
|
||||||
|
if (!res) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int hour = date.tm_hour;
|
||||||
|
auto updated_hour = find_next(
|
||||||
|
cex.hours,
|
||||||
|
date,
|
||||||
|
Traits::CRON_MIN_HOURS,
|
||||||
|
Traits::CRON_MAX_HOURS,
|
||||||
|
hour,
|
||||||
|
cron_field::hour_of_day,
|
||||||
|
cron_field::day_of_week,
|
||||||
|
marked_fields);
|
||||||
|
if (hour == updated_hour)
|
||||||
|
{
|
||||||
|
mark_field(marked_fields, cron_field::hour_of_day);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = find_next<Traits>(cex, date, dot);
|
||||||
|
if (!res) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int day_of_week = date.tm_wday;
|
||||||
|
unsigned int day_of_month = date.tm_mday;
|
||||||
|
auto updated_day_of_month = find_next_day<Traits>(
|
||||||
|
date,
|
||||||
|
cex.days_of_month,
|
||||||
|
day_of_month,
|
||||||
|
cex.days_of_week,
|
||||||
|
day_of_week,
|
||||||
|
marked_fields);
|
||||||
|
if (day_of_month == updated_day_of_month)
|
||||||
|
{
|
||||||
|
mark_field(marked_fields, cron_field::day_of_month);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = find_next<Traits>(cex, date, dot);
|
||||||
|
if (!res) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int month = date.tm_mon;
|
||||||
|
auto updated_month = find_next(
|
||||||
|
cex.months,
|
||||||
|
date,
|
||||||
|
Traits::CRON_MIN_MONTHS,
|
||||||
|
Traits::CRON_MAX_MONTHS,
|
||||||
|
month,
|
||||||
|
cron_field::month,
|
||||||
|
cron_field::year,
|
||||||
|
marked_fields);
|
||||||
|
if (month != updated_month)
|
||||||
|
{
|
||||||
|
if (date.tm_year - dot > Traits::CRON_MAX_YEARS_DIFF)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
res = find_next<Traits>(cex, date, dot);
|
||||||
|
if (!res) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits>
|
||||||
|
static cronexpr make_cron(CRONCPP_STRING_VIEW expr)
|
||||||
|
{
|
||||||
|
cronexpr cex;
|
||||||
|
|
||||||
|
if (expr.empty())
|
||||||
|
throw bad_cronexpr("Invalid empty cron expression");
|
||||||
|
|
||||||
|
auto fields = utils::split(expr, ' ');
|
||||||
|
fields.erase(
|
||||||
|
std::remove_if(std::begin(fields), std::end(fields),
|
||||||
|
[](CRONCPP_STRING_VIEW s) {return s.empty(); }),
|
||||||
|
std::end(fields));
|
||||||
|
if (fields.size() != 6)
|
||||||
|
throw bad_cronexpr("cron expression must have six fields");
|
||||||
|
|
||||||
|
detail::set_cron_field(fields[0], cex.seconds, Traits::CRON_MIN_SECONDS, Traits::CRON_MAX_SECONDS);
|
||||||
|
detail::set_cron_field(fields[1], cex.minutes, Traits::CRON_MIN_MINUTES, Traits::CRON_MAX_MINUTES);
|
||||||
|
detail::set_cron_field(fields[2], cex.hours, Traits::CRON_MIN_HOURS, Traits::CRON_MAX_HOURS);
|
||||||
|
|
||||||
|
detail::set_cron_days_of_week<Traits>(fields[5], cex.days_of_week);
|
||||||
|
|
||||||
|
detail::set_cron_days_of_month<Traits>(fields[3], cex.days_of_month);
|
||||||
|
|
||||||
|
detail::set_cron_month<Traits>(fields[4], cex.months);
|
||||||
|
|
||||||
|
cex.expr = expr;
|
||||||
|
|
||||||
|
return cex;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits = cron_standard_traits>
|
||||||
|
static std::tm cron_next(cronexpr const & cex, std::tm date)
|
||||||
|
{
|
||||||
|
time_t original = utils::tm_to_time(date);
|
||||||
|
if (INVALID_TIME == original) return {};
|
||||||
|
|
||||||
|
if (!detail::find_next<Traits>(cex, date, date.tm_year))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
time_t calculated = utils::tm_to_time(date);
|
||||||
|
if (INVALID_TIME == calculated) return {};
|
||||||
|
|
||||||
|
if (calculated == original)
|
||||||
|
{
|
||||||
|
add_to_field(date, detail::cron_field::second, 1);
|
||||||
|
if (!detail::find_next<Traits>(cex, date, date.tm_year))
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits = cron_standard_traits>
|
||||||
|
static std::time_t cron_next(cronexpr const & cex, std::time_t const & date)
|
||||||
|
{
|
||||||
|
std::tm val;
|
||||||
|
std::tm* dt = utils::time_to_tm(&date, &val);
|
||||||
|
if (dt == nullptr) return INVALID_TIME;
|
||||||
|
|
||||||
|
time_t original = utils::tm_to_time(*dt);
|
||||||
|
if (INVALID_TIME == original) return INVALID_TIME;
|
||||||
|
|
||||||
|
if(!detail::find_next<Traits>(cex, *dt, dt->tm_year))
|
||||||
|
return INVALID_TIME;
|
||||||
|
|
||||||
|
time_t calculated = utils::tm_to_time(*dt);
|
||||||
|
if (INVALID_TIME == calculated) return calculated;
|
||||||
|
|
||||||
|
if (calculated == original)
|
||||||
|
{
|
||||||
|
add_to_field(*dt, detail::cron_field::second, 1);
|
||||||
|
if(!detail::find_next<Traits>(cex, *dt, dt->tm_year))
|
||||||
|
return INVALID_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::tm_to_time(*dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Traits = cron_standard_traits>
|
||||||
|
static std::chrono::system_clock::time_point cron_next(cronexpr const & cex, std::chrono::system_clock::time_point const & time_point) {
|
||||||
|
return std::chrono::system_clock::from_time_t(cron_next<Traits>(cex, std::chrono::system_clock::to_time_t(time_point)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,12 +83,13 @@ namespace OpenWifi {
|
|||||||
InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
|
InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
|
||||||
DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {}
|
DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {}
|
||||||
|
|
||||||
bool InventoryDB::CreateFromConnection( const std::string &SerialNumber,
|
bool InventoryDB::CreateFromConnection( const std::string &SerialNumberRaw,
|
||||||
const std::string &ConnectionInfo,
|
const std::string &ConnectionInfo,
|
||||||
const std::string &DeviceType,
|
const std::string &DeviceType,
|
||||||
const std::string &Locale) {
|
const std::string &Locale) {
|
||||||
|
|
||||||
ProvObjects::InventoryTag ExistingDevice;
|
ProvObjects::InventoryTag ExistingDevice;
|
||||||
|
auto SerialNumber = Poco::toLower(SerialNumberRaw);
|
||||||
if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) {
|
if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) {
|
||||||
ProvObjects::InventoryTag NewDevice;
|
ProvObjects::InventoryTag NewDevice;
|
||||||
uint64_t Now = OpenWifi::Now();
|
uint64_t Now = OpenWifi::Now();
|
||||||
@@ -223,7 +224,7 @@ namespace OpenWifi {
|
|||||||
ProvObjects::DeviceRules Rules;
|
ProvObjects::DeviceRules Rules;
|
||||||
std::string SerialNumber = Utils::IntToSerialNumber(i);
|
std::string SerialNumber = Utils::IntToSerialNumber(i);
|
||||||
if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) {
|
if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) {
|
||||||
if(Rules.rrm=="yes")
|
if(Rules.rrm!="no" && Rules.rrm!="inherit")
|
||||||
DeviceList.push_back(SerialNumber);
|
DeviceList.push_back(SerialNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ if [ -z ${OWPROV_OVERRIDE+x} ]; then
|
|||||||
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
|
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
|
||||||
path="$(echo $url | grep / | cut -d/ -f2-)"
|
path="$(echo $url | grep / | cut -d/ -f2-)"
|
||||||
export OWPROV=${url}
|
export OWPROV=${url}
|
||||||
echo "Using ${OWPROV}..."
|
echo "Using PROV=${OWPROV}..."
|
||||||
else
|
else
|
||||||
echo "OWPROV endpoint is not found:"
|
echo "OWPROV endpoint is not found:"
|
||||||
jq < ${result_file}
|
jq < ${result_file}
|
||||||
@@ -108,6 +108,33 @@ else
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setrrm() {
|
||||||
|
if [ -z ${OWRRM_OVERRIDE+x} ]; then
|
||||||
|
curl ${FLAGS} -X GET "https://${OWSEC}/api/v1/systemEndpoints" \
|
||||||
|
-H "Accept: application/json" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer ${token}" > ${result_file}
|
||||||
|
rawurl="$(cat ${result_file} | jq -r '.endpoints[] | select( .type == "owrrm" ) | .uri')"
|
||||||
|
if [[ ! -z "${rawurl}" ]]; then
|
||||||
|
proto="$(echo $rawurl | grep :// | sed -e's,^\(.*://\).*,\1,g')"
|
||||||
|
url="$(echo ${rawurl/$proto/})"
|
||||||
|
user="$(echo $url | grep @ | cut -d@ -f1)"
|
||||||
|
hostport="$(echo ${url/$user@/} | cut -d/ -f1)"
|
||||||
|
host="$(echo $hostport | sed -e 's,:.*,,g')"
|
||||||
|
port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')"
|
||||||
|
path="$(echo $url | grep / | cut -d/ -f2-)"
|
||||||
|
export OWRRM=${url}
|
||||||
|
echo "Using RRM=${OWRRM}..."
|
||||||
|
else
|
||||||
|
echo "OWRRM endpoint is not found:"
|
||||||
|
jq < ${result_file}
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
export OWRRM=${OWRRM_OVERRIDE}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
|
curl ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
@@ -507,6 +534,24 @@ getvenuedevices() {
|
|||||||
jq < ${result_file}
|
jq < ${result_file}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listrrmalgos() {
|
||||||
|
setrrm
|
||||||
|
curl ${FLAGS} -X GET "http://${OWRRM}/api/v1/algorithms" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer ${token}" \
|
||||||
|
-H "Accept: application/json" > ${result_file}
|
||||||
|
jq < ${result_file}
|
||||||
|
}
|
||||||
|
|
||||||
|
rrmprovider() {
|
||||||
|
setrrm
|
||||||
|
curl ${FLAGS} -X GET "http://${OWRRM}/api/v1/provider" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer ${token}" \
|
||||||
|
-H "Accept: application/json" > ${result_file}
|
||||||
|
jq < ${result_file}
|
||||||
|
}
|
||||||
|
|
||||||
shopt -s nocasematch
|
shopt -s nocasematch
|
||||||
case "$1" in
|
case "$1" in
|
||||||
"login") login; echo "You are logged in..." ; logout ;;
|
"login") login; echo "You are logged in..." ; logout ;;
|
||||||
@@ -555,6 +600,8 @@ case "$1" in
|
|||||||
"getsubdevs") login; getsubdevs $2; logout;;
|
"getsubdevs") login; getsubdevs $2; logout;;
|
||||||
"listvenues") login; listvenues $2; logout;;
|
"listvenues") login; listvenues $2; logout;;
|
||||||
"getvenuedevices") login; getvenuedevices $2; logout;;
|
"getvenuedevices") login; getvenuedevices $2; logout;;
|
||||||
|
"listrrmalgos") login; listrrmalgos; logout;;
|
||||||
|
"rrmprovider") login; rrmprovider; logout;;
|
||||||
*) help ;;
|
*) help ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user