mirror of
				https://github.com/Telecominfraproject/wlan-cloud-owprov.git
				synced 2025-10-30 18:18:03 +00:00 
			
		
		
		
	Compare commits
	
		
			131 Commits
		
	
	
		
			v2.6.0-RC1
			...
			v2.7.0-RC6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | af7cbf0ce1 | ||
|   | d50e8c0c44 | ||
|   | c5e44f2a98 | ||
|   | 5c2937c7ec | ||
|   | 698b467d3f | ||
|   | a8f1483362 | ||
|   | 693814de1c | ||
|   | 0394369410 | ||
|   | 5abe7a9909 | ||
|   | 0a3a9a4b20 | ||
|   | 9d4eb1e502 | ||
|   | 0b6d68def5 | ||
|   | 51ba962338 | ||
|   | fef07e3150 | ||
|   | 03a6675359 | ||
|   | 19686da4d8 | ||
|   | c5997a3511 | ||
|   | 3feb5fd666 | ||
|   | d3cd3a1a21 | ||
|   | 5e6228b9d6 | ||
|   | ad526ebf1d | ||
|   | 8de53277e6 | ||
|   | 93fbb3017a | ||
|   | 2e4d1ad3e8 | ||
|   | 109a9affc5 | ||
|   | 9c65813735 | ||
|   | 7d0bdf059d | ||
|   | 93e4b069c4 | ||
|   | 4fe1367651 | ||
|   | 5f5f2fd699 | ||
|   | c2e0d32e0d | ||
|   | cab81a3930 | ||
|   | 01395f11a3 | ||
|   | 250c12acf1 | ||
|   | e23d04c1d0 | ||
|   | b48955e791 | ||
|   | e58eb38d53 | ||
|   | 791af9aeba | ||
|   | 67081917a9 | ||
|   | 3a33815096 | ||
|   | f515bb8e30 | ||
|   | 02fd6d726a | ||
|   | 27ffb31a7c | ||
|   | 5fd9831d6b | ||
|   | fed085cc4a | ||
|   | 121fee841e | ||
|   | 4c6f03ba14 | ||
|   | 0fb9478675 | ||
|   | 97c2af83fd | ||
|   | 599ba0793c | ||
|   | 6df780dba3 | ||
|   | a00287ae85 | ||
|   | c7a300b81e | ||
|   | 5dc507a82e | ||
|   | 8b3e1326b7 | ||
|   | 667f8bc4bd | ||
|   | 6cacebad28 | ||
|   | e487b68945 | ||
|   | ffddfa87d2 | ||
|   | 0168301d6b | ||
|   | 1a0b00e989 | ||
|   | 7c2229f3d6 | ||
|   | 541df429ec | ||
|   | 6f9fe6cd5d | ||
|   | 2594a2c5f2 | ||
|   | 2e02d96523 | ||
|   | a1375f9468 | ||
|   | 777bc0f2aa | ||
|   | bd0e99309c | ||
|   | 6cb6a60142 | ||
|   | fc7947394d | ||
|   | 1341e15874 | ||
|   | f065815df3 | ||
|   | 03ba51e869 | ||
|   | efd7ef2a9b | ||
|   | 4b90a6e893 | ||
|   | f5cb4a5a87 | ||
|   | e3e4aac202 | ||
|   | 5945d02b3d | ||
|   | 0ac192cdc0 | ||
|   | 1b5eb87eef | ||
|   | 46db18d7cd | ||
|   | 30b8665d7d | ||
|   | c8b3a3b060 | ||
|   | 096da35ff4 | ||
|   | bd7f3af11c | ||
|   | 2a06021c4a | ||
|   | bf18bb25ba | ||
|   | e93f899b76 | ||
|   | eda73038f6 | ||
|   | 953ca155a4 | ||
|   | 898806f232 | ||
|   | 7d97b19b85 | ||
|   | d6c587fde6 | ||
|   | 58c9a7805b | ||
|   | 94dd4c84e9 | ||
|   | 2636715f6f | ||
|   | f9f4624add | ||
|   | cf441de197 | ||
|   | 158455a528 | ||
|   | 4d2ccec1a8 | ||
|   | 7dad5a9bdb | ||
|   | cd2ac84c5b | ||
|   | 9735f709e9 | ||
|   | ae5fd31818 | ||
|   | 2b46ad4a66 | ||
|   | 43d7078cb7 | ||
|   | 18f5d42f00 | ||
|   | 70622b2bb8 | ||
|   | 5b24aea47c | ||
|   | e97617a0db | ||
|   | ba63a7033f | ||
|   | e9db2e1a0d | ||
|   | d85fef7725 | ||
|   | 543c46bf68 | ||
|   | 73eec53fe4 | ||
|   | 8ad2d67c2c | ||
|   | 442f810688 | ||
|   | 2dca5204ea | ||
|   | dc2abe2154 | ||
|   | 8c14bb5b3a | ||
|   | 6ec4bc7115 | ||
|   | 9883a40ec6 | ||
|   | cc647b8108 | ||
|   | 3b0f2a0977 | ||
|   | dfefe39188 | ||
|   | 7d65e19d29 | ||
|   | 1e16c59743 | ||
|   | 4582cbd133 | ||
|   | 18e4b68c1f | ||
|   | 46a11ebda2 | 
							
								
								
									
										8
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/cleanup.yml
									
									
									
									
										vendored
									
									
								
							| @@ -17,4 +17,10 @@ jobs: | |||||||
|     steps: |     steps: | ||||||
|       - run: | |       - run: | | ||||||
|           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') |           export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-') | ||||||
|           curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owprov/$PR_BRANCH_TAG" |  | ||||||
|  |           if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then | ||||||
|  |             echo "PR branch is $PR_BRANCH_TAG, deleting Docker image" | ||||||
|  |             curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owprov/$PR_BRANCH_TAG" | ||||||
|  |           else | ||||||
|  |             echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image" | ||||||
|  |           fi | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| cmake_minimum_required(VERSION 3.13) | cmake_minimum_required(VERSION 3.13) | ||||||
| project(owprov VERSION 2.6.0) | project(owprov VERSION 2.7.0) | ||||||
|  |  | ||||||
| set(CMAKE_CXX_STANDARD 17) | set(CMAKE_CXX_STANDARD 17) | ||||||
|  |  | ||||||
| @@ -58,6 +58,8 @@ include_directories(/usr/local/include  /usr/local/opt/openssl/include src inclu | |||||||
|  |  | ||||||
| configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY) | configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY) | ||||||
|  |  | ||||||
|  | add_definitions(-DPOCO_LOG_DEBUG="1") | ||||||
|  |  | ||||||
| add_compile_options(-Wall -Wextra) | add_compile_options(-Wall -Wextra) | ||||||
| if(ASAN) | if(ASAN) | ||||||
|     add_compile_options(-fsanitize=address) |     add_compile_options(-fsanitize=address) | ||||||
| @@ -76,7 +78,9 @@ add_executable(owprov | |||||||
|         src/framework/ConfigurationValidator.cpp |         src/framework/ConfigurationValidator.cpp | ||||||
|         src/framework/ConfigurationValidator.h |         src/framework/ConfigurationValidator.h | ||||||
|         src/framework/ow_constants.h |         src/framework/ow_constants.h | ||||||
|  |         src/framework/MicroServiceErrorHandler.h | ||||||
|         src/framework/WebSocketClientNotifications.h |         src/framework/WebSocketClientNotifications.h | ||||||
|  |         src/framework/MicroServiceErrorHandler.h | ||||||
|         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp |         src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp | ||||||
|         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h |         src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h | ||||||
|         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp |         src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp | ||||||
| @@ -125,7 +129,6 @@ add_executable(owprov | |||||||
|         src/RESTAPI/RESTAPI_db_helpers.h |         src/RESTAPI/RESTAPI_db_helpers.h | ||||||
|         src/JobController.cpp src/JobController.h |         src/JobController.cpp src/JobController.h | ||||||
|         src/JobRegistrations.cpp |         src/JobRegistrations.cpp | ||||||
|         src/storage/storage_jobs.cpp src/storage/storage_jobs.h |  | ||||||
|         src/storage/storage_maps.cpp src/storage/storage_maps.h |         src/storage/storage_maps.cpp src/storage/storage_maps.h | ||||||
|         src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h |         src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h | ||||||
|         src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h |         src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h | ||||||
| @@ -135,7 +138,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} | ||||||
|   | |||||||
							
								
								
									
										75
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,16 +1,23 @@ | |||||||
| FROM alpine:3.15 AS build-base | ARG DEBIAN_VERSION=11.4-slim | ||||||
|  | ARG POCO_VERSION=poco-tip-v1 | ||||||
|  | ARG FMTLIB_VERSION=9.0.0 | ||||||
|  | ARG CPPKAFKA_VERSION=tip-v1 | ||||||
|  | ARG JSON_VALIDATOR_VERSION=2.1.0 | ||||||
|  |  | ||||||
| RUN apk add --update --no-cache \ | FROM debian:$DEBIAN_VERSION AS build-base | ||||||
|  |  | ||||||
|  | RUN apt-get update && apt-get install --no-install-recommends -y \ | ||||||
|     make cmake g++ git \ |     make cmake g++ git \ | ||||||
|     unixodbc-dev postgresql-dev mariadb-dev \ |     libpq-dev libmariadb-dev libmariadbclient-dev-compat \ | ||||||
|     librdkafka-dev boost-dev openssl-dev \ |     librdkafka-dev libboost-all-dev libssl-dev \ | ||||||
|     zlib-dev nlohmann-json \ |     zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev | ||||||
|     curl-dev |  | ||||||
|  |  | ||||||
| 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 +26,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 +56,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 +68,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,21 +90,21 @@ 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 debian:$DEBIAN_VERSION | ||||||
|  |  | ||||||
| ENV OWPROV_USER=owprov \ | ENV OWPROV_USER=owprov \ | ||||||
|     OWPROV_ROOT=/owprov-data \ |     OWPROV_ROOT=/owprov-data \ | ||||||
|     OWPROV_CONFIG=/owprov-data |     OWPROV_CONFIG=/owprov-data | ||||||
|  |  | ||||||
| RUN addgroup -S "$OWPROV_USER" && \ | RUN useradd "$OWPROV_USER" | ||||||
|     adduser -S -G "$OWPROV_USER" "$OWPROV_USER" |  | ||||||
|  |  | ||||||
| RUN mkdir /openwifi | RUN mkdir /openwifi | ||||||
| RUN mkdir -p "$OWPROV_ROOT" "$OWPROV_CONFIG" && \ | RUN mkdir -p "$OWPROV_ROOT" "$OWPROV_CONFIG" && \ | ||||||
|     chown "$OWPROV_USER": "$OWPROV_ROOT" "$OWPROV_CONFIG" |     chown "$OWPROV_USER": "$OWPROV_ROOT" "$OWPROV_CONFIG" | ||||||
|  |  | ||||||
| RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \ | RUN apt-get update && apt-get install --no-install-recommends -y \ | ||||||
|     mariadb-connector-c libpq unixodbc postgresql-client |     librdkafka++1 gosu gettext ca-certificates bash jq curl wget \ | ||||||
|  |     libmariadb-dev-compat libpq5 unixodbc postgresql-client | ||||||
|  |  | ||||||
| COPY readiness_check /readiness_check | COPY readiness_check /readiness_check | ||||||
| COPY test_scripts/curl/cli /cli | COPY test_scripts/curl/cli /cli | ||||||
| @@ -100,12 +113,14 @@ COPY owprov.properties.tmpl / | |||||||
| COPY docker-entrypoint.sh / | COPY docker-entrypoint.sh / | ||||||
| COPY wait-for-postgres.sh / | COPY wait-for-postgres.sh / | ||||||
| RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ | ||||||
|     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem |     -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt | ||||||
|  |  | ||||||
| COPY --from=owprov-build /owprov/cmake-build/owprov /openwifi/owprov | COPY --from=owprov-build /owprov/cmake-build/owprov /openwifi/owprov | ||||||
| COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib | COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib | ||||||
| COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib | COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib | ||||||
|  |  | ||||||
|  | RUN ldconfig | ||||||
|  |  | ||||||
| EXPOSE 16005 17005 16105 | EXPOSE 16005 17005 16105 | ||||||
|  |  | ||||||
| ENTRYPOINT ["/docker-entrypoint.sh"] | ENTRYPOINT ["/docker-entrypoint.sh"] | ||||||
|   | |||||||
| @@ -1,11 +1,11 @@ | |||||||
| #!/bin/sh | #!/bin/bash | ||||||
| set -e | set -e | ||||||
|  |  | ||||||
| if [ "$SELFSIGNED_CERTS" = 'true' ]; then | if [ "$SELFSIGNED_CERTS" = 'true' ]; then | ||||||
|     update-ca-certificates |     update-ca-certificates | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWPROV_CONFIG"/owprov.properties ]]; then | if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then | ||||||
|   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWPROV_ROOT/certs/restapi-ca.pem"} \ |   RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWPROV_ROOT/certs/restapi-ca.pem"} \ | ||||||
|   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16005"} \ |   RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16005"} \ | ||||||
|   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWPROV_ROOT/certs/restapi-cert.pem"} \ |   RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWPROV_ROOT/certs/restapi-cert.pem"} \ | ||||||
| @@ -24,6 +24,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWPROV_CONFIG"/owprov.properties ]]; | |||||||
|   SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17005"} \ |   SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17005"} \ | ||||||
|   SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16005"} \ |   SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16005"} \ | ||||||
|   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ |   SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ | ||||||
|  |   SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \ | ||||||
|   KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ |   KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ | ||||||
|   KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \ |   KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \ | ||||||
|   KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \ |   KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \ | ||||||
| @@ -48,7 +49,7 @@ if [ "$1" = '/openwifi/owprov' -a "$(id -u)" = '0' ]; then | |||||||
|     if [ "$RUN_CHOWN" = 'true' ]; then |     if [ "$RUN_CHOWN" = 'true' ]; then | ||||||
|       chown -R "$OWPROV_USER": "$OWPROV_ROOT" "$OWPROV_CONFIG" |       chown -R "$OWPROV_USER": "$OWPROV_ROOT" "$OWPROV_CONFIG" | ||||||
|     fi |     fi | ||||||
|     exec su-exec "$OWPROV_USER" "$@" |     exec gosu "$OWPROV_USER" "$@" | ||||||
| fi | fi | ||||||
|  |  | ||||||
| exec "$@" | exec "$@" | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								helm/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,3 @@ | |||||||
| *.swp | *.swp | ||||||
|  | Chart.lock | ||||||
|  | charts/ | ||||||
|   | |||||||
| @@ -5,14 +5,14 @@ name: owprov | |||||||
| version: 0.1.0 | version: 0.1.0 | ||||||
| dependencies: | dependencies: | ||||||
| - name: postgresql | - name: postgresql | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 10.9.2 |   version: 10.9.2 | ||||||
|   condition: postgresql.enabled |   condition: postgresql.enabled | ||||||
| - name: mysql | - name: mysql | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 8.8.3 |   version: 8.8.3 | ||||||
|   condition: mysql.enabled |   condition: mysql.enabled | ||||||
| - name: mariadb | - name: mariadb | ||||||
|   repository: https://charts.bitnami.com/bitnami |   repository: https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral-helm/ | ||||||
|   version: 9.4.2 |   version: 9.4.2 | ||||||
|   condition: mariadb.enabled |   condition: mariadb.enabled | ||||||
|   | |||||||
| @@ -70,8 +70,8 @@ The following table lists the configurable parameters of the chart and their def | |||||||
| | persistence.size | string | Defines PV size | `'10Gi'` | | | persistence.size | string | Defines PV size | `'10Gi'` | | ||||||
| | public_env_variables | hash | Defines list of environment variables to be passed to the Provisioning | | | | public_env_variables | hash | Defines list of environment variables to be passed to the Provisioning | | | ||||||
| | configProperties | hash | Configuration properties that should be passed to the application in `owprov.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | | | | configProperties | hash | Configuration properties that should be passed to the application in `owprov.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | | | ||||||
| | certs | hash | Defines files (keys and certificates) that should be passed to the Provisioning (PEM format is adviced to be used) (see `volumes.owprov` on where it is mounted) |  | | | existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` | | ||||||
|  | | certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owprov` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. |  | | ||||||
|  |  | ||||||
| Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, | Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -97,8 +131,10 @@ spec: | |||||||
|             {{- toYaml . | nindent 12 }} |             {{- toYaml . | nindent 12 }} | ||||||
|           {{- end }} |           {{- end }} | ||||||
|  |  | ||||||
|  |       {{- with .Values.securityContext }} | ||||||
|       securityContext: |       securityContext: | ||||||
|         fsGroup: 101 |         {{- toYaml . | nindent 8 }} | ||||||
|  |       {{- end }} | ||||||
|  |  | ||||||
|       imagePullSecrets: |       imagePullSecrets: | ||||||
|       {{- range $image, $imageValue := .Values.images }} |       {{- range $image, $imageValue := .Values.images }} | ||||||
|   | |||||||
| @@ -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-RC6 | ||||||
|     pullPolicy: Always |     pullPolicy: Always | ||||||
| #    regcred: | #    regcred: | ||||||
| #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | #      registry: tip-tip-wlan-cloud-ucentral.jfrog.io | ||||||
| @@ -71,7 +71,7 @@ volumes: | |||||||
|       mountPath: /owprov-data/certs |       mountPath: /owprov-data/certs | ||||||
|       volumeDefinition: | |       volumeDefinition: | | ||||||
|         secret: |         secret: | ||||||
|           secretName: {{ include "owprov.fullname" . }}-certs |           secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owprov.fullname" . }}-certs{{ end }} | ||||||
|     # Change this if you want to use another volume type |     # Change this if you want to use another volume type | ||||||
|     - name: persist |     - name: persist | ||||||
|       mountPath: /owprov-data/persist |       mountPath: /owprov-data/persist | ||||||
| @@ -91,6 +91,9 @@ resources: {} | |||||||
|   #  cpu: 100m |   #  cpu: 100m | ||||||
|   #  memory: 128Mi |   #  memory: 128Mi | ||||||
|  |  | ||||||
|  | securityContext: | ||||||
|  |   fsGroup: 1000 | ||||||
|  |  | ||||||
| nodeSelector: {} | nodeSelector: {} | ||||||
|  |  | ||||||
| tolerations: [] | tolerations: [] | ||||||
| @@ -199,6 +202,9 @@ configProperties: | |||||||
|   storage.type.mysql.username: stephb |   storage.type.mysql.username: stephb | ||||||
|   storage.type.mysql.password: snoopy99 |   storage.type.mysql.password: snoopy99 | ||||||
|  |  | ||||||
|  | # NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr | ||||||
|  | existingCertsSecret: "" | ||||||
|  |  | ||||||
| certs: | certs: | ||||||
|   # restapi-ca.pem: "" |   # restapi-ca.pem: "" | ||||||
|   # restapi-cert.pem: "" |   # restapi-cert.pem: "" | ||||||
|   | |||||||
							
								
								
									
										268
									
								
								openapi/ow_or_ameriband.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								openapi/ow_or_ameriband.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,268 @@ | |||||||
|  | openapi: 3.0.1 | ||||||
|  | info: | ||||||
|  |   title: OpenWiFi Open roaming Ameriband Provisioning Model | ||||||
|  |   description: Registration of an OpenRoaming profile with Ameriband for TIP OpenWifi. | ||||||
|  |   version: 1.0.0 | ||||||
|  |   license: | ||||||
|  |     name: BSD3 | ||||||
|  |     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||||
|  |  | ||||||
|  | servers: | ||||||
|  |   - url: 'https://tip.regiatration.ameriband.com:8001/api/v1' | ||||||
|  |  | ||||||
|  | security: | ||||||
|  |   - bearerAuth: [] | ||||||
|  |  | ||||||
|  | components: | ||||||
|  |   securitySchemes: | ||||||
|  |     bearerAuth: | ||||||
|  |       type: http | ||||||
|  |       scheme: bearer | ||||||
|  |  | ||||||
|  |   responses: | ||||||
|  |     NotFound: | ||||||
|  |       description: The specified resource was not found. | ||||||
|  |       content: | ||||||
|  |         application/json: | ||||||
|  |           schema: | ||||||
|  |             properties: | ||||||
|  |               ErrorCode: | ||||||
|  |                 type: integer | ||||||
|  |               ErrorDetails: | ||||||
|  |                 type: string | ||||||
|  |               ErrorDescription: | ||||||
|  |                 type: string | ||||||
|  |  | ||||||
|  |     Unauthorized: | ||||||
|  |       description: The requested does not have sufficient rights to perform the operation. | ||||||
|  |       content: | ||||||
|  |         application/json: | ||||||
|  |           schema: | ||||||
|  |             properties: | ||||||
|  |               ErrorCode: | ||||||
|  |                 type: integer | ||||||
|  |                 enum: | ||||||
|  |                   - 0     # Success | ||||||
|  |                   - 8     # INVALID_TOKEN | ||||||
|  |                   - 9     # EXPIRED_TOKEN | ||||||
|  |               ErrorDetails: | ||||||
|  |                 type: string | ||||||
|  |               ErrorDescription: | ||||||
|  |                 type: string | ||||||
|  |  | ||||||
|  |     Success: | ||||||
|  |       description: The requested operation was performed. | ||||||
|  |       content: | ||||||
|  |         application/json: | ||||||
|  |           schema: | ||||||
|  |             properties: | ||||||
|  |               Operation: | ||||||
|  |                 type: string | ||||||
|  |               Details: | ||||||
|  |                 type: string | ||||||
|  |               Code: | ||||||
|  |                 type: integer | ||||||
|  |  | ||||||
|  |     BadRequest: | ||||||
|  |       description: The requested operation failed. | ||||||
|  |       content: | ||||||
|  |         application/json: | ||||||
|  |           schema: | ||||||
|  |             properties: | ||||||
|  |               ErrorCode: | ||||||
|  |                 type: integer | ||||||
|  |               ErrorDetails: | ||||||
|  |                 type: string | ||||||
|  |               ErrorDescription: | ||||||
|  |                 type: integer | ||||||
|  |  | ||||||
|  |   schemas: | ||||||
|  |     RegistrationRequest: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         orgRequestId: | ||||||
|  |           type: string | ||||||
|  |           format: uuid | ||||||
|  |           minLength: 36 | ||||||
|  |           maxLength: 36 | ||||||
|  |           example: | ||||||
|  |             Client will generate a UUID that must be returned in the response. | ||||||
|  |         orgAcceptedTermsAndConditions: | ||||||
|  |           type: boolean | ||||||
|  |           default: false | ||||||
|  |         orgLegalName: | ||||||
|  |           type: string | ||||||
|  |           minLength: 1 | ||||||
|  |         orgWebSite: | ||||||
|  |           type: string | ||||||
|  |           format: url | ||||||
|  |           minLength: 1 | ||||||
|  |         orgContact: | ||||||
|  |           type: string | ||||||
|  |           minLength: 1 | ||||||
|  |           example: | ||||||
|  |             John Smith | ||||||
|  |         orgEmail: | ||||||
|  |           type: string | ||||||
|  |           format: email | ||||||
|  |           minLength: 1 | ||||||
|  |         orgPhone: | ||||||
|  |           type: string | ||||||
|  |           example: | ||||||
|  |             (607)555-1234 or +1(223)555-1222 | ||||||
|  |         orgLocation: | ||||||
|  |           type: string | ||||||
|  |           example: | ||||||
|  |             Boston, NH - LA, CA | ||||||
|  |         orgCertificate: | ||||||
|  |           type: string | ||||||
|  |           minLength: 1 | ||||||
|  |           example: | ||||||
|  |             This must be the entire PEM file content of the certificate, encoded using base64 | ||||||
|  |  | ||||||
|  |     RegistrationResponse: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         orgRequestId: | ||||||
|  |           type: string | ||||||
|  |           format: uuid | ||||||
|  |           minLength: 36 | ||||||
|  |           maxLength: 36 | ||||||
|  |           example: | ||||||
|  |             This should be the same orgRequestId passed during registration. | ||||||
|  |         orgNASID: | ||||||
|  |           type: string | ||||||
|  |           minLength: 10 | ||||||
|  |           description: | ||||||
|  |             This is the NASID generated by Ameriband. It will be used by the operator as NASID when contacting Ameriband. | ||||||
|  |         ameribandCertificate: | ||||||
|  |           type: string | ||||||
|  |           minLength: 1 | ||||||
|  |           example: | ||||||
|  |             This must be the entire PEM file content of the certificate, encoded using base64 | ||||||
|  |  | ||||||
|  |     RegistrationInformationRequest: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         link: | ||||||
|  |           description: This should be the link where a potential registrant can read the terms and conditions of registering with Ameriband. | ||||||
|  |           type: string | ||||||
|  |           format: url | ||||||
|  |           minLength: 1 | ||||||
|  |           example: | ||||||
|  |             https://ameriband.com/romain-registration.html | ||||||
|  |  | ||||||
|  | paths: | ||||||
|  |   /termsAndConditions: | ||||||
|  |     get: | ||||||
|  |       summary: The registrant must be given a chance to view the terms and conditions of the relationship they are entering into | ||||||
|  |       operationId: getTermsAndConditions | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: Sucessfully retrieved Terms and Conditions | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 $ref: '#/components/schemas/RegistrationInformationRequest' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |  | ||||||
|  |   /registration: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - Registration | ||||||
|  |       operationId: getRegistrationInformation | ||||||
|  |       summary: This should return the information from a registration based on the NASID | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: orgNASID | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: true | ||||||
|  |           example: | ||||||
|  |             This is the orgNASID returned during registration. | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/RegistrationResponse' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  |  | ||||||
|  |     post: | ||||||
|  |       summary: Called when the registrant ahs read the T&Cs and iw willing to submit their information to enter in a partnership | ||||||
|  |       tags: | ||||||
|  |         - Registration | ||||||
|  |       operationId: createRegistration | ||||||
|  |       requestBody: | ||||||
|  |         required: true | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               $ref: '#/components/schemas/RegistrationRequest' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: Succesfully registered | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 $ref: '#/components/schemas/RegistrationResponse' | ||||||
|  |         400: | ||||||
|  |           description: Registration failed due to  missing or incomplete information | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |  | ||||||
|  |     put: | ||||||
|  |       summary: Called when the registrant needs to update its information with Ameriband. The does not generate a new NASID. | ||||||
|  |       tags: | ||||||
|  |         - Registration | ||||||
|  |       operationId: updateRegistration | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: orgNASID | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: true | ||||||
|  |           example: | ||||||
|  |             This is the orgNASID returned during registration. | ||||||
|  |       requestBody: | ||||||
|  |         required: true | ||||||
|  |         content: | ||||||
|  |           application/json: | ||||||
|  |             schema: | ||||||
|  |               $ref: '#/components/schemas/RegistrationRequest' | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: Succesfully found the information based on the orgNASID | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 $ref: '#/components/schemas/RegistrationResponse' | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  |  | ||||||
|  |     delete: | ||||||
|  |       tags: | ||||||
|  |         - Registration | ||||||
|  |       summary: When a registrant wants to terminate a relationship with Ameriband. Ameriband should also delete all information from the registrant | ||||||
|  |       operationId: deleteRegistration | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           name: orgNASID | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: true | ||||||
|  |           example: | ||||||
|  |             This is the orgNASID returned during registration. | ||||||
|  |       responses: | ||||||
|  |         204: | ||||||
|  |           $ref: '#/components/responses/Success' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
| @@ -27,71 +27,13 @@ components: | |||||||
|  |  | ||||||
|   responses: |   responses: | ||||||
|     NotFound: |     NotFound: | ||||||
|       description: The specified resource was not found. |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' | ||||||
|       content: |  | ||||||
|         application/json: |  | ||||||
|           schema: |  | ||||||
|             properties: |  | ||||||
|               ErrorCode: |  | ||||||
|                 type: integer |  | ||||||
|               ErrorDetails: |  | ||||||
|                 type: string |  | ||||||
|               ErrorDescription: |  | ||||||
|                 type: string |  | ||||||
|  |  | ||||||
|     Unauthorized: |     Unauthorized: | ||||||
|       description: The requested does not have sufficient rights to perform the operation. |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized' | ||||||
|       content: |  | ||||||
|         application/json: |  | ||||||
|           schema: |  | ||||||
|             properties: |  | ||||||
|               ErrorCode: |  | ||||||
|                 type: integer |  | ||||||
|                 enum: |  | ||||||
|                   - 0     # Success |  | ||||||
|                   - 1     # PASSWORD_CHANGE_REQUIRED, |  | ||||||
|                   - 2     # INVALID_CREDENTIALS, |  | ||||||
|                   - 3     # PASSWORD_ALREADY_USED, |  | ||||||
|                   - 4     # USERNAME_PENDING_VERIFICATION, |  | ||||||
|                   - 5     # PASSWORD_INVALID, |  | ||||||
|                   - 6     # INTERNAL_ERROR, |  | ||||||
|                   - 7     # ACCESS_DENIED, |  | ||||||
|                   - 8     # INVALID_TOKEN |  | ||||||
|                   - 9     # EXPIRED_TOKEN |  | ||||||
|                   - 10    # RATE_LIMIT_EXCEEDED |  | ||||||
|                   - 11    # BAD_MFA_TRANSACTION |  | ||||||
|                   - 12    # MFA_FAILURE |  | ||||||
|                   - 13    # SECURITY_SERVICE_UNREACHABLE |  | ||||||
|               ErrorDetails: |  | ||||||
|                 type: string |  | ||||||
|               ErrorDescription: |  | ||||||
|                 type: string |  | ||||||
|  |  | ||||||
|     Success: |     Success: | ||||||
|       description: The requested operation was performed. |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' | ||||||
|       content: |  | ||||||
|         application/json: |  | ||||||
|           schema: |  | ||||||
|             properties: |  | ||||||
|               Operation: |  | ||||||
|                 type: string |  | ||||||
|               Details: |  | ||||||
|                 type: string |  | ||||||
|               Code: |  | ||||||
|                 type: integer |  | ||||||
|  |  | ||||||
|     BadRequest: |     BadRequest: | ||||||
|       description: The requested operation failed. |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' | ||||||
|       content: |  | ||||||
|         application/json: |  | ||||||
|           schema: |  | ||||||
|             properties: |  | ||||||
|               ErrorCode: |  | ||||||
|                 type: integer |  | ||||||
|               ErrorDetails: |  | ||||||
|                 type: string |  | ||||||
|               ErrorDescription: |  | ||||||
|                 type: integer |  | ||||||
|  |  | ||||||
|   schemas: |   schemas: | ||||||
|  |  | ||||||
| @@ -2016,11 +1958,6 @@ paths: | |||||||
|           schema: |           schema: | ||||||
|             type: boolean |             type: boolean | ||||||
|           required: false |           required: false | ||||||
|         - in: query |  | ||||||
|           name: deviceType |  | ||||||
|           schema: |  | ||||||
|             type: string |  | ||||||
|           required: false |  | ||||||
|         - in: query |         - in: query | ||||||
|           description: Pagination start (starts at 1. If not specified, 1 is assumed) |           description: Pagination start (starts at 1. If not specified, 1 is assumed) | ||||||
|           name: offset |           name: offset | ||||||
| @@ -2092,6 +2029,21 @@ paths: | |||||||
|             type: string |             type: string | ||||||
|             format: uuid |             format: uuid | ||||||
|           required: false |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: return RRM settings for a specific device | ||||||
|  |           name: rrmSettings | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |             default: false | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: return the resolved configuration for a specific device | ||||||
|  |           name:   resolveConfig | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |             default: false | ||||||
|  |           required: false | ||||||
|  |  | ||||||
|       responses: |       responses: | ||||||
|         200: |         200: | ||||||
|           description: Return a list of elements |           description: Return a list of elements | ||||||
| @@ -2313,12 +2265,6 @@ paths: | |||||||
|             type: string |             type: string | ||||||
|             example: serial1,serial2,serial3 |             example: serial1,serial2,serial3 | ||||||
|           required: false |           required: false | ||||||
|         - in: query |  | ||||||
|           description: only serial numbers of full device details |  | ||||||
|           name: serialOnly |  | ||||||
|           schema: |  | ||||||
|             type: boolean |  | ||||||
|           required: false |  | ||||||
|         - in: query |         - in: query | ||||||
|           description: return the number of devices |           description: return the number of devices | ||||||
|           name: countOnly |           name: countOnly | ||||||
|   | |||||||
							
								
								
									
										174
									
								
								openapi/rrm_provider.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								openapi/rrm_provider.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | |||||||
|  | openapi: 3.0.1 | ||||||
|  | info: | ||||||
|  |   title: OpenWiFi RRM Provider Model | ||||||
|  |   description: Definitions and APIs to manages an OpenWiFi RRM Providers. | ||||||
|  |   version: 1.0.0 | ||||||
|  |   license: | ||||||
|  |     name: BSD3 | ||||||
|  |     url: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE | ||||||
|  |  | ||||||
|  | servers: | ||||||
|  |   - url: 'https://localhost:16022/api/v1' | ||||||
|  |  | ||||||
|  | security: | ||||||
|  |   - bearerAuth: [] | ||||||
|  |   - ApiKeyAuth: [] | ||||||
|  |  | ||||||
|  | components: | ||||||
|  |   securitySchemes: | ||||||
|  |     ApiKeyAuth: | ||||||
|  |       type: apiKey | ||||||
|  |       in: header | ||||||
|  |       name: X-API-KEY | ||||||
|  |     bearerAuth: | ||||||
|  |       type: http | ||||||
|  |       scheme: bearer | ||||||
|  |       bearerFormat: JWT | ||||||
|  |  | ||||||
|  |   responses: | ||||||
|  |     NotFound: | ||||||
|  |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound' | ||||||
|  |     Unauthorized: | ||||||
|  |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized' | ||||||
|  |     Success: | ||||||
|  |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success' | ||||||
|  |     BadRequest: | ||||||
|  |       $ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest' | ||||||
|  |  | ||||||
|  |   schemas: | ||||||
|  |  | ||||||
|  |     Provider: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         vendor: | ||||||
|  |           description: The name of the vendor for display. | ||||||
|  |           type: string | ||||||
|  |           minLength: 1 | ||||||
|  |           maxLength: 128 | ||||||
|  |         vendorShortname: | ||||||
|  |           description: A shortname for the vendor. Only letters and numbers are allowed. This is the name used internally. | ||||||
|  |           type: string | ||||||
|  |           minLength: 4 | ||||||
|  |           maxLength: 16 | ||||||
|  |         version: | ||||||
|  |           description: An identifier that will help users identify the version of the RRM module they are using. | ||||||
|  |           type: string | ||||||
|  |         about: | ||||||
|  |           description: A link to the Vendor page for this RRM Module | ||||||
|  |           type: string | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     Algorithm: | ||||||
|  |       type: object | ||||||
|  |       properties: | ||||||
|  |         name: | ||||||
|  |           description: A display for this algorithm. | ||||||
|  |           type: string | ||||||
|  |           minLength: 1 | ||||||
|  |           maxLength: 128 | ||||||
|  |         description: | ||||||
|  |           description: A description of the algorithm. | ||||||
|  |           type: string | ||||||
|  |         shortName: | ||||||
|  |           description: This is the name used internally. | ||||||
|  |           type: string | ||||||
|  |           minLength: 4 | ||||||
|  |           maxLength: 16 | ||||||
|  |         parameterFormat: | ||||||
|  |           description: this is a Regex used to validate the input. If this is empty, no validation will be performed. | ||||||
|  |           type: string | ||||||
|  |         parameterSamples: | ||||||
|  |           description: These samples will be displayed in the UI to the user trying to configure the options | ||||||
|  |           type: array | ||||||
|  |           items: | ||||||
|  |             type: string | ||||||
|  |         helper: | ||||||
|  |           description: A link to a web page or PDF document explaining the algorithm and its parameters | ||||||
|  |           type: string | ||||||
|  |  | ||||||
|  |     Algorithms: | ||||||
|  |       description: The list of all algorithms supported by the vendor | ||||||
|  |       type: array | ||||||
|  |       items: | ||||||
|  |         $ref: '#/components/schemas/Algorithm' | ||||||
|  |  | ||||||
|  | paths: | ||||||
|  |   /provider: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - RRM | ||||||
|  |       operationId: getProvider | ||||||
|  |       summary: Retrieve information about the provider for this RRM Module | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/Provider' | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  |  | ||||||
|  |   /algorithms: | ||||||
|  |     get: | ||||||
|  |       tags: | ||||||
|  |         - RRM | ||||||
|  |       operationId: getAlgorithms | ||||||
|  |       summary: Retrieve a lists of algorithms supported in the module. | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           $ref: '#/components/schemas/Algorithms' | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  |  | ||||||
|  |   /runRRM: | ||||||
|  |     put: | ||||||
|  |       tags: | ||||||
|  |         - RRM | ||||||
|  |       operationId: runRRMNow | ||||||
|  |       summary: Run a specific or default RRM algorithm. The UI user or CLI user will have the ability to run an algorithm on demand. | ||||||
|  |       parameters: | ||||||
|  |         - in: query | ||||||
|  |           description: | ||||||
|  |           name: venue | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |             format: uuid | ||||||
|  |           required: true | ||||||
|  |         - in: query | ||||||
|  |           description: Perform RRM without updating anything. This may be used by an admin to see what RRM would do. | ||||||
|  |           name: mock | ||||||
|  |           schema: | ||||||
|  |             type: boolean | ||||||
|  |             default: false | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: Specify the RRM algorithm to use. If omitted, select the default algorithm. | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: false | ||||||
|  |         - in: query | ||||||
|  |           description: Specify the parameters to use with the RRM algorithm to use. If omitted, select the default parameters. | ||||||
|  |           schema: | ||||||
|  |             type: string | ||||||
|  |           required: false | ||||||
|  |       responses: | ||||||
|  |         200: | ||||||
|  |           description: Return the list of actions that were or would be performed. | ||||||
|  |           content: | ||||||
|  |             application/json: | ||||||
|  |               schema: | ||||||
|  |                 type: array | ||||||
|  |                 items: | ||||||
|  |                   type: string | ||||||
|  |         400: | ||||||
|  |           $ref: '#/components/responses/BadRequest' | ||||||
|  |         403: | ||||||
|  |           $ref: '#/components/responses/Unauthorized' | ||||||
|  |         404: | ||||||
|  |           $ref: '#/components/responses/NotFound' | ||||||
|  |  | ||||||
| @@ -34,6 +34,7 @@ openwifi.system.uri.private = https://localhost:17005 | |||||||
| openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16005 | openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16005 | ||||||
| openwifi.system.commandchannel = /tmp/app.owprov | openwifi.system.commandchannel = /tmp/app.owprov | ||||||
| openwifi.system.uri.ui = owprov-ui.arilia.com | openwifi.system.uri.ui = owprov-ui.arilia.com | ||||||
|  | openwifi.security.restapi.disable = false | ||||||
|  |  | ||||||
| firmware.updater.upgrade = false | firmware.updater.upgrade = false | ||||||
| firmware.updater.releaseonly = false | firmware.updater.releaseonly = false | ||||||
| @@ -115,4 +116,4 @@ storage.type.mysql.connectiontimeout = 60 | |||||||
| ######################################################################## | ######################################################################## | ||||||
| logging.type = file | logging.type = file | ||||||
| logging.path = $OWPROV_ROOT/logs | logging.path = $OWPROV_ROOT/logs | ||||||
| logging.level = debug | logging.level = debug | ||||||
|   | |||||||
| @@ -39,6 +39,7 @@ openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE} | |||||||
| openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC} | openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC} | ||||||
| openwifi.system.commandchannel = /tmp/app.ucentralfms | openwifi.system.commandchannel = /tmp/app.ucentralfms | ||||||
| openwifi.system.uri.ui = ${SYSTEM_URI_UI} | openwifi.system.uri.ui = ${SYSTEM_URI_UI} | ||||||
|  | openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE} | ||||||
|  |  | ||||||
| ############################# | ############################# | ||||||
| # Generic information for all micro services | # Generic information for all micro services | ||||||
|   | |||||||
| @@ -153,60 +153,62 @@ namespace OpenWifi { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         std::set<std::string>   Sections; |         try { | ||||||
|         for(const auto &i:Config_) { |             std::set<std::string> Sections; | ||||||
|             Poco::JSON::Parser  P; |             for (const auto &i: Config_) { | ||||||
|             auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>(); |                 Poco::JSON::Parser P; | ||||||
|             auto Names = O->getNames(); |                 auto O = P.parse(i.element.configuration).extract<Poco::JSON::Object::Ptr>(); | ||||||
|             for(const auto &SectionName:Names) { |                 auto Names = O->getNames(); | ||||||
|                 auto InsertInfo = Sections.insert(SectionName); |                 for (const auto &SectionName: Names) { | ||||||
|                 if (InsertInfo.second) { |                     auto InsertInfo = Sections.insert(SectionName); | ||||||
|                     if (O->isArray(SectionName)) { |                     if (InsertInfo.second) { | ||||||
|                         auto OriginalArray = O->getArray(SectionName); |                         if (O->isArray(SectionName)) { | ||||||
|                         if (Explain_) { |                             auto OriginalArray = O->getArray(SectionName); | ||||||
|                             Poco::JSON::Object ExObj; |                             if (Explain_) { | ||||||
|                             ExObj.set("from-uuid", i.info.id); |                                 Poco::JSON::Object ExObj; | ||||||
|                             ExObj.set("from-name", i.info.name); |                                 ExObj.set("from-uuid", i.info.id); | ||||||
|                             ExObj.set("action", "added"); |                                 ExObj.set("from-name", i.info.name); | ||||||
|                             ExObj.set("element", OriginalArray); |                                 ExObj.set("action", "added"); | ||||||
|                             Explanation_.add(ExObj); |                                 ExObj.set("element", OriginalArray); | ||||||
|  |                                 Explanation_.add(ExObj); | ||||||
|  |                             } | ||||||
|  |                             auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>(); | ||||||
|  |                             ReplaceVariablesInArray(OriginalArray, ExpandedArray); | ||||||
|  |                             Configuration->set(SectionName, ExpandedArray); | ||||||
|  |                         } else if (O->isObject(SectionName)) { | ||||||
|  |                             auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>(); | ||||||
|  |                             if (Explain_) { | ||||||
|  |                                 Poco::JSON::Object ExObj; | ||||||
|  |                                 ExObj.set("from-uuid", i.info.id); | ||||||
|  |                                 ExObj.set("from-name", i.info.name); | ||||||
|  |                                 ExObj.set("action", "added"); | ||||||
|  |                                 ExObj.set("element", OriginalSection); | ||||||
|  |                                 Explanation_.add(ExObj); | ||||||
|  |                             } | ||||||
|  |                             auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>(); | ||||||
|  |                             ReplaceVariablesInObject(OriginalSection, ExpandedSection); | ||||||
|  |                             Configuration->set(SectionName, ExpandedSection); | ||||||
|  |                         } else { | ||||||
|  |                             std::cout << " --- unknown element type --- " << O->get(SectionName).toString() | ||||||
|  |                                       << std::endl; | ||||||
|                         } |                         } | ||||||
|                         auto ExpandedArray = Poco::makeShared<Poco::JSON::Array>(); |  | ||||||
|                         ReplaceVariablesInArray(OriginalArray, ExpandedArray); |  | ||||||
|                         Configuration->set(SectionName, ExpandedArray); |  | ||||||
|                     } else if (O->isObject(SectionName)) { |  | ||||||
|                         auto OriginalSection = O->get(SectionName).extract<Poco::JSON::Object::Ptr>(); |  | ||||||
|                         if (Explain_) { |  | ||||||
|                             Poco::JSON::Object ExObj; |  | ||||||
|                             ExObj.set("from-uuid", i.info.id); |  | ||||||
|                             ExObj.set("from-name", i.info.name); |  | ||||||
|                             ExObj.set("action", "added"); |  | ||||||
|                             ExObj.set("element", OriginalSection); |  | ||||||
|                             Explanation_.add(ExObj); |  | ||||||
|                         } |  | ||||||
|                         auto ExpandedSection = Poco::makeShared<Poco::JSON::Object>(); |  | ||||||
|                         ReplaceVariablesInObject(OriginalSection, ExpandedSection); |  | ||||||
|                         Configuration->set(SectionName, ExpandedSection); |  | ||||||
|                     } else { |                     } else { | ||||||
|                         std::cout << " --- unknown element type --- " << O->get(SectionName).toString() << std::endl; |                         if (Explain_) { | ||||||
|                     } |                             Poco::JSON::Object ExObj; | ||||||
|                 } else { |                             ExObj.set("from-uuid", i.info.id); | ||||||
|                     if (Explain_) { |                             ExObj.set("from-name", i.info.name); | ||||||
|                         Poco::JSON::Object ExObj; |                             ExObj.set("action", "ignored"); | ||||||
|                         ExObj.set("from-uuid", i.info.id); |                             ExObj.set("reason", "weight insufficient"); | ||||||
|                         ExObj.set("from-name", i.info.name); |                             ExObj.set("element", O->get(SectionName)); | ||||||
|                         ExObj.set("action", "ignored"); |                             Explanation_.add(ExObj); | ||||||
|                         ExObj.set("reason", "weight insufficient"); |                         } | ||||||
|                         ExObj.set("element", O->get(SectionName)); |  | ||||||
|                         Explanation_.add(ExObj); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } catch (...) { | ||||||
|         if(Config_.empty()) |  | ||||||
|             return false; |  | ||||||
|  |  | ||||||
|         return true; |         } | ||||||
|  |         return !Config_.empty(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) { |     static bool DeviceTypeMatch(const std::string &DeviceType, const Types::StringVec & Types) { | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void AutoDiscovery::run() { |     void AutoDiscovery::run() { | ||||||
|         Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); |         Poco::AutoPtr<Poco::Notification>	Note(Queue_.waitDequeueNotification()); | ||||||
|  |         Utils::SetThreadName("auto-discovery"); | ||||||
|         while(Note && Running_) { |         while(Note && Running_) { | ||||||
|             auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get()); |             auto Msg = dynamic_cast<DiscoveryMessage *>(Note.get()); | ||||||
|             if(Msg!= nullptr) { |             if(Msg!= nullptr) { | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ namespace OpenWifi { | |||||||
|             void Stop() override; |             void Stop() override; | ||||||
|             void ConnectionReceived( const std::string & Key, const std::string & Payload) { |             void ConnectionReceived( const std::string & Key, const std::string & Payload) { | ||||||
|                 std::lock_guard G(Mutex_); |                 std::lock_guard G(Mutex_); | ||||||
|                 Logger().information(Poco::format("Device(%s): Connection/Ping message.", Key)); |                 poco_debug(Logger(),Poco::format("Device(%s): Connection/Ping message.", Key)); | ||||||
|                 Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload)); |                 Queue_.enqueueNotification( new DiscoveryMessage(Key,Payload)); | ||||||
|             } |             } | ||||||
|             void run() override; |             void run() override; | ||||||
|   | |||||||
| @@ -73,17 +73,25 @@ namespace OpenWifi { | |||||||
| } | } | ||||||
|  |  | ||||||
| int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||||
| 	try { |     int ExitCode; | ||||||
| 		auto App = OpenWifi::Daemon::instance(); |     try { | ||||||
| 		auto ExitCode =  App->run(argc, argv); |         Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr); | ||||||
| 		delete App; |         auto App = OpenWifi::Daemon::instance(); | ||||||
|  |         ExitCode =  App->run(argc, argv); | ||||||
|  |         Poco::Net::SSLManager::instance().shutdown(); | ||||||
|  |     } catch (Poco::Exception &exc) { | ||||||
|  |         ExitCode = Poco::Util::Application::EXIT_SOFTWARE; | ||||||
|  |         std::cout << exc.displayText() << std::endl; | ||||||
|  |     } catch (std::exception &exc) { | ||||||
|  |         ExitCode = Poco::Util::Application::EXIT_TEMPFAIL; | ||||||
|  |         std::cout << exc.what() << std::endl; | ||||||
|  |     } catch (...) { | ||||||
|  |         ExitCode = Poco::Util::Application::EXIT_TEMPFAIL; | ||||||
|  |         std::cout << "Exception on closure" << std::endl; | ||||||
|  |     } | ||||||
|  |  | ||||||
| 		return ExitCode; |     std::cout << "Exitcode: " << ExitCode << std::endl; | ||||||
|  |     return ExitCode; | ||||||
| 	} catch (Poco::Exception &exc) { |  | ||||||
| 		std::cerr << exc.displayText() << std::endl; |  | ||||||
| 		return Poco::Util::Application::EXIT_SOFTWARE; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // end of namespace | // end of namespace | ||||||
| @@ -26,6 +26,8 @@ namespace OpenWifi { | |||||||
|                 {"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" } |                 {"https://ucentral.io/ucentral.schema.pretty.json", "ucentral.schema.pretty.json" } | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|  |         Utils::SetThreadName("file-dmnldr"); | ||||||
|  |  | ||||||
|         for(const auto &[url,filename]:Files) { |         for(const auto &[url,filename]:Files) { | ||||||
|             try { |             try { | ||||||
|                 std::string FileContent; |                 std::string FileContent; | ||||||
|   | |||||||
| @@ -27,11 +27,32 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void JobController::run() { |     void JobController::run() { | ||||||
|         Running_ = true ; |         Running_ = true ; | ||||||
|  |         Utils::SetThreadName("job-controller"); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|             Poco::Thread::trySleep(2000); |             Poco::Thread::trySleep(2000); | ||||||
|  |  | ||||||
|  |             std::lock_guard G(Mutex_); | ||||||
|  |  | ||||||
|  |             for(auto ¤t_job:jobs_) { | ||||||
|  |                 if(current_job!=nullptr) { | ||||||
|  |                     if(current_job->Started()==0 && Pool_.used()<Pool_.available()) { | ||||||
|  |                         current_job->Logger().information(fmt::format("Starting {}: {}",current_job->JobId(),current_job->Name())); | ||||||
|  |                         current_job->Start(); | ||||||
|  |                         Pool_.start(*current_job); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for(auto it = jobs_.begin(); it!=jobs_.end();) {\ | ||||||
|  |                 auto current_job = *it; | ||||||
|  |                 if(current_job!=nullptr && current_job->Completed()!=0) { | ||||||
|  |                     current_job->Logger().information(fmt::format("Completed {}: {}",current_job->JobId(),current_job->Name())); | ||||||
|  |                     it = jobs_.erase(it); | ||||||
|  |                     delete current_job; | ||||||
|  |                 } else { | ||||||
|  |                     ++it; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -7,99 +7,45 @@ | |||||||
| #include <vector> | #include <vector> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <functional> | #include <functional> | ||||||
|  | #include <list> | ||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     class Job { |     class Job : public Poco::Runnable { | ||||||
|         public: |     public: | ||||||
|             struct Parameter { |         Job(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|                 std::string name; |             jobId_(JobID), | ||||||
|                 std::string value; |             name_(name), | ||||||
|                 inline void to_json(Poco::JSON::Object &Obj) const { |             parameters_(parameters), | ||||||
|                     RESTAPI_utils::field_to_json(Obj,"name",name); |             when_(when), | ||||||
|                     RESTAPI_utils::field_to_json(Obj,"value",value); |             userinfo_(UI), | ||||||
|                 } |             Logger_(L) | ||||||
|  |         {}; | ||||||
|  |  | ||||||
|                 inline bool from_json(const Poco::JSON::Object::Ptr &Obj) { |         virtual void run() = 0; | ||||||
|                     try { |         [[nodiscard]] std::string Name() const { return name_; } | ||||||
|                         RESTAPI_utils::field_from_json(Obj,"name",name); |         const SecurityObjects::UserInfo & UserInfo() const { return userinfo_; } | ||||||
|                         RESTAPI_utils::field_from_json(Obj,"value",value); |         Poco::Logger & Logger() { return Logger_; } | ||||||
|                         return true; |         const std::string & JobId() const { return jobId_; } | ||||||
|                     } catch (...) { |         const std::string & Parameter(int x) const { return parameters_[x];} | ||||||
|  |         uint64_t When() const { return when_; } | ||||||
|  |         void Start() { started_ = OpenWifi::Now(); } | ||||||
|  |         uint64_t Started() const { return started_; } | ||||||
|  |         uint64_t Completed() const { return completed_;} | ||||||
|  |         void Complete() { completed_ = OpenWifi::Now(); } | ||||||
|  |  | ||||||
|                     } |     private: | ||||||
|                     return false; |         std::string                 jobId_; | ||||||
|                 } |         std::string                 name_; | ||||||
|             }; |         std::vector<std::string>    parameters_; | ||||||
|  |         uint64_t                    when_=0; | ||||||
|             struct Status { |         SecurityObjects::UserInfo   userinfo_; | ||||||
|                 Types::UUID_t   UUID; |         Poco::Logger                & Logger_; | ||||||
|                 uint64_t        Start = 0 ; |         uint64_t                    started_=0; | ||||||
|                 uint64_t        Progress = 0 ; |         uint64_t                    completed_=0; | ||||||
|                 uint64_t        Completed = 0 ; |  | ||||||
|                 std::string     CurrentDisplay; |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             struct Result { |  | ||||||
|                 int         Error=0; |  | ||||||
|                 std::string Reason; |  | ||||||
|             }; |  | ||||||
|  |  | ||||||
|             typedef std::vector<Parameter>       Parameters; |  | ||||||
|             typedef std::vector<Parameters>      ParametersVec; |  | ||||||
|             typedef std::function<bool(const Parameters &Parameters, Result &Result, bool &Retry)>  WorkerFunction; |  | ||||||
|             typedef std::vector<Status>          Statuses; |  | ||||||
|  |  | ||||||
|             Job(std::string Title, |  | ||||||
|                          std::string Description, |  | ||||||
|                          std::string RegisteredName, |  | ||||||
|                          ParametersVec Parameters, |  | ||||||
|                          [[maybe_unused]] bool Parallel=true) : |  | ||||||
|                     Title_(std::move(Title)), |  | ||||||
|                     Description_(std::move(Description)), |  | ||||||
|                     RegisteredName_(std::move(RegisteredName)), |  | ||||||
|                     Parameters_(std::move(Parameters)) |  | ||||||
|                 { |  | ||||||
|                     UUID_ = MicroService::instance().CreateUUID(); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             [[nodiscard]] inline const Types::UUID_t & ID() const { return UUID_; } |  | ||||||
|  |  | ||||||
|         private: |  | ||||||
|             Types::UUID_t       UUID_; |  | ||||||
|             std::string         Title_; |  | ||||||
|             std::string         Description_; |  | ||||||
|             std::string         RegisteredName_; |  | ||||||
|             ParametersVec       Parameters_; |  | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class JobRegistry { |  | ||||||
|         public: |  | ||||||
|             static auto instance() { |  | ||||||
|                 static auto instance_ = new JobRegistry; |  | ||||||
|                 return instance_; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             inline void RegisterJobType( const std::string & JobType, Job::WorkerFunction Function) { |  | ||||||
|                     JobTypes_[JobType] = std::move(Function); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             inline bool Execute(const std::string &JobType, const Job::Parameters & Params, Job::Result &Result, bool & Retry) { |  | ||||||
|                 auto Hint = JobTypes_.find(JobType); |  | ||||||
|                 if(Hint != end(JobTypes_)) { |  | ||||||
|                     Hint->second(Params, Result, Retry); |  | ||||||
|                     return true; |  | ||||||
|                 } |  | ||||||
|                 return false; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         private: |  | ||||||
|             std::map<std::string,Job::WorkerFunction>  JobTypes_; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     inline auto JobRegistry() { return JobRegistry::instance(); } |  | ||||||
|  |  | ||||||
|     class JobController : public SubSystemServer, Poco::Runnable { |     class JobController : public SubSystemServer, Poco::Runnable { | ||||||
|         public: |         public: | ||||||
|             static auto instance() { |             static auto instance() { | ||||||
| @@ -112,11 +58,16 @@ namespace OpenWifi { | |||||||
|             void run() override; |             void run() override; | ||||||
|             inline void wakeup() { Thr_.wakeUp(); } |             inline void wakeup() { Thr_.wakeUp(); } | ||||||
|  |  | ||||||
|             bool JobList(Job::Statuses & Statuses); |             void AddJob( Job* newJob ) { | ||||||
|  |                 std::lock_guard G(Mutex_); | ||||||
|  |                 jobs_.push_back(newJob); | ||||||
|  |             } | ||||||
|  |  | ||||||
|         private: |         private: | ||||||
|             Poco::Thread            Thr_; |             Poco::Thread                        Thr_; | ||||||
|             std::atomic_bool        Running_=false; |             std::atomic_bool                    Running_=false; | ||||||
|  |             std::list<Job *>                    jobs_; | ||||||
|  |             Poco::ThreadPool                    Pool_; | ||||||
|  |  | ||||||
|         JobController() noexcept: |         JobController() noexcept: | ||||||
|             SubSystemServer("JobController", "JOB-SVR", "job") |             SubSystemServer("JobController", "JOB-SVR", "job") | ||||||
|   | |||||||
| @@ -23,6 +23,7 @@ namespace OpenWifi { | |||||||
|                                                               bool &Done, std::string &Answer) { |                                                               bool &Done, std::string &Answer) { | ||||||
|         Done = false; |         Done = false; | ||||||
|         auto Prefix = O->get("serial_prefix").toString(); |         auto Prefix = O->get("serial_prefix").toString(); | ||||||
|  |         Poco::toLowerInPlace(Prefix); | ||||||
|         Logger().information(Poco::format("serial_number_search: %s", Prefix)); |         Logger().information(Poco::format("serial_number_search: %s", Prefix)); | ||||||
|         if (!Prefix.empty() && Prefix.length() < 13) { |         if (!Prefix.empty() && Prefix.length() < 13) { | ||||||
|             std::vector<uint64_t> Numbers; |             std::vector<uint64_t> Numbers; | ||||||
| @@ -83,6 +84,7 @@ namespace OpenWifi { | |||||||
|         Done = false; |         Done = false; | ||||||
|         auto operatorId = O->get("operatorId").toString(); |         auto operatorId = O->get("operatorId").toString(); | ||||||
|         auto Prefix = O->get("serial_prefix").toString(); |         auto Prefix = O->get("serial_prefix").toString(); | ||||||
|  |         Poco::toLowerInPlace(Prefix); | ||||||
|         std::string Query; |         std::string Query; | ||||||
|  |  | ||||||
|         if(Prefix[0]=='*') { |         if(Prefix[0]=='*') { | ||||||
|   | |||||||
| @@ -9,6 +9,9 @@ | |||||||
| #include "framework/MicroService.h" | #include "framework/MicroService.h" | ||||||
| #include "framework/ConfigurationValidator.h" | #include "framework/ConfigurationValidator.h" | ||||||
| #include "sdks/SDK_sec.h" | #include "sdks/SDK_sec.h" | ||||||
|  | #include "Poco/StringTokenizer.h" | ||||||
|  |  | ||||||
|  | #include "libs/croncpp.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -405,7 +408,9 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) { |     inline bool ValidateConfigBlock(const ProvObjects::DeviceConfiguration &Config, RESTAPI::Errors::msg & Error) { | ||||||
|         static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", "unit" }; |         static const std::vector<std::string> SectionNames{ "globals", "interfaces", "metrics", "radios", "services", | ||||||
|  |                                                             "unit", "definitions", "ethernet", "switch", "config-raw", | ||||||
|  |                                                             "third-party" }; | ||||||
|  |  | ||||||
|         for(const auto &i:Config.configuration) { |         for(const auto &i:Config.configuration) { | ||||||
|             Poco::JSON::Parser  P; |             Poco::JSON::Parser  P; | ||||||
| @@ -521,12 +526,39 @@ namespace OpenWifi { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         return Result; |         return Result; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     inline bool ValidSchedule(const std::string &v) { | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             auto cron = cron::make_cron(v); | ||||||
|  |             return true; | ||||||
|  |         } | ||||||
|  |         catch (cron::bad_cronexpr const & ex) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline bool ValidRRM(const std::string &v) { | ||||||
|  |         if((v=="no") || (v=="inherit")) return true; | ||||||
|  |         try { | ||||||
|  |             Poco::JSON::Parser  P; | ||||||
|  |             auto O = P.parse(v).extract<Poco::JSON::Object::Ptr>(); | ||||||
|  |  | ||||||
|  |             ProvObjects::RRMDetails D; | ||||||
|  |             if(D.from_json(O)) { | ||||||
|  |                 return ValidSchedule(D.schedule); | ||||||
|  |             } | ||||||
|  |         } catch (...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     inline bool ValidDeviceRules(const ProvObjects::DeviceRules & DR) { |     inline bool ValidDeviceRules(const ProvObjects::DeviceRules & DR) { | ||||||
|         return  (DR.rrm=="yes" || DR.rrm=="no" || DR.rrm=="inherit") && |         return  (ValidRRM(DR.rrm)) && | ||||||
|                 (DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") && |                 (DR.firmwareUpgrade=="yes" || DR.firmwareUpgrade=="no" || DR.firmwareUpgrade=="inherit") && | ||||||
|                 (DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit"); |                 (DR.rcOnly=="yes" || DR.rcOnly=="no" || DR.rcOnly=="inherit"); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -35,36 +35,53 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|     void RESTAPI_inventory_handler::DoGet() { |     void RESTAPI_inventory_handler::DoGet() { | ||||||
|  |  | ||||||
|         ProvObjects::InventoryTag   Existing; |         ProvObjects::InventoryTag Existing; | ||||||
|         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); |         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, ""); | ||||||
|         Logger().debug(Poco::format("%s: Retrieving inventory information.",SerialNumber)); |         Logger().debug(Poco::format("%s: Retrieving inventory information.", SerialNumber)); | ||||||
|         if(SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER,SerialNumber,Existing)) { |         if (SerialNumber.empty() || !DB_.GetRecord(RESTAPI::Protocol::SERIALNUMBER, SerialNumber, Existing)) { | ||||||
|             return NotFound(); |             return NotFound(); | ||||||
|         } |         } | ||||||
|         Logger().debug(Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id )); |         Logger().debug( | ||||||
|  |                 Poco::format("%s,%s: Retrieving inventory information.", Existing.serialNumber, Existing.info.id)); | ||||||
|  |  | ||||||
|         Poco::JSON::Object  Answer; |         Poco::JSON::Object Answer; | ||||||
|         std::string Arg; |         std::string Arg; | ||||||
|         if(HasParameter("config",Arg) && Arg=="true") { |         if (HasParameter("config", Arg) && Arg == "true") { | ||||||
|             bool Explain = (HasParameter("explain",Arg) && Arg == "true"); |             bool Explain = (HasParameter("explain", Arg) && Arg == "true"); | ||||||
|             APConfig    Device(SerialNumber,Existing.deviceType,Logger(), Explain); |             APConfig Device(SerialNumber, Existing.deviceType, Logger(), Explain); | ||||||
|  |  | ||||||
|             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); |             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||||
|             if(Device.Get(Configuration)) { |             if (Device.Get(Configuration)) { | ||||||
|                 Answer.set("config", Configuration); |                 Answer.set("config", Configuration); | ||||||
|                 if(Explain) |                 if (Explain) | ||||||
|                     Answer.set("explanation", Device.Explanation()); |                     Answer.set("explanation", Device.Explanation()); | ||||||
|             } else { |             } else { | ||||||
|                 Answer.set("config","none"); |                 Answer.set("config", "none"); | ||||||
|             } |             } | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|         } else if(HasParameter("firmwareOptions", Arg) && Arg=="true") { |         } else if (GetBoolParameter("firmwareOptions", false)) { | ||||||
|             ProvObjects::DeviceRules Rules; |             ProvObjects::DeviceRules Rules; | ||||||
|             StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber,Rules); |             StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); | ||||||
|             Answer.set("firmwareUpgrade",Rules.firmwareUpgrade); |             Answer.set("firmwareUpgrade", Rules.firmwareUpgrade); | ||||||
|             Answer.set("firmwareRCOnly", Rules.rcOnly == "yes" ); |             Answer.set("firmwareRCOnly", Rules.rcOnly == "yes"); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|         } else if(HasParameter("applyConfiguration",Arg) && Arg=="true") { |         } else if(GetBoolParameter("rrmSettings",false)) { | ||||||
|  |             ProvObjects::DeviceRules Rules; | ||||||
|  |             StorageService()->InventoryDB().EvaluateDeviceSerialNumberRules(SerialNumber, Rules); | ||||||
|  |             if(Rules.rrm=="no" || Rules.rrm=="inherit") { | ||||||
|  |                 Answer.set("rrm", Rules.rrm); | ||||||
|  |             } else { | ||||||
|  |                 ProvObjects::RRMDetails D; | ||||||
|  |                 Poco::JSON::Parser  P; | ||||||
|  |                 try { | ||||||
|  |                     auto Obj = P.parse(Rules.rrm).extract<Poco::JSON::Object::Ptr>(); | ||||||
|  |                     Answer.set("rrm", Obj); | ||||||
|  |                 } catch (...) { | ||||||
|  |                     Answer.set("rrm", "invalid"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return ReturnObject(Answer); | ||||||
|  |         } else if(GetBoolParameter("applyConfiguration", false)) { | ||||||
|             Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber)); |             Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber)); | ||||||
|             auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); |             auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); | ||||||
|             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); |             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||||
| @@ -91,6 +108,19 @@ namespace OpenWifi{ | |||||||
|             } |             } | ||||||
|             Results.to_json(Answer); |             Results.to_json(Answer); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|  |         } else if(GetBoolParameter("resolveConfig", false)) { | ||||||
|  |             Logger().debug(Poco::format("%s: Retrieving configuration.",Existing.serialNumber)); | ||||||
|  |             auto Device = std::make_shared<APConfig>(SerialNumber, Existing.deviceType, Logger(), false); | ||||||
|  |             auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||||
|  |             Poco::JSON::Object ErrorsObj, WarningsObj; | ||||||
|  |             ProvObjects::InventoryConfigApplyResult Results; | ||||||
|  |             Logger().debug(Poco::format("%s: Computing configuration.",Existing.serialNumber)); | ||||||
|  |             if (Device->Get(Configuration)) { | ||||||
|  |                 Answer.set("configuration", Configuration); | ||||||
|  |             } else { | ||||||
|  |                 Answer.set("error", 1); | ||||||
|  |             } | ||||||
|  |             return ReturnObject(Answer); | ||||||
|         }   else if(QB_.AdditionalInfo) { |         }   else if(QB_.AdditionalInfo) { | ||||||
|             AddExtendedInfo(Existing,Answer); |             AddExtendedInfo(Existing,Answer); | ||||||
|         } |         } | ||||||
| @@ -136,6 +166,7 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|     void RESTAPI_inventory_handler::DoPost() { |     void RESTAPI_inventory_handler::DoPost() { | ||||||
|         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); |         std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER,""); | ||||||
|  |         Poco::toLowerInPlace(SerialNumber); | ||||||
|         if(SerialNumber.empty()) { |         if(SerialNumber.empty()) { | ||||||
|             return BadRequest(RESTAPI::Errors::MissingSerialNumber); |             return BadRequest(RESTAPI::Errors::MissingSerialNumber); | ||||||
|         } |         } | ||||||
| @@ -154,6 +185,11 @@ namespace OpenWifi{ | |||||||
|             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); |             return BadRequest(RESTAPI::Errors::InvalidJSONDocument); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         NormalizeMac(NewObject.serialNumber); | ||||||
|  |         if(SerialNumber!=NewObject.serialNumber) { | ||||||
|  |             return BadRequest(RESTAPI::Errors::SerialNumberMismatch); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules,*this))) { |         if((RawObject->has("deviceRules") && !ValidDeviceRules(NewObject.deviceRules,*this))) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -101,7 +101,7 @@ namespace OpenWifi { | |||||||
|                 { "email", UserName }, |                 { "email", UserName }, | ||||||
|                 { "signupUUID" , SignupUUID }, |                 { "signupUUID" , SignupUUID }, | ||||||
|                 { "owner" , SignupOperator.info.id }, |                 { "owner" , SignupOperator.info.id }, | ||||||
|  |                 { "operatorName", SignupOperator.registrationId } | ||||||
|         }, Body, 30000); |         }, Body, 30000); | ||||||
|  |  | ||||||
|         Poco::JSON::Object::Ptr Answer; |         Poco::JSON::Object::Ptr Answer; | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ namespace OpenWifi{ | |||||||
|             for (const auto &i: V.children) { |             for (const auto &i: V.children) { | ||||||
|                 ProvObjects::Venue V2; |                 ProvObjects::Venue V2; | ||||||
|                 if (StorageService()->VenueDB().GetRecord("id", i, V2)) { |                 if (StorageService()->VenueDB().GetRecord("id", i, V2)) { | ||||||
|  |                     std::copy(V2.devices.begin(),V2.devices.end(),std::back_inserter(R)); | ||||||
|                     auto LowerDevs = GetDevices(V2, GetChildren); |                     auto LowerDevs = GetDevices(V2, GetChildren); | ||||||
|                     std::copy(LowerDevs.begin(), LowerDevs.end(), std::back_inserter(R)); |                     std::copy(LowerDevs.begin(), LowerDevs.end(), std::back_inserter(R)); | ||||||
|                 } |                 } | ||||||
| @@ -227,10 +228,10 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             SNL.serialNumbers = Existing.devices; |             SNL.serialNumbers = Existing.devices; | ||||||
|  |             auto JobId = MicroService::instance().CreateUUID(); | ||||||
|             auto Task = new VenueConfigUpdater(UUID,UserInfo_.userinfo,0,Logger()); |             Types::StringVec Parameters{UUID};; | ||||||
|             auto JobId = Task->Start(); |             auto NewJob = new VenueConfigUpdater(JobId,"VenueConfigurationUpdater", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||||
|  |             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||||
|             SNL.to_json(Answer); |             SNL.to_json(Answer); | ||||||
|             Answer.set("jobId",JobId); |             Answer.set("jobId",JobId); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
| @@ -241,10 +242,10 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             SNL.serialNumbers = Existing.devices; |             SNL.serialNumbers = Existing.devices; | ||||||
|  |             auto JobId = MicroService::instance().CreateUUID(); | ||||||
|             auto Task = new VenueUpgrade(UUID,UserInfo_.userinfo,0,Logger()); |             Types::StringVec Parameters{UUID};; | ||||||
|             auto JobId = Task->Start(); |             auto NewJob = new VenueUpgrade(JobId,"VenueFirmwareUpgrade", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||||
|  |             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||||
|             SNL.to_json(Answer); |             SNL.to_json(Answer); | ||||||
|             Answer.set("jobId",JobId); |             Answer.set("jobId",JobId); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
| @@ -255,10 +256,10 @@ namespace OpenWifi{ | |||||||
|  |  | ||||||
|             Poco::JSON::Object  Answer; |             Poco::JSON::Object  Answer; | ||||||
|             SNL.serialNumbers = Existing.devices; |             SNL.serialNumbers = Existing.devices; | ||||||
|  |             auto JobId = MicroService::instance().CreateUUID(); | ||||||
|             auto Task = new VenueRebooter(UUID,UserInfo_.userinfo,0,Logger()); |             Types::StringVec Parameters{UUID};; | ||||||
|             auto JobId = Task->Start(); |             auto NewJob = new VenueRebooter(JobId,"VenueRebooter", Parameters, 0, UserInfo_.userinfo, Logger()); | ||||||
|  |             JobController()->AddJob(dynamic_cast<Job*>(NewJob)); | ||||||
|             SNL.to_json(Answer); |             SNL.to_json(Answer); | ||||||
|             Answer.set("jobId",JobId); |             Answer.set("jobId",JobId); | ||||||
|             return ReturnObject(Answer); |             return ReturnObject(Answer); | ||||||
|   | |||||||
| @@ -538,8 +538,8 @@ namespace OpenWifi::AnalyticsObjects { | |||||||
|  |  | ||||||
|     void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const { |     void WifiClientHistory::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         field_to_json(Obj,"timestamp",timestamp); |         field_to_json(Obj,"timestamp",timestamp); | ||||||
|         field_to_json(Obj,"stationId",stationId); |         field_to_json(Obj,"station_id",station_id); | ||||||
|         field_to_json(Obj,"bssId",bssId); |         field_to_json(Obj,"bssid",bssid); | ||||||
|         field_to_json(Obj,"ssid",ssid); |         field_to_json(Obj,"ssid",ssid); | ||||||
|         field_to_json(Obj,"rssi",rssi); |         field_to_json(Obj,"rssi",rssi); | ||||||
|         field_to_json(Obj,"rx_bitrate",rx_bitrate); |         field_to_json(Obj,"rx_bitrate",rx_bitrate); | ||||||
| @@ -573,13 +573,14 @@ namespace OpenWifi::AnalyticsObjects { | |||||||
|         field_to_json(Obj,"connected",connected); |         field_to_json(Obj,"connected",connected); | ||||||
|         field_to_json(Obj,"inactive",inactive); |         field_to_json(Obj,"inactive",inactive); | ||||||
|         field_to_json(Obj,"tx_retries",tx_retries); |         field_to_json(Obj,"tx_retries",tx_retries); | ||||||
|  |         field_to_json(Obj,"venue_id",venue_id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool WifiClientHistory::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|         try { |         try { | ||||||
|             field_from_json(Obj,"timestamp",timestamp); |             field_from_json(Obj,"timestamp",timestamp); | ||||||
|             field_from_json(Obj,"stationId",stationId); |             field_from_json(Obj,"station_id",station_id); | ||||||
|             field_from_json(Obj,"bssId",bssId); |             field_from_json(Obj,"bssid",bssid); | ||||||
|             field_from_json(Obj,"ssid",ssid); |             field_from_json(Obj,"ssid",ssid); | ||||||
|             field_from_json(Obj,"rssi",rssi); |             field_from_json(Obj,"rssi",rssi); | ||||||
|             field_from_json(Obj,"rx_bitrate",rx_bitrate); |             field_from_json(Obj,"rx_bitrate",rx_bitrate); | ||||||
| @@ -613,6 +614,7 @@ namespace OpenWifi::AnalyticsObjects { | |||||||
|             field_from_json(Obj,"connected",connected); |             field_from_json(Obj,"connected",connected); | ||||||
|             field_from_json(Obj,"inactive",inactive); |             field_from_json(Obj,"inactive",inactive); | ||||||
|             field_from_json(Obj,"tx_retries",tx_retries); |             field_from_json(Obj,"tx_retries",tx_retries); | ||||||
|  |             field_from_json(Obj,"venue_id",venue_id); | ||||||
|             return true; |             return true; | ||||||
|         } catch(...) { |         } catch(...) { | ||||||
|  |  | ||||||
|   | |||||||
| @@ -376,8 +376,8 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|         struct WifiClientHistory { |         struct WifiClientHistory { | ||||||
|             uint64_t        timestamp=OpenWifi::Now(); |             uint64_t        timestamp=OpenWifi::Now(); | ||||||
|             std::string     stationId; |             std::string     station_id; | ||||||
|             std::string     bssId; |             std::string     bssid; | ||||||
|             std::string     ssid; |             std::string     ssid; | ||||||
|             int64_t         rssi=0; |             int64_t         rssi=0; | ||||||
|             uint32_t        rx_bitrate=0; |             uint32_t        rx_bitrate=0; | ||||||
| @@ -411,6 +411,7 @@ namespace OpenWifi { | |||||||
|             uint64_t        connected=0; |             uint64_t        connected=0; | ||||||
|             uint64_t        inactive=0; |             uint64_t        inactive=0; | ||||||
|             uint64_t        tx_retries=0; |             uint64_t        tx_retries=0; | ||||||
|  |             std::string     venue_id; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|   | |||||||
| @@ -3,176 +3,206 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| #include "RESTAPI_CertObjects.h" | #include "RESTAPI_CertObjects.h" | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
| using OpenWifi::RESTAPI_utils::field_to_json; | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
| using OpenWifi::RESTAPI_utils::field_from_json; | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi::CertObjects { | ||||||
|     namespace  CertObjects { |     void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|         void CertificateEntry::to_json(Poco::JSON::Object &Obj) const { |         field_to_json(Obj,"id", id); | ||||||
|             field_to_json(Obj,"id", id); |         field_to_json(Obj,"entity", entity); | ||||||
|             field_to_json(Obj,"entity", entity); |         field_to_json(Obj,"creator", creator); | ||||||
|             field_to_json(Obj,"creator", creator); |         field_to_json(Obj,"type", type); | ||||||
|             field_to_json(Obj,"type", type); |         field_to_json(Obj,"status", status); | ||||||
|             field_to_json(Obj,"status", status); |         field_to_json(Obj,"certificate", certificate); | ||||||
|             field_to_json(Obj,"certificate", certificate); |         field_to_json(Obj,"key", key); | ||||||
|             field_to_json(Obj,"key", key); |         field_to_json(Obj,"devid", devid); | ||||||
|             field_to_json(Obj,"devid", devid); |         field_to_json(Obj,"cas", cas); | ||||||
|             field_to_json(Obj,"cas", cas); |         field_to_json(Obj,"manufacturer", manufacturer); | ||||||
|             field_to_json(Obj,"manufacturer", manufacturer); |         field_to_json(Obj,"model", model); | ||||||
|             field_to_json(Obj,"model", model); |         field_to_json(Obj,"redirector", redirector); | ||||||
|             field_to_json(Obj,"redirector", redirector); |         field_to_json(Obj,"commonName", commonName); | ||||||
|             field_to_json(Obj,"commonName", commonName); |         field_to_json(Obj,"certificateId", certificateId); | ||||||
|             field_to_json(Obj,"certificateId", certificateId); |         field_to_json(Obj,"batch", batch); | ||||||
|             field_to_json(Obj,"batch", batch); |         field_to_json(Obj,"created", created); | ||||||
|             field_to_json(Obj,"created", created); |         field_to_json(Obj,"modified", modified); | ||||||
|             field_to_json(Obj,"modified", modified); |         field_to_json(Obj,"revoked", revoked); | ||||||
|             field_to_json(Obj,"revoked", revoked); |         field_to_json(Obj,"revokeCount", revokeCount); | ||||||
|             field_to_json(Obj,"revokeCount", revokeCount); |         field_to_json(Obj,"synched", synched); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|             try { |         try { | ||||||
|                 field_from_json(Obj,"id", id); |             field_from_json(Obj,"id", id); | ||||||
|                 field_from_json(Obj,"entity", entity); |             field_from_json(Obj,"entity", entity); | ||||||
|                 field_from_json(Obj,"creator", creator); |             field_from_json(Obj,"creator", creator); | ||||||
|                 field_from_json(Obj,"type", type); |             field_from_json(Obj,"type", type); | ||||||
|                 field_from_json(Obj,"status", status); |             field_from_json(Obj,"status", status); | ||||||
|                 field_from_json(Obj,"certificate", certificate); |             field_from_json(Obj,"certificate", certificate); | ||||||
|                 field_from_json(Obj,"key", key); |             field_from_json(Obj,"key", key); | ||||||
|                 field_from_json(Obj,"devid", devid); |             field_from_json(Obj,"devid", devid); | ||||||
|                 field_from_json(Obj,"cas", cas); |             field_from_json(Obj,"cas", cas); | ||||||
|                 field_from_json(Obj,"manufacturer", manufacturer); |             field_from_json(Obj,"manufacturer", manufacturer); | ||||||
|                 field_from_json(Obj,"model", model); |             field_from_json(Obj,"model", model); | ||||||
|                 field_from_json(Obj,"redirector", redirector); |             field_from_json(Obj,"redirector", redirector); | ||||||
|                 field_from_json(Obj,"commonName", commonName); |             field_from_json(Obj,"commonName", commonName); | ||||||
|                 field_from_json(Obj,"certificateId", certificateId); |             field_from_json(Obj,"certificateId", certificateId); | ||||||
|                 field_from_json(Obj,"batch", batch); |             field_from_json(Obj,"batch", batch); | ||||||
|                 field_from_json(Obj,"created", created); |             field_from_json(Obj,"created", created); | ||||||
|                 field_from_json(Obj,"modified", modified); |             field_from_json(Obj,"modified", modified); | ||||||
|                 field_from_json(Obj,"revoked", revoked); |             field_from_json(Obj,"revoked", revoked); | ||||||
|                 field_from_json(Obj,"revokeCount", revokeCount); |             field_from_json(Obj,"revokeCount", revokeCount); | ||||||
|                 return true; |             field_from_json(Obj,"synched", synched); | ||||||
|             } catch (...) { |             return true; | ||||||
|             } |         } catch (...) { | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|         void EntityEntry::to_json(Poco::JSON::Object &Obj) const { |     void EntityEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|             field_to_json(Obj,"id", id); |         field_to_json(Obj,"id", id); | ||||||
|             field_to_json(Obj,"creator", creator); |         field_to_json(Obj,"creator", creator); | ||||||
|             field_to_json(Obj,"name", name); |         field_to_json(Obj,"name", name); | ||||||
|             field_to_json(Obj,"description", description); |         field_to_json(Obj,"description", description); | ||||||
|             field_to_json(Obj,"defaultRedirector", defaultRedirector); |         field_to_json(Obj,"defaultRedirector", defaultRedirector); | ||||||
|             field_to_json(Obj,"apiKey", apiKey); |         field_to_json(Obj,"apiKey", apiKey); | ||||||
|             field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); |         field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); | ||||||
|             field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); |         field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); | ||||||
|             field_to_json(Obj,"organization", organization); |         field_to_json(Obj,"organization", organization); | ||||||
|             field_to_json(Obj,"created", created); |         field_to_json(Obj,"created", created); | ||||||
|             field_to_json(Obj,"modified", modified); |         field_to_json(Obj,"modified", modified); | ||||||
|             field_to_json(Obj,"suspended", suspended); |         field_to_json(Obj,"suspended", suspended); | ||||||
|             field_to_json(Obj,"deleted", deleted); |         field_to_json(Obj,"deleted", deleted); | ||||||
|             field_to_json(Obj,"notes", notes); |         field_to_json(Obj,"notes", notes); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|             try { |         try { | ||||||
|                 field_from_json(Obj,"id", id); |             field_from_json(Obj,"id", id); | ||||||
|                 field_from_json(Obj,"creator", creator); |             field_from_json(Obj,"creator", creator); | ||||||
|                 field_from_json(Obj,"name", name); |             field_from_json(Obj,"name", name); | ||||||
|                 field_from_json(Obj,"description", description); |             field_from_json(Obj,"description", description); | ||||||
|                 field_from_json(Obj,"defaultRedirector", defaultRedirector); |             field_from_json(Obj,"defaultRedirector", defaultRedirector); | ||||||
|                 field_from_json(Obj,"apiKey", apiKey); |             field_from_json(Obj,"apiKey", apiKey); | ||||||
|                 field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); |             field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile); | ||||||
|                 field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); |             field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile); | ||||||
|                 field_from_json(Obj,"organization", organization); |             field_from_json(Obj,"organization", organization); | ||||||
|                 field_from_json(Obj,"created", created); |             field_from_json(Obj,"created", created); | ||||||
|                 field_from_json(Obj,"modified", modified); |             field_from_json(Obj,"modified", modified); | ||||||
|                 field_from_json(Obj,"suspended", suspended); |             field_from_json(Obj,"suspended", suspended); | ||||||
|                 field_from_json(Obj,"deleted", deleted); |             field_from_json(Obj,"deleted", deleted); | ||||||
|                 field_from_json(Obj,"notes", notes); |             field_from_json(Obj,"notes", notes); | ||||||
|                 return true; |             return true; | ||||||
|             } catch (...) { |         } catch (...) { | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|         void BatchEntry::to_json(Poco::JSON::Object &Obj) const { |     void BatchEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|             field_to_json(Obj,"id", id); |         field_to_json(Obj,"id", id); | ||||||
|             field_to_json(Obj,"entity", entity); |         field_to_json(Obj,"entity", entity); | ||||||
|             field_to_json(Obj,"creator", creator); |         field_to_json(Obj,"creator", creator); | ||||||
|             field_to_json(Obj,"name", name); |         field_to_json(Obj,"name", name); | ||||||
|             field_to_json(Obj,"description", description); |         field_to_json(Obj,"description", description); | ||||||
|             field_to_json(Obj,"manufacturer", manufacturer); |         field_to_json(Obj,"manufacturer", manufacturer); | ||||||
|             field_to_json(Obj,"model", model); |         field_to_json(Obj,"model", model); | ||||||
|             field_to_json(Obj,"redirector", redirector); |         field_to_json(Obj,"redirector", redirector); | ||||||
|             field_to_json(Obj,"commonNames", commonNames); |         field_to_json(Obj,"commonNames", commonNames); | ||||||
|             field_to_json(Obj,"jobHistory", jobHistory); |         field_to_json(Obj,"jobHistory", jobHistory); | ||||||
|             field_to_json(Obj,"notes", notes); |         field_to_json(Obj,"notes", notes); | ||||||
|             field_to_json(Obj,"submitted", submitted); |         field_to_json(Obj,"submitted", submitted); | ||||||
|             field_to_json(Obj,"started", started); |         field_to_json(Obj,"started", started); | ||||||
|             field_to_json(Obj,"completed", completed); |         field_to_json(Obj,"completed", completed); | ||||||
|             field_to_json(Obj,"modified", modified); |         field_to_json(Obj,"modified", modified); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|             try { |         try { | ||||||
|                 field_from_json(Obj,"id", id); |             field_from_json(Obj,"id", id); | ||||||
|                 field_from_json(Obj,"entity", entity); |             field_from_json(Obj,"entity", entity); | ||||||
|                 field_from_json(Obj,"creator", creator); |             field_from_json(Obj,"creator", creator); | ||||||
|                 field_from_json(Obj,"name", name); |             field_from_json(Obj,"name", name); | ||||||
|                 field_from_json(Obj,"description", description); |             field_from_json(Obj,"description", description); | ||||||
|                 field_from_json(Obj,"manufacturer", manufacturer); |             field_from_json(Obj,"manufacturer", manufacturer); | ||||||
|                 field_from_json(Obj,"model", model); |             field_from_json(Obj,"model", model); | ||||||
|                 field_from_json(Obj,"redirector", redirector); |             field_from_json(Obj,"redirector", redirector); | ||||||
|                 field_from_json(Obj,"commonNames", commonNames); |             field_from_json(Obj,"commonNames", commonNames); | ||||||
|                 field_from_json(Obj,"jobHistory", jobHistory); |             field_from_json(Obj,"jobHistory", jobHistory); | ||||||
|                 field_from_json(Obj,"notes", notes); |             field_from_json(Obj,"notes", notes); | ||||||
|                 field_from_json(Obj,"submitted", submitted); |             field_from_json(Obj,"submitted", submitted); | ||||||
|                 field_from_json(Obj,"started", started); |             field_from_json(Obj,"started", started); | ||||||
|                 field_from_json(Obj,"completed", completed); |             field_from_json(Obj,"completed", completed); | ||||||
|                 field_from_json(Obj,"modified", modified); |             field_from_json(Obj,"modified", modified); | ||||||
|                 return true; |             return true; | ||||||
|             } catch (...) { |         } catch (...) { | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|         void JobEntry::to_json(Poco::JSON::Object &Obj) const { |     void JobEntry::to_json(Poco::JSON::Object &Obj) const { | ||||||
|             field_to_json(Obj,"id", id); |         field_to_json(Obj,"id", id); | ||||||
|             field_to_json(Obj,"entity", entity); |         field_to_json(Obj,"entity", entity); | ||||||
|             field_to_json(Obj,"creator", creator); |         field_to_json(Obj,"creator", creator); | ||||||
|             field_to_json(Obj,"batch", batch); |         field_to_json(Obj,"batch", batch); | ||||||
|             field_to_json(Obj,"commonNames", commonNames); |         field_to_json(Obj,"commonNames", commonNames); | ||||||
|             field_to_json(Obj,"completedNames", completedNames); |         field_to_json(Obj,"completedNames", completedNames); | ||||||
|             field_to_json(Obj,"errorNames", errorNames); |         field_to_json(Obj,"errorNames", errorNames); | ||||||
|             field_to_json(Obj,"status", status); |         field_to_json(Obj,"status", status); | ||||||
|             field_to_json(Obj,"command", command); |         field_to_json(Obj,"command", command); | ||||||
|             field_to_json(Obj,"parameters", parameters); |         field_to_json(Obj,"parameters", parameters); | ||||||
|             field_to_json(Obj,"submitted", submitted); |         field_to_json(Obj,"submitted", submitted); | ||||||
|             field_to_json(Obj,"started", started); |         field_to_json(Obj,"started", started); | ||||||
|             field_to_json(Obj,"completed", completed); |         field_to_json(Obj,"completed", completed); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { |     bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|             try { |         try { | ||||||
|                 field_from_json(Obj,"id", id); |             field_from_json(Obj,"id", id); | ||||||
|                 field_from_json(Obj,"entity", entity); |             field_from_json(Obj,"entity", entity); | ||||||
|                 field_from_json(Obj,"creator", creator); |             field_from_json(Obj,"creator", creator); | ||||||
|                 field_from_json(Obj,"batch", batch); |             field_from_json(Obj,"batch", batch); | ||||||
|                 field_from_json(Obj,"commonNames", commonNames); |             field_from_json(Obj,"commonNames", commonNames); | ||||||
|                 field_from_json(Obj,"completedNames", completedNames); |             field_from_json(Obj,"completedNames", completedNames); | ||||||
|                 field_from_json(Obj,"errorNames", errorNames); |             field_from_json(Obj,"errorNames", errorNames); | ||||||
|                 field_from_json(Obj,"status", status); |             field_from_json(Obj,"status", status); | ||||||
|                 field_from_json(Obj,"command", command); |             field_from_json(Obj,"command", command); | ||||||
|                 field_from_json(Obj,"parameters", parameters); |             field_from_json(Obj,"parameters", parameters); | ||||||
|                 field_from_json(Obj,"submitted", submitted); |             field_from_json(Obj,"submitted", submitted); | ||||||
|                 field_from_json(Obj,"started", started); |             field_from_json(Obj,"started", started); | ||||||
|                 field_from_json(Obj,"completed", completed); |             field_from_json(Obj,"completed", completed); | ||||||
|                 return true; |             return true; | ||||||
|             } catch (...) { |         } catch (...) { | ||||||
|             } |  | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "year", year); | ||||||
|  |         field_to_json(Obj, "activeCerts", activeCerts); | ||||||
|  |         field_to_json(Obj, "revokedCerts", revokedCerts); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"snapshot", snapshot); | ||||||
|  |         field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts); | ||||||
|  |         field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts); | ||||||
|  |         field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization); | ||||||
|  |         field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization); | ||||||
|  |         field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors); | ||||||
|  |         field_to_json(Obj,"deviceTypes", deviceTypes); | ||||||
|  |         field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts); | ||||||
|  |         field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::reset() { | ||||||
|  |         snapshot=0; | ||||||
|  |         numberOfRevokedCerts = numberOfIssuedCerts = 0; | ||||||
|  |         activeCertsPerOrganization.clear(); | ||||||
|  |         revokedCertsPerOrganization.clear(); | ||||||
|  |         numberOfRedirectors.clear(); | ||||||
|  |         deviceTypes.clear(); | ||||||
|  |         monthlyNumberOfCerts.clear(); | ||||||
|  |         monthlyNumberOfCertsPerOrgPerYear.clear(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -5,97 +5,118 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include "framework/MicroService.h" |  | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
| #include "RESTObjects/RESTAPI_SecurityObjects.h" | #include "RESTObjects/RESTAPI_SecurityObjects.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi::CertObjects { | ||||||
|  |  | ||||||
|     namespace CertObjects { |     struct CertificateEntry { | ||||||
|  |         OpenWifi::Types::UUID_t         id; | ||||||
|  |         OpenWifi::Types::UUID_t         entity; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         std::string                     type; | ||||||
|  |         std::string                     status; | ||||||
|  |         std::string                     certificate; | ||||||
|  |         std::string                     key; | ||||||
|  |         std::string                     devid; | ||||||
|  |         std::string                     cas; | ||||||
|  |         std::string                     manufacturer; | ||||||
|  |         std::string                     model; | ||||||
|  |         std::string                     redirector; | ||||||
|  |         std::string                     commonName; | ||||||
|  |         std::string                     certificateId; | ||||||
|  |         OpenWifi::Types::UUID_t         batch; | ||||||
|  |         uint64_t                        created = 0; | ||||||
|  |         uint64_t                        modified = 0; | ||||||
|  |         uint64_t                        revoked = 0; | ||||||
|  |         uint64_t                        revokeCount = 0; | ||||||
|  |         uint64_t                        synched = 0; | ||||||
|  |  | ||||||
|         struct CertificateEntry { |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             OpenWifi::Types::UUID_t         id; |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             OpenWifi::Types::UUID_t         entity; |     }; | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             std::string                     type; |  | ||||||
|             std::string                     status; |  | ||||||
|             std::string                     certificate; |  | ||||||
|             std::string                     key; |  | ||||||
|             std::string                     devid; |  | ||||||
|             std::string                     cas; |  | ||||||
|             std::string                     manufacturer; |  | ||||||
|             std::string                     model; |  | ||||||
|             std::string                     redirector; |  | ||||||
|             std::string                     commonName; |  | ||||||
|             std::string                     certificateId; |  | ||||||
|             OpenWifi::Types::UUID_t         batch; |  | ||||||
|             uint64_t                        created = 0; |  | ||||||
|             uint64_t                        modified = 0; |  | ||||||
|             uint64_t                        revoked = 0; |  | ||||||
|             uint64_t                        revokeCount = 0; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |     struct EntityEntry { | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |         OpenWifi::Types::UUID_t         id; | ||||||
|         }; |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         std::string                     name; | ||||||
|  |         std::string                     description; | ||||||
|  |         std::string                     defaultRedirector; | ||||||
|  |         std::string                     apiKey; | ||||||
|  |         std::string                     serverEnrollmentProfile; | ||||||
|  |         std::string                     clientEnrollmentProfile; | ||||||
|  |         std::string                     organization; | ||||||
|  |         SecurityObjects::NoteInfoVec    notes; | ||||||
|  |         bool                            suspended=false; | ||||||
|  |         bool                            deleted=false; | ||||||
|  |         uint64_t                        created = 0 ; | ||||||
|  |         uint64_t                        modified = 0 ; | ||||||
|  |  | ||||||
|         struct EntityEntry { |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             OpenWifi::Types::UUID_t         id; |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             OpenWifi::Types::UUID_t         creator; |     }; | ||||||
|             std::string                     name; |  | ||||||
|             std::string                     description; |  | ||||||
|             std::string                     defaultRedirector; |  | ||||||
|             std::string                     apiKey; |  | ||||||
|             std::string                     serverEnrollmentProfile; |  | ||||||
|             std::string                     clientEnrollmentProfile; |  | ||||||
|             std::string                     organization; |  | ||||||
|             SecurityObjects::NoteInfoVec    notes; |  | ||||||
|             bool                            suspended=false; |  | ||||||
|             bool                            deleted=false; |  | ||||||
|             uint64_t                        created = 0 ; |  | ||||||
|             uint64_t                        modified = 0 ; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |     struct BatchEntry { | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |         OpenWifi::Types::UUID_t         id; | ||||||
|         }; |         OpenWifi::Types::UUID_t         entity; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         std::string                     name; | ||||||
|  |         std::string                     description; | ||||||
|  |         std::string                     manufacturer; | ||||||
|  |         std::string                     model; | ||||||
|  |         std::string                     redirector; | ||||||
|  |         std::vector<std::string>        commonNames; | ||||||
|  |         std::vector<std::string>        jobHistory; | ||||||
|  |         SecurityObjects::NoteInfoVec    notes; | ||||||
|  |         uint64_t                        submitted = 0 ; | ||||||
|  |         uint64_t                        started = 0 ; | ||||||
|  |         uint64_t                        completed = 0 ; | ||||||
|  |         uint64_t                        modified = 0 ; | ||||||
|  |  | ||||||
|         struct BatchEntry { |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             OpenWifi::Types::UUID_t         id; |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             OpenWifi::Types::UUID_t         entity; |     }; | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             std::string                     name; |  | ||||||
|             std::string                     description; |  | ||||||
|             std::string                     manufacturer; |  | ||||||
|             std::string                     model; |  | ||||||
|             std::string                     redirector; |  | ||||||
|             std::vector<std::string>        commonNames; |  | ||||||
|             std::vector<std::string>        jobHistory; |  | ||||||
|             SecurityObjects::NoteInfoVec    notes; |  | ||||||
|             uint64_t                        submitted = 0 ; |  | ||||||
|             uint64_t                        started = 0 ; |  | ||||||
|             uint64_t                        completed = 0 ; |  | ||||||
|             uint64_t                        modified = 0 ; |  | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |     struct JobEntry { | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |         OpenWifi::Types::UUID_t         id; | ||||||
|         }; |         OpenWifi::Types::UUID_t         entity; | ||||||
|  |         OpenWifi::Types::UUID_t         creator; | ||||||
|  |         OpenWifi::Types::UUID_t         batch; | ||||||
|  |         std::string                     command; | ||||||
|  |         OpenWifi::Types::StringVec      commonNames; | ||||||
|  |         OpenWifi::Types::StringVec      completedNames; | ||||||
|  |         OpenWifi::Types::StringVec      errorNames; | ||||||
|  |         Types::StringPairVec            parameters; | ||||||
|  |         std::string                     status; | ||||||
|  |         uint64_t                        submitted=0; | ||||||
|  |         uint64_t                        started=0; | ||||||
|  |         uint64_t                        completed=0; | ||||||
|  |  | ||||||
|         struct JobEntry { |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             OpenWifi::Types::UUID_t         id; |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|             OpenWifi::Types::UUID_t         entity; |     }; | ||||||
|             OpenWifi::Types::UUID_t         creator; |  | ||||||
|             OpenWifi::Types::UUID_t         batch; |     struct DashBoardYearlyStats { | ||||||
|             std::string                     command; |         uint64_t                            year=0; | ||||||
|             OpenWifi::Types::StringVec      commonNames; |         OpenWifi::Types::Counted3DMapSII    activeCerts; | ||||||
|             OpenWifi::Types::StringVec      completedNames; |         OpenWifi::Types::Counted3DMapSII    revokedCerts; | ||||||
|             OpenWifi::Types::StringVec      errorNames; |  | ||||||
|             Types::StringPairVec            parameters; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             std::string                     status; |     }; | ||||||
|             uint64_t                        submitted=0; |  | ||||||
|             uint64_t                        started=0; |     struct Dashboard { | ||||||
|             uint64_t                        completed=0; |         uint64_t                            snapshot=0; | ||||||
|  |         uint64_t                            numberOfIssuedCerts=0; | ||||||
|  |         uint64_t                            numberOfRevokedCerts=0; | ||||||
|  |         OpenWifi::Types::CountedMap         activeCertsPerOrganization; | ||||||
|  |         OpenWifi::Types::CountedMap         revokedCertsPerOrganization; | ||||||
|  |         OpenWifi::Types::CountedMap         numberOfRedirectors; | ||||||
|  |         OpenWifi::Types::CountedMap         deviceTypes; | ||||||
|  |         OpenWifi::Types::CountedMap         monthlyNumberOfCerts; | ||||||
|  |         std::vector<DashBoardYearlyStats>   monthlyNumberOfCertsPerOrgPerYear; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         void reset(); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |  | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj); |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| @@ -233,7 +233,7 @@ namespace OpenWifi::FMSObjects { | |||||||
|         UnknownFirmwares_.clear(); |         UnknownFirmwares_.clear(); | ||||||
|         totalSecondsOld_.clear(); |         totalSecondsOld_.clear(); | ||||||
|         numberOfDevices = 0 ; |         numberOfDevices = 0 ; | ||||||
|         snapshot = std::time(nullptr); |         snapshot = OpenWifi::Now(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { |     bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -273,4 +273,37 @@ namespace OpenWifi::FMSObjects { | |||||||
|         } |         } | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     void DeviceCurrentInfo::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "serialNumber",serialNumber); | ||||||
|  |         field_to_json(Obj, "revision", revision); | ||||||
|  |         field_to_json(Obj, "upgraded", upgraded); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool DeviceCurrentInfo::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "serialNumber",serialNumber); | ||||||
|  |             field_from_json(Obj, "revision", revision); | ||||||
|  |             field_from_json(Obj, "upgraded", upgraded); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void DeviceCurrentInfoList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj, "devices",devices); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool DeviceCurrentInfoList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj, "devices",devices); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,9 +4,7 @@ | |||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
|  |  | ||||||
| #ifndef UCENTRALFMS_RESTAPI_FMSOBJECTS_H | #pragma once | ||||||
| #define UCENTRALFMS_RESTAPI_FMSOBJECTS_H |  | ||||||
|  |  | ||||||
|  |  | ||||||
| #include "RESTAPI_SecurityObjects.h" | #include "RESTAPI_SecurityObjects.h" | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
| @@ -29,7 +27,7 @@ namespace OpenWifi::FMSObjects { | |||||||
|         std::string     location; |         std::string     location; | ||||||
|         std::string     uploader; |         std::string     uploader; | ||||||
|         std::string     digest; |         std::string     digest; | ||||||
|         bool            latest=0; |         bool            latest=false; | ||||||
|         SecurityObjects::NoteInfoVec    notes; |         SecurityObjects::NoteInfoVec    notes; | ||||||
|         uint64_t        created=0; |         uint64_t        created=0; | ||||||
|  |  | ||||||
| @@ -141,7 +139,21 @@ namespace OpenWifi::FMSObjects { | |||||||
|         void to_json(Poco::JSON::Object &Obj) const; |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|         bool from_json(const Poco::JSON::Object::Ptr &Obj); |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  |     struct DeviceCurrentInfo { | ||||||
|  |         std::string                 serialNumber; | ||||||
|  |         std::string                 revision; | ||||||
|  |         uint64_t                    upgraded=0; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct DeviceCurrentInfoList { | ||||||
|  |         std::vector<DeviceCurrentInfo>  devices; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| #endif //UCENTRALFMS_RESTAPI_FMSOBJECTS_H |  | ||||||
|   | |||||||
| @@ -203,6 +203,10 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"kafkaClients", kafkaClients); | 		field_to_json(Obj,"kafkaClients", kafkaClients); | ||||||
| 		field_to_json(Obj,"kafkaPackets", kafkaPackets); | 		field_to_json(Obj,"kafkaPackets", kafkaPackets); | ||||||
| 		field_to_json(Obj,"locale", locale); | 		field_to_json(Obj,"locale", locale); | ||||||
|  | 		field_to_json(Obj,"started", started); | ||||||
|  | 		field_to_json(Obj,"sessionId", sessionId); | ||||||
|  | 		field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime); | ||||||
|  | 		field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started); | ||||||
|  |  | ||||||
| 		switch(VerifiedCertificate) { | 		switch(VerifiedCertificate) { | ||||||
| 			case NO_CERTIFICATE: | 			case NO_CERTIFICATE: | ||||||
| @@ -218,6 +222,21 @@ namespace OpenWifi::GWObjects { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  | 		field_to_json(Obj,"averageConnectionTime", averageConnectionTime); | ||||||
|  | 		field_to_json(Obj,"connectedDevices", connectedDevices ); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  | 		try { | ||||||
|  | 			field_from_json(Obj,"averageConnectionTime", averageConnectionTime); | ||||||
|  | 			field_from_json(Obj,"connectedDevices", connectedDevices ); | ||||||
|  | 			return true; | ||||||
|  | 		} catch (const Poco::Exception &E) { | ||||||
|  | 		} | ||||||
|  | 		return false; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const { | 	void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"serialNumber", SerialNumber); | 		field_to_json(Obj,"serialNumber", SerialNumber); | ||||||
| 		field_to_json(Obj,"server", Server); | 		field_to_json(Obj,"server", Server); | ||||||
| @@ -293,7 +312,6 @@ namespace OpenWifi::GWObjects { | |||||||
| 		} catch (const Poco::Exception &E) { | 		} catch (const Poco::Exception &E) { | ||||||
| 		} | 		} | ||||||
| 		return false; | 		return false; | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const { | 	void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const { | ||||||
| @@ -314,6 +332,8 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"description",description); | 		field_to_json(Obj,"description",description); | ||||||
| 		field_to_json(Obj,"authConfig",authConfig); | 		field_to_json(Obj,"authConfig",authConfig); | ||||||
| 		field_to_json(Obj,"acctConfig",acctConfig); | 		field_to_json(Obj,"acctConfig",acctConfig); | ||||||
|  | 		field_to_json(Obj,"coaConfig",coaConfig); | ||||||
|  | 		field_to_json(Obj,"useByDefault",useByDefault); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) { | 	bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -322,6 +342,8 @@ namespace OpenWifi::GWObjects { | |||||||
| 			field_from_json(Obj,"description",description); | 			field_from_json(Obj,"description",description); | ||||||
| 			field_from_json(Obj,"authConfig",authConfig); | 			field_from_json(Obj,"authConfig",authConfig); | ||||||
| 			field_from_json(Obj,"acctConfig",acctConfig); | 			field_from_json(Obj,"acctConfig",acctConfig); | ||||||
|  | 			field_from_json(Obj,"coaConfig",coaConfig); | ||||||
|  | 			field_from_json(Obj,"useByDefault",useByDefault); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch (const Poco::Exception &E) { | 		} catch (const Poco::Exception &E) { | ||||||
| 		} | 		} | ||||||
| @@ -329,7 +351,7 @@ namespace OpenWifi::GWObjects { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const { | 	void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const { | ||||||
| 		field_to_json(Obj,"policy",strategy); | 		field_to_json(Obj,"strategy",strategy); | ||||||
| 		field_to_json(Obj,"monitor",monitor); | 		field_to_json(Obj,"monitor",monitor); | ||||||
| 		field_to_json(Obj,"monitorMethod",monitorMethod); | 		field_to_json(Obj,"monitorMethod",monitorMethod); | ||||||
| 		field_to_json(Obj,"methodParameters",methodParameters); | 		field_to_json(Obj,"methodParameters",methodParameters); | ||||||
| @@ -338,7 +360,7 @@ namespace OpenWifi::GWObjects { | |||||||
|  |  | ||||||
| 	bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | 	bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| 		try { | 		try { | ||||||
| 			field_from_json(Obj,"policy",strategy); | 			field_from_json(Obj,"strategy",strategy); | ||||||
| 			field_from_json(Obj,"monitor",monitor); | 			field_from_json(Obj,"monitor",monitor); | ||||||
| 			field_from_json(Obj,"monitorMethod",monitorMethod); | 			field_from_json(Obj,"monitorMethod",monitorMethod); | ||||||
| 			field_from_json(Obj,"methodParameters",methodParameters); | 			field_from_json(Obj,"methodParameters",methodParameters); | ||||||
| @@ -354,6 +376,16 @@ namespace OpenWifi::GWObjects { | |||||||
| 		field_to_json(Obj,"ip",ip); | 		field_to_json(Obj,"ip",ip); | ||||||
| 		field_to_json(Obj,"port",port); | 		field_to_json(Obj,"port",port); | ||||||
| 		field_to_json(Obj,"weight",weight); | 		field_to_json(Obj,"weight",weight); | ||||||
|  | 		field_to_json(Obj,"secret",secret); | ||||||
|  | 		field_to_json(Obj,"certificate",certificate); | ||||||
|  | 		field_to_json(Obj,"radsec",radsec); | ||||||
|  | 		field_to_json(Obj,"radsecPort",radsecPort); | ||||||
|  | 		field_to_json(Obj,"radsecSecret",radsecSecret); | ||||||
|  | 		field_to_json(Obj,"radsecCacerts",radsecCacerts); | ||||||
|  | 		field_to_json(Obj,"radsecCert",radsecCert); | ||||||
|  | 		field_to_json(Obj,"radsecKey",radsecKey); | ||||||
|  | 		field_to_json(Obj,"radsecRealms",radsecRealms); | ||||||
|  | 		field_to_json(Obj,"ignore",ignore); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | 	bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
| @@ -362,6 +394,16 @@ namespace OpenWifi::GWObjects { | |||||||
| 			field_from_json(Obj,"ip",ip); | 			field_from_json(Obj,"ip",ip); | ||||||
| 			field_from_json(Obj,"port",port); | 			field_from_json(Obj,"port",port); | ||||||
| 			field_from_json(Obj,"weight",weight); | 			field_from_json(Obj,"weight",weight); | ||||||
|  | 			field_from_json(Obj,"secret",secret); | ||||||
|  | 			field_from_json(Obj,"certificate",certificate); | ||||||
|  | 			field_from_json(Obj,"radsec",radsec); | ||||||
|  | 			field_from_json(Obj,"radsecSecret",radsecSecret); | ||||||
|  | 			field_from_json(Obj,"radsecPort",radsecPort); | ||||||
|  | 			field_from_json(Obj,"radsecCacerts",radsecCacerts); | ||||||
|  | 			field_from_json(Obj,"radsecCert",radsecCert); | ||||||
|  | 			field_from_json(Obj,"radsecKey",radsecKey); | ||||||
|  | 			field_from_json(Obj,"radsecRealms",radsecRealms); | ||||||
|  | 			field_from_json(Obj,"ignore",ignore); | ||||||
| 			return true; | 			return true; | ||||||
| 		} catch (const Poco::Exception &E) { | 		} catch (const Poco::Exception &E) { | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -38,6 +38,10 @@ namespace OpenWifi::GWObjects { | |||||||
| 		uint64_t 	kafkaPackets=0; | 		uint64_t 	kafkaPackets=0; | ||||||
| 		uint64_t 	websocketPackets=0; | 		uint64_t 	websocketPackets=0; | ||||||
| 		std::string locale; | 		std::string locale; | ||||||
|  | 		uint64_t 	started=0; | ||||||
|  | 		uint64_t 	sessionId=0; | ||||||
|  | 		double      connectionCompletionTime=0.0; | ||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| @@ -71,6 +75,13 @@ namespace OpenWifi::GWObjects { | |||||||
| 		void Print() const; | 		void Print() const; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	struct DeviceConnectionStatistics { | ||||||
|  | 		std::uint64_t connectedDevices = 0; | ||||||
|  | 		std::uint64_t averageConnectionTime = 0; | ||||||
|  | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	struct Statistics { | 	struct Statistics { | ||||||
| 		std::string SerialNumber; | 		std::string SerialNumber; | ||||||
| 		uint64_t 	UUID = 0 ; | 		uint64_t 	UUID = 0 ; | ||||||
| @@ -216,6 +227,16 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string ip; | 		std::string ip; | ||||||
| 		uint16_t 	port=0; | 		uint16_t 	port=0; | ||||||
| 		uint64_t 	weight=0; | 		uint64_t 	weight=0; | ||||||
|  | 		std::string secret; | ||||||
|  | 		std::string certificate; | ||||||
|  | 		bool 		radsec=false; | ||||||
|  | 		uint16_t 	radsecPort=2083; | ||||||
|  | 		std::string radsecSecret; | ||||||
|  | 		std::string radsecKey; | ||||||
|  | 		std::string radsecCert; | ||||||
|  | 		std::vector<std::string> 	radsecCacerts; | ||||||
|  | 		std::vector<std::string>	radsecRealms; | ||||||
|  | 		bool 		ignore=false; | ||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
| @@ -237,6 +258,8 @@ namespace OpenWifi::GWObjects { | |||||||
| 		std::string description; | 		std::string description; | ||||||
| 		RadiusProxyServerConfig	authConfig; | 		RadiusProxyServerConfig	authConfig; | ||||||
| 		RadiusProxyServerConfig	acctConfig; | 		RadiusProxyServerConfig	acctConfig; | ||||||
|  | 		RadiusProxyServerConfig	coaConfig; | ||||||
|  | 		bool 		useByDefault=false; | ||||||
|  |  | ||||||
| 		void to_json(Poco::JSON::Object &Obj) const; | 		void to_json(Poco::JSON::Object &Obj) const; | ||||||
| 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | 		bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|   | |||||||
							
								
								
									
										110
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-08-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #include "framework/MicroService.h" | ||||||
|  |  | ||||||
|  | using OpenWifi::RESTAPI_utils::field_to_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::field_from_json; | ||||||
|  | using OpenWifi::RESTAPI_utils::EmbedDocument; | ||||||
|  |  | ||||||
|  | #include "RESTAPI_OWLSobjects.h" | ||||||
|  |  | ||||||
|  | // SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d | ||||||
|  |  | ||||||
|  | namespace OpenWifi::OWLSObjects { | ||||||
|  |  | ||||||
|  |     void SimulationDetails::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"name", name); | ||||||
|  |         field_to_json(Obj,"gateway", gateway); | ||||||
|  |         field_to_json(Obj,"certificate", certificate); | ||||||
|  |         field_to_json(Obj,"key", key); | ||||||
|  |         field_to_json(Obj,"macPrefix", macPrefix); | ||||||
|  |         field_to_json(Obj,"deviceType", deviceType); | ||||||
|  |         field_to_json(Obj,"devices", devices); | ||||||
|  |         field_to_json(Obj,"healthCheckInterval", healthCheckInterval); | ||||||
|  |         field_to_json(Obj,"stateInterval", stateInterval); | ||||||
|  |         field_to_json(Obj,"minAssociations", minAssociations); | ||||||
|  |         field_to_json(Obj,"maxAssociations", maxAssociations); | ||||||
|  |         field_to_json(Obj,"minClients", minClients); | ||||||
|  |         field_to_json(Obj,"maxClients", maxClients); | ||||||
|  |         field_to_json(Obj,"simulationLength", simulationLength); | ||||||
|  |         field_to_json(Obj,"threads", threads); | ||||||
|  |         field_to_json(Obj,"clientInterval", clientInterval); | ||||||
|  |         field_to_json(Obj,"keepAlive", keepAlive); | ||||||
|  |         field_to_json(Obj,"reconnectInterval", reconnectInterval); | ||||||
|  |         field_to_json(Obj,"concurrentDevices", concurrentDevices); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"id", id); | ||||||
|  |             field_from_json(Obj,"name", name); | ||||||
|  |             field_from_json(Obj,"gateway", gateway); | ||||||
|  |             field_from_json(Obj,"certificate", certificate); | ||||||
|  |             field_from_json(Obj,"key", key); | ||||||
|  |             field_from_json(Obj,"macPrefix", macPrefix); | ||||||
|  |             field_from_json(Obj,"deviceType", deviceType); | ||||||
|  |             field_from_json(Obj,"devices", devices); | ||||||
|  |             field_from_json(Obj,"healthCheckInterval", healthCheckInterval); | ||||||
|  |             field_from_json(Obj,"stateInterval", stateInterval); | ||||||
|  |             field_from_json(Obj,"minAssociations", minAssociations); | ||||||
|  |             field_from_json(Obj,"maxAssociations", maxAssociations); | ||||||
|  |             field_from_json(Obj,"minClients", minClients); | ||||||
|  |             field_from_json(Obj,"maxClients", maxClients); | ||||||
|  |             field_from_json(Obj,"simulationLength", simulationLength); | ||||||
|  |             field_from_json(Obj,"threads", threads); | ||||||
|  |             field_from_json(Obj,"clientInterval", clientInterval); | ||||||
|  |             field_from_json(Obj,"keepAlive", keepAlive); | ||||||
|  |             field_from_json(Obj,"reconnectInterval", reconnectInterval); | ||||||
|  |             field_from_json(Obj,"concurrentDevices", concurrentDevices); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"list", list); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             field_from_json(Obj,"list", list); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void SimulationStatus::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         field_to_json(Obj,"id", id); | ||||||
|  |         field_to_json(Obj,"simulationId", simulationId); | ||||||
|  |         field_to_json(Obj,"state", state); | ||||||
|  |         field_to_json(Obj,"tx", tx); | ||||||
|  |         field_to_json(Obj,"rx", rx); | ||||||
|  |         field_to_json(Obj,"msgsTx", msgsTx); | ||||||
|  |         field_to_json(Obj,"msgsRx", msgsRx); | ||||||
|  |         field_to_json(Obj,"liveDevices", liveDevices); | ||||||
|  |         field_to_json(Obj,"timeToFullDevices", timeToFullDevices); | ||||||
|  |         field_to_json(Obj,"startTime", startTime); | ||||||
|  |         field_to_json(Obj,"endTime", endTime); | ||||||
|  |         field_to_json(Obj,"errorDevices", errorDevices); | ||||||
|  |         field_to_json(Obj,"owner", owner); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void Dashboard::reset() { | ||||||
|  |  | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										77
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/RESTObjects/RESTAPI_OWLSobjects.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-08-31. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||||
|  | #define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  | #include "Poco/JSON/Object.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi::OWLSObjects { | ||||||
|  |  | ||||||
|  |     struct SimulationDetails { | ||||||
|  |         std::string     id; | ||||||
|  |         std::string     name; | ||||||
|  |         std::string     gateway; | ||||||
|  |         std::string     certificate; | ||||||
|  |         std::string     key; | ||||||
|  |         std::string     macPrefix; | ||||||
|  |         std::string     deviceType; | ||||||
|  |         uint64_t        devices = 5; | ||||||
|  |         uint64_t        healthCheckInterval = 60; | ||||||
|  |         uint64_t        stateInterval = 60 ; | ||||||
|  |         uint64_t        minAssociations = 1; | ||||||
|  |         uint64_t        maxAssociations = 3; | ||||||
|  |         uint64_t        minClients = 1 ; | ||||||
|  |         uint64_t        maxClients = 3; | ||||||
|  |         uint64_t        simulationLength = 60 * 60; | ||||||
|  |         uint64_t        threads = 16; | ||||||
|  |         uint64_t        clientInterval = 1; | ||||||
|  |         uint64_t        keepAlive = 300; | ||||||
|  |         uint64_t        reconnectInterval = 30 ; | ||||||
|  |         uint64_t        concurrentDevices = 5; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SimulationDetailsList { | ||||||
|  |         std::vector<SimulationDetails>  list; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     struct SimulationStatus { | ||||||
|  |         std::string     id; | ||||||
|  |         std::string     simulationId; | ||||||
|  |         std::string     state; | ||||||
|  |         uint64_t        tx; | ||||||
|  |         uint64_t        rx; | ||||||
|  |         uint64_t        msgsTx; | ||||||
|  |         uint64_t        msgsRx; | ||||||
|  |         uint64_t        liveDevices; | ||||||
|  |         uint64_t        timeToFullDevices; | ||||||
|  |         uint64_t        startTime; | ||||||
|  |         uint64_t        endTime; | ||||||
|  |         uint64_t        errorDevices; | ||||||
|  |         std::string     owner; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     struct Dashboard { | ||||||
|  |         int O; | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         void reset(); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H | ||||||
| @@ -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"}; | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <type_traits> | ||||||
| #include "framework/OpenWifiTypes.h" | #include "framework/OpenWifiTypes.h" | ||||||
| #include "Poco/JSON/Object.h" | #include "Poco/JSON/Object.h" | ||||||
| #include "Poco/Data/LOB.h" | #include "Poco/Data/LOB.h" | ||||||
| @@ -27,8 +28,13 @@ namespace OpenWifi { | |||||||
|             bool Delete_ = true; |             bool Delete_ = true; | ||||||
|             bool PortalLogin_ = true; |             bool PortalLogin_ = true; | ||||||
|  |  | ||||||
|  |             AclTemplate()  noexcept = default; | ||||||
|  |  | ||||||
|             void to_json(Poco::JSON::Object &Obj) const; |             void to_json(Poco::JSON::Object &Obj) const; | ||||||
|             bool from_json(const Poco::JSON::Object::Ptr &Obj);	}; |             bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         static_assert( std::is_nothrow_move_constructible_v<AclTemplate> ); | ||||||
|  |  | ||||||
|         struct WebToken { |         struct WebToken { | ||||||
|             std::string access_token_; |             std::string access_token_; | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|     void Signup::run() { |     void Signup::run() { | ||||||
|         Running_ = true; |         Running_ = true; | ||||||
|  |         Utils::SetThreadName("signup-mgr"); | ||||||
|         while(Running_) { |         while(Running_) { | ||||||
|             Poco::Thread::trySleep(5000); |             Poco::Thread::trySleep(5000); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -105,6 +105,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Storage::onTimer([[maybe_unused]] Poco::Timer &timer) { |     void Storage::onTimer([[maybe_unused]] Poco::Timer &timer) { | ||||||
|  |         Utils::SetThreadName("strg-janitor"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Storage::Stop() { |     void Storage::Stop() { | ||||||
| @@ -194,18 +195,24 @@ namespace OpenWifi { | |||||||
|         // check that all inventory in venues and entities actually exists, if not, fix it. |         // check that all inventory in venues and entities actually exists, if not, fix it. | ||||||
|         auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool { |         auto FixVenueDevices = [&](const ProvObjects::Venue &V) -> bool { | ||||||
|             Types::UUIDvec_t NewDevices; |             Types::UUIDvec_t NewDevices; | ||||||
|  |             bool modified=false; | ||||||
|             for(const auto &device:V.devices) { |             for(const auto &device:V.devices) { | ||||||
|                 ProvObjects::InventoryTag T; |                 ProvObjects::InventoryTag T; | ||||||
|                 if(InventoryDB().GetRecord("id", device, T)) { |                 if(InventoryDB().GetRecord("id", device, T)) { | ||||||
|                     NewDevices.emplace_back(device); |                     NewDevices.emplace_back(device); | ||||||
|                 } else { |                 } else { | ||||||
|  |                     modified=true; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(NewDevices!=V.devices) { |             ProvObjects::Venue NewVenue = V; | ||||||
|  |             if(V.deviceRules.rrm=="yes") { | ||||||
|  |                 NewVenue.deviceRules.rrm="inherit"; | ||||||
|  |                 modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(modified) { | ||||||
|                 Logger().warning(fmt::format("  fixing venue: {}", V.info.name)); |                 Logger().warning(fmt::format("  fixing venue: {}", V.info.name)); | ||||||
|                 ProvObjects::Venue NewVenue = V; |  | ||||||
|                 NewVenue.devices = NewDevices; |                 NewVenue.devices = NewDevices; | ||||||
|                 VenueDB().UpdateRecord("id", V.info.id, NewVenue); |                 VenueDB().UpdateRecord("id", V.info.id, NewVenue); | ||||||
|             } |             } | ||||||
| @@ -213,31 +220,175 @@ namespace OpenWifi { | |||||||
|             return true; |             return true; | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         auto FixEntityDevices = [&](const ProvObjects::Entity &E) -> bool { |         auto FixEntity = [&](const ProvObjects::Entity &E) -> bool { | ||||||
|             Types::UUIDvec_t NewDevices; |             Types::UUIDvec_t NewDevices; | ||||||
|  |             bool Modified=false; | ||||||
|             for(const auto &device:E.devices) { |             for(const auto &device:E.devices) { | ||||||
|                 ProvObjects::InventoryTag T; |                 ProvObjects::InventoryTag T; | ||||||
|                 if(InventoryDB().GetRecord("id", device, T)) { |                 if(InventoryDB().GetRecord("id", device, T)) { | ||||||
|                     NewDevices.emplace_back(device); |                     NewDevices.emplace_back(device); | ||||||
|                 } else { |                 } else { | ||||||
|  |                     Modified=true; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if(NewDevices!=E.devices) { |             Types::UUIDvec_t NewContacts; | ||||||
|  |             for(const auto &contact:E.contacts) { | ||||||
|  |                 ProvObjects::Contact C; | ||||||
|  |                 if(ContactDB().GetRecord("id", contact, C)) { | ||||||
|  |                     NewContacts.emplace_back(contact); | ||||||
|  |                 } else { | ||||||
|  |                     Modified=true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Types::UUIDvec_t NewLocations; | ||||||
|  |             for(const auto &location:E.locations) { | ||||||
|  |                 ProvObjects::Location L; | ||||||
|  |                 if(LocationDB().GetRecord("id", location, L)) { | ||||||
|  |                     NewLocations.emplace_back(location); | ||||||
|  |                 } else { | ||||||
|  |                     Modified=true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Types::UUIDvec_t NewVenues; | ||||||
|  |             for(const auto &venue:E.venues) { | ||||||
|  |                 ProvObjects::Venue V; | ||||||
|  |                 if(VenueDB().GetRecord("id", venue, V)) { | ||||||
|  |                     NewVenues.emplace_back(venue); | ||||||
|  |                 } else { | ||||||
|  |                     Modified=true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             Types::UUIDvec_t NewVariables; | ||||||
|  |             for(const auto &variable:E.variables) { | ||||||
|  |                 ProvObjects::VariableBlock V; | ||||||
|  |                 if(VariablesDB().GetRecord("id", variable, V)) { | ||||||
|  |                     NewVariables.emplace_back(variable); | ||||||
|  |                 } else { | ||||||
|  |                     Modified=true; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             ProvObjects::Entity NewEntity = E; | ||||||
|  |  | ||||||
|  |             if(E.deviceRules.rrm=="yes") { | ||||||
|  |                 NewEntity.deviceRules.rrm="inherit"; | ||||||
|  |                 Modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(Modified) | ||||||
|  |             { | ||||||
|                 Logger().warning(fmt::format("  fixing entity: {}",E.info.name)); |                 Logger().warning(fmt::format("  fixing entity: {}",E.info.name)); | ||||||
|                 ProvObjects::Entity NewEntity = E; |  | ||||||
|                 NewEntity.devices = NewDevices; |                 NewEntity.devices = NewDevices; | ||||||
|  |                 NewEntity.contacts = NewContacts; | ||||||
|  |                 NewEntity.locations = NewLocations; | ||||||
|  |                 NewEntity.venues = NewVenues; | ||||||
|  |                 NewEntity.variables = NewVariables; | ||||||
|                 EntityDB().UpdateRecord("id", E.info.id, NewEntity); |                 EntityDB().UpdateRecord("id", E.info.id, NewEntity); | ||||||
|             } |             } | ||||||
|             return true; |             return true; | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|  |         auto FixInventory = [&](const ProvObjects::InventoryTag &T) -> bool { | ||||||
|  |             // check the venue/entity for this device. | ||||||
|  |             ProvObjects::InventoryTag   NewTag{T}; | ||||||
|  |             bool modified=false; | ||||||
|  |             if(!T.venue.empty() && !VenueDB().Exists("id",T.venue)) { | ||||||
|  |                 NewTag.venue.clear(); | ||||||
|  |                 modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(!T.entity.empty() && !EntityDB().Exists("id",T.entity)) { | ||||||
|  |                 NewTag.entity.clear(); | ||||||
|  |                 modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(!T.location.empty() && !LocationDB().Exists("id",T.location)) { | ||||||
|  |                 NewTag.location.clear(); | ||||||
|  |                 modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(!T.contact.empty() && !ContactDB().Exists("id",T.contact)) { | ||||||
|  |                 NewTag.contact.clear(); | ||||||
|  |                 modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(T.deviceRules.rrm=="yes") { | ||||||
|  |                 NewTag.deviceRules.rrm = "inherit"; | ||||||
|  |                 modified=true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if(modified) { | ||||||
|  |                 Logger().warning(fmt::format("  fixing entity: {}",T.info.name)); | ||||||
|  |                 InventoryDB().UpdateRecord("id", T.info.id, NewTag); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         auto FixConfiguration = [&](const ProvObjects::DeviceConfiguration &C) -> bool { | ||||||
|  |             ProvObjects::DeviceConfiguration NewConfig{C}; | ||||||
|  |  | ||||||
|  |             bool modified = false; | ||||||
|  |  | ||||||
|  |             if (C.deviceRules.rrm == "yes") { | ||||||
|  |                 NewConfig.deviceRules.rrm = "inherit"; | ||||||
|  |                 modified = true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (modified) { | ||||||
|  |                 Logger().warning(fmt::format("  fixing configuration: {}", C.info.name)); | ||||||
|  |                 ConfigurationDB().UpdateRecord("id", C.info.id, NewConfig); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         auto FixOperator = [&](const ProvObjects::Operator &O) -> bool { | ||||||
|  |             ProvObjects::Operator NewOp{O}; | ||||||
|  |             bool modified = false; | ||||||
|  |  | ||||||
|  |             if (O.deviceRules.rrm == "yes") { | ||||||
|  |                 NewOp.deviceRules.rrm = "inherit"; | ||||||
|  |                 modified = true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (modified) { | ||||||
|  |                 Logger().warning(fmt::format("  fixing operator: {}", O.info.name)); | ||||||
|  |                 OperatorDB().UpdateRecord("id", O.info.id, NewOp); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         auto FixSubscriber = [&](const ProvObjects::SubscriberDevice &O) -> bool { | ||||||
|  |             ProvObjects::SubscriberDevice NewSub{O}; | ||||||
|  |             bool modified = false; | ||||||
|  |  | ||||||
|  |             if (O.deviceRules.rrm == "yes") { | ||||||
|  |                 NewSub.deviceRules.rrm = "inherit"; | ||||||
|  |                 modified = true; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (modified) { | ||||||
|  |                 Logger().warning(fmt::format("  fixing subscriber: {}", O.info.name)); | ||||||
|  |                 SubscriberDeviceDB().UpdateRecord("id", O.info.id, NewSub); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }; | ||||||
|  |  | ||||||
|         Logger().information("Checking DB consistency: venues"); |         Logger().information("Checking DB consistency: venues"); | ||||||
|         VenueDB().Iterate(FixVenueDevices); |         VenueDB().Iterate(FixVenueDevices); | ||||||
|         Logger().information("Checking DB consistency: entities"); |         Logger().information("Checking DB consistency: entities"); | ||||||
|         EntityDB().Iterate(FixEntityDevices); |         EntityDB().Iterate(FixEntity); | ||||||
|  |         Logger().information("Checking DB consistency: inventory"); | ||||||
|  |         InventoryDB().Iterate(FixInventory); | ||||||
|  |         Logger().information("Checking DB consistency: configurations"); | ||||||
|  |         ConfigurationDB().Iterate(FixConfiguration); | ||||||
|  |         Logger().information("Checking DB consistency: operators"); | ||||||
|  |         OperatorDB().Iterate(FixOperator); | ||||||
|  |         Logger().information("Checking DB consistency: subscribers"); | ||||||
|  |         SubscriberDeviceDB().Iterate(FixSubscriber); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void Storage::InitializeSystemDBs() { |     void Storage::InitializeSystemDBs() { | ||||||
|   | |||||||
| @@ -21,7 +21,7 @@ namespace OpenWifi { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     void TagServer::run() { |     void TagServer::run() { | ||||||
|  |         Utils::SetThreadName("tag-server"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
| @@ -9,6 +9,7 @@ | |||||||
| #include "APConfig.h" | #include "APConfig.h" | ||||||
| #include "sdks/SDK_gw.h" | #include "sdks/SDK_gw.h" | ||||||
| #include "framework/WebSocketClientNotifications.h" | #include "framework/WebSocketClientNotifications.h" | ||||||
|  | #include "JobController.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -19,8 +20,6 @@ namespace OpenWifi { | |||||||
|                 auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>(); |                 auto Status = Results->get("status").extract<Poco::JSON::Object::Ptr>(); | ||||||
|                 auto Rejected = Status->getArray("rejected"); |                 auto Rejected = Status->getArray("rejected"); | ||||||
|                 std::transform(Rejected->begin(),Rejected->end(),std::back_inserter(Warnings), [](auto i) -> auto { return i.toString(); }); |                 std::transform(Rejected->begin(),Rejected->end(),std::back_inserter(Warnings), [](auto i) -> auto { return i.toString(); }); | ||||||
| //                for(const auto &i:*Rejected) |  | ||||||
|                 //                  Warnings.push_back(i.toString()); |  | ||||||
|             } |             } | ||||||
|         } catch (...) { |         } catch (...) { | ||||||
|         } |         } | ||||||
| @@ -37,35 +36,42 @@ namespace OpenWifi { | |||||||
|         void run() final { |         void run() final { | ||||||
|             ProvObjects::InventoryTag   Device; |             ProvObjects::InventoryTag   Device; | ||||||
|             started_=true; |             started_=true; | ||||||
|  |             Utils::SetThreadName("venue-cfg"); | ||||||
|             if(StorageService()->InventoryDB().GetRecord("id",uuid_,Device)) { |             if(StorageService()->InventoryDB().GetRecord("id",uuid_,Device)) { | ||||||
|                 SerialNumber = Device.serialNumber; |                 SerialNumber = Device.serialNumber; | ||||||
|                 // std::cout << "Starting push for " << Device.serialNumber << std::endl; |                 // std::cout << "Starting push for " << Device.serialNumber << std::endl; | ||||||
|                 Logger().debug(fmt::format("{}: Computing configuration.",Device.serialNumber)); |                 Logger().debug(fmt::format("{}: Computing configuration.",Device.serialNumber)); | ||||||
|                 auto DeviceConfig = std::make_shared<APConfig>(Device.serialNumber, Device.deviceType, Logger(), false); |                 auto DeviceConfig = std::make_shared<APConfig>(Device.serialNumber, Device.deviceType, Logger(), false); | ||||||
|                 auto Configuration = Poco::makeShared<Poco::JSON::Object>(); |                 auto Configuration = Poco::makeShared<Poco::JSON::Object>(); | ||||||
|                 if (DeviceConfig->Get(Configuration)) { |                 try { | ||||||
|                     std::ostringstream OS; |                     if (DeviceConfig->Get(Configuration)) { | ||||||
|                     Configuration->stringify(OS); |                         std::ostringstream OS; | ||||||
|                     auto Response=Poco::makeShared<Poco::JSON::Object>(); |                         Configuration->stringify(OS); | ||||||
|                     Logger().debug(fmt::format("{}: Pushing configuration.",Device.serialNumber)); |                         auto Response = Poco::makeShared<Poco::JSON::Object>(); | ||||||
|                     if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) { |                         Logger().debug(fmt::format("{}: Pushing configuration.", Device.serialNumber)); | ||||||
|                         Logger().debug(fmt::format("{}: Configuration pushed.",Device.serialNumber)); |                         if (SDK::GW::Device::Configure(nullptr, Device.serialNumber, Configuration, Response)) { | ||||||
|                         Logger().information(fmt::format("{}: Updated.", Device.serialNumber)); |                             Logger().debug(fmt::format("{}: Configuration pushed.", Device.serialNumber)); | ||||||
|                         // std::cout << Device.serialNumber << ": Updated" << std::endl; |                             Logger().information(fmt::format("{}: Updated.", Device.serialNumber)); | ||||||
|                         updated_++; |                             // std::cout << Device.serialNumber << ": Updated" << std::endl; | ||||||
|  |                             updated_++; | ||||||
|  |                         } else { | ||||||
|  |                             Logger().information(fmt::format("{}: Not updated.", Device.serialNumber)); | ||||||
|  |                             // std::cout << Device.serialNumber << ": Failed" << std::endl; | ||||||
|  |                             failed_++; | ||||||
|  |                         } | ||||||
|                     } else { |                     } else { | ||||||
|                         Logger().information(fmt::format("{}: Not updated.", Device.serialNumber)); |                         Logger().debug(fmt::format("{}: Configuration is bad.", Device.serialNumber)); | ||||||
|                         // std::cout << Device.serialNumber << ": Failed" << std::endl; |                         bad_config_++; | ||||||
|                         failed_++; |                         // std::cout << Device.serialNumber << ": Bad config" << std::endl; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } catch (...) { | ||||||
|                     Logger().debug(fmt::format("{}: Configuration is bad.",Device.serialNumber)); |                     Logger().debug(fmt::format("{}: Configuration is bad (caused an exception).", Device.serialNumber)); | ||||||
|                     bad_config_++; |                     bad_config_++; | ||||||
|                     // std::cout << Device.serialNumber << ": Bad config" << std::endl; |  | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             done_ = true; |             done_ = true; | ||||||
|             // std::cout << "Done push for " << Device.serialNumber << std::endl; |             // std::cout << "Done push for " << Device.serialNumber << std::endl; | ||||||
|  |             Utils::SetThreadName("free"); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         uint64_t        updated_=0, failed_=0, bad_config_=0; |         uint64_t        updated_=0, failed_=0, bad_config_=0; | ||||||
| @@ -80,133 +86,101 @@ namespace OpenWifi { | |||||||
|         inline Poco::Logger & Logger() { return Logger_; } |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class VenueConfigUpdater: public Poco::Runnable { |     class VenueConfigUpdater: public Job { | ||||||
|     public: |     public: | ||||||
|         explicit VenueConfigUpdater(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : |         VenueConfigUpdater(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|             VenueUUID_(VenueUUID), |                 Job(JobID, name, parameters, when, UI, L) { | ||||||
|             UI_(UI), |  | ||||||
|             When_(When), |  | ||||||
|             Logger_(L) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string Start() { |         inline virtual void run() { | ||||||
|             JobId_ = MicroService::CreateUUID(); |             std::string                 VenueUUID_; | ||||||
|             Worker_.start(*this); |  | ||||||
|             return JobId_; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |             Utils::SetThreadName("venue-update"); | ||||||
|         std::string                 VenueUUID_; |             VenueUUID_ = Parameter(0); | ||||||
|         SecurityObjects::UserInfo   UI_; |  | ||||||
|         uint64_t                    When_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         Poco::Thread                Worker_; |  | ||||||
|         std::string                 JobId_; |  | ||||||
|         Poco::ThreadPool            Pool_{2,16,300}; |  | ||||||
|  |  | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|  |  | ||||||
|         inline void run() final { |  | ||||||
|  |  | ||||||
|             if(When_ && When_>OpenWifi::Now()) |  | ||||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); |  | ||||||
|  |  | ||||||
|             WebSocketNotification<WebSocketNotificationJobContent> N; |             WebSocketNotification<WebSocketNotificationJobContent> N; | ||||||
|  |  | ||||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); |  | ||||||
|  |  | ||||||
|             ProvObjects::Venue  Venue; |             ProvObjects::Venue  Venue; | ||||||
|             uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ; |             uint64_t Updated = 0, Failed = 0 , BadConfigs = 0 ; | ||||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { |             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||||
|                 const std::size_t MaxThreads=16; |  | ||||||
|                 struct tState { |  | ||||||
|                     Poco::Thread                thr_; |  | ||||||
|                     VenueDeviceConfigUpdater    *task= nullptr; |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 N.content.title = fmt::format("Updating {} configurations", Venue.info.name); |                 N.content.title = fmt::format("Updating {} configurations", Venue.info.name); | ||||||
|                 N.content.jobId = JobId_; |                 N.content.jobId = JobId(); | ||||||
|  |  | ||||||
|  |                 Poco::ThreadPool    Pool_; | ||||||
|  |                 std::list<VenueDeviceConfigUpdater*> JobList; | ||||||
|  |  | ||||||
|                 std::array<tState,MaxThreads> Tasks; |  | ||||||
|  |  | ||||||
|                 for(const auto &uuid:Venue.devices) { |                 for(const auto &uuid:Venue.devices) { | ||||||
|                     auto NewTask = new VenueDeviceConfigUpdater(uuid, Venue.info.name, Logger()); |                     auto NewTask = new VenueDeviceConfigUpdater(uuid, Venue.info.name, Logger()); | ||||||
|                     // std::cout << "Scheduling config push for " << uuid << std::endl; |                     bool TaskAdded=false; | ||||||
|                     bool found_slot = false; |                     while(!TaskAdded) { | ||||||
|                     while (!found_slot) { |                         if (Pool_.available()) { | ||||||
|                         for (auto &cur_task: Tasks) { |                             JobList.push_back(NewTask); | ||||||
|                             if (cur_task.task == nullptr) { |                             Pool_.start(*NewTask); | ||||||
|                                 cur_task.task = NewTask; |                             TaskAdded = true; | ||||||
|                                 cur_task.thr_.start(*NewTask); |                             continue; | ||||||
|                                 found_slot = true; |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                         //  Let's look for a slot... |                     for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||||
|                         if (!found_slot) { |                         VenueDeviceConfigUpdater * current_job = *job_it; | ||||||
|                             for (auto &cur_task: Tasks) { |                         if(current_job!= nullptr && current_job->done_) { | ||||||
|                                 if (cur_task.task != nullptr && cur_task.task->started_) { |                             Updated += current_job->updated_; | ||||||
|                                     if (cur_task.thr_.isRunning()) |                             Failed += current_job->failed_; | ||||||
|                                         continue; |                             BadConfigs += current_job->bad_config_; | ||||||
|                                     if (!cur_task.thr_.isRunning() && cur_task.task->done_) { |                             if(current_job->updated_) { | ||||||
|                                         cur_task.thr_.join(); |                                 N.content.success.push_back(current_job->SerialNumber); | ||||||
|                                         Updated += cur_task.task->updated_; |                             } else if(current_job->failed_) { | ||||||
|                                         Failed += cur_task.task->failed_; |                                 N.content.warning.push_back(current_job->SerialNumber); | ||||||
|                                         BadConfigs += cur_task.task->bad_config_; |                             } else { | ||||||
|                                         cur_task.task->started_ = cur_task.task->done_ = false; |                                 N.content.error.push_back(current_job->SerialNumber); | ||||||
|                                         delete cur_task.task; |  | ||||||
|                                         cur_task.task = nullptr; |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                             } |                             } | ||||||
|  |                             job_it = JobList.erase(job_it); | ||||||
|  |                             delete current_job; | ||||||
|  |                         } else { | ||||||
|  |                             ++job_it; | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); |                 Logger().debug("Waiting for outstanding update threads to finish."); | ||||||
|                 bool stillTasksRunning=true; |                 Pool_.joinAll(); | ||||||
|                 while(stillTasksRunning) { |                 for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||||
|                     stillTasksRunning = false; |                     VenueDeviceConfigUpdater * current_job = *job_it; | ||||||
|                     for(auto &cur_task:Tasks) { |                     if(current_job!= nullptr && current_job->done_) { | ||||||
|                         if(cur_task.task!= nullptr && cur_task.task->started_) { |                         Updated += current_job->updated_; | ||||||
|                             if(cur_task.thr_.isRunning()) { |                         Failed += current_job->failed_; | ||||||
|                                 stillTasksRunning = true; |                         BadConfigs += current_job->bad_config_; | ||||||
|                                 continue; |                         if(current_job->updated_) { | ||||||
|                             } |                             N.content.success.push_back(current_job->SerialNumber); | ||||||
|                             if(!cur_task.thr_.isRunning() && cur_task.task->done_) { |                         } else if(current_job->failed_) { | ||||||
|                                 cur_task.thr_.join(); |                             N.content.warning.push_back(current_job->SerialNumber); | ||||||
|                                 if(cur_task.task->updated_) { |                         } else { | ||||||
|                                     Updated++; |                             N.content.error.push_back(current_job->SerialNumber); | ||||||
|                                     N.content.success.push_back(cur_task.task->SerialNumber); |  | ||||||
|                                 } else if(cur_task.task->failed_) { |  | ||||||
|                                     Failed++; |  | ||||||
|                                     N.content.warning.push_back(cur_task.task->SerialNumber); |  | ||||||
|                                 } else { |  | ||||||
|                                     BadConfigs++; |  | ||||||
|                                     N.content.error.push_back(cur_task.task->SerialNumber); |  | ||||||
|                                 } |  | ||||||
|                                 cur_task.task->started_ = cur_task.task->done_ = false; |  | ||||||
|                                 delete cur_task.task; |  | ||||||
|                                 cur_task.task = nullptr; |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|  |                         job_it = JobList.erase(job_it); | ||||||
|  |                         delete current_job; | ||||||
|  |                     } else { | ||||||
|  |                         ++job_it; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ", |                 N.content.details = fmt::format("Job {} Completed: {} updated, {} failed to update, {} bad configurations. ", | ||||||
|                                                 JobId_, Updated ,Failed, BadConfigs); |                                                 JobId(), Updated ,Failed, BadConfigs); | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); |                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||||
|                 Logger().warning(N.content.details); |                 Logger().warning(N.content.details); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueUpdateJobCompletionToUser(UI_.email, N); |             // std::cout << N.content.details << std::endl; | ||||||
|  |             WebSocketClientNotificationVenueUpdateJobCompletionToUser(UserInfo().email, N); | ||||||
|             Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.", |             Logger().information(fmt::format("Job {} Completed: {} updated, {} failed to update , {} bad configurations.", | ||||||
|                                              JobId_, Updated ,Failed, BadConfigs)); |                                              JobId(), Updated ,Failed, BadConfigs)); | ||||||
|             delete this; |             Utils::SetThreadName("free"); | ||||||
|  |             Complete(); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
| #include "StorageService.h" | #include "StorageService.h" | ||||||
| #include "APConfig.h" | #include "APConfig.h" | ||||||
| #include "sdks/SDK_gw.h" | #include "sdks/SDK_gw.h" | ||||||
|  | #include "JobController.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
| @@ -48,129 +49,90 @@ namespace OpenWifi { | |||||||
|         inline Poco::Logger & Logger() { return Logger_; } |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class VenueRebooter: public Poco::Runnable { |     class VenueRebooter: public Job { | ||||||
|     public: |     public: | ||||||
|         explicit VenueRebooter(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : |         VenueRebooter(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|                 VenueUUID_(VenueUUID), |                 Job(JobID, name, parameters, when, UI, L) { | ||||||
|                 UI_(UI), |  | ||||||
|                 When_(When), |  | ||||||
|                 Logger_(L) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string Start() { |         inline virtual void run() final { | ||||||
|             JobId_ = MicroService::CreateUUID(); |  | ||||||
|             Worker_.start(*this); |  | ||||||
|             return JobId_; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |             Utils::SetThreadName("venue-reboot"); | ||||||
|         std::string                 VenueUUID_; |  | ||||||
|         SecurityObjects::UserInfo   UI_; |  | ||||||
|         uint64_t                    When_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         Poco::Thread                Worker_; |  | ||||||
|         std::string                 JobId_; |  | ||||||
|         Poco::ThreadPool            Pool_{2,16,300}; |  | ||||||
|  |  | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |  | ||||||
|  |  | ||||||
|         inline void run() final { |  | ||||||
|  |  | ||||||
|             if(When_ && When_>OpenWifi::Now()) |  | ||||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); |  | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootList_t        N; |             WebSocketClientNotificationVenueRebootList_t        N; | ||||||
|  |             auto VenueUUID_ = Parameter(0); | ||||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); |  | ||||||
|  |  | ||||||
|             ProvObjects::Venue  Venue; |             ProvObjects::Venue  Venue; | ||||||
|             uint64_t rebooted_ = 0, failed_ = 0; |             uint64_t rebooted_ = 0, failed_ = 0; | ||||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { |             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||||
|                 const std::size_t MaxThreads=16; |  | ||||||
|                 struct tState { |  | ||||||
|                     Poco::Thread                thr_; |  | ||||||
|                     VenueDeviceRebooter    *task= nullptr; |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name); |                 N.content.title = fmt::format("Rebooting {} devices.", Venue.info.name); | ||||||
|                 N.content.jobId = JobId_; |                 N.content.jobId = JobId(); | ||||||
|  |  | ||||||
|                 std::array<tState,MaxThreads> Tasks; |                 Poco::ThreadPool    Pool_; | ||||||
|  |                 std::list<VenueDeviceRebooter*> JobList; | ||||||
|  |  | ||||||
|                 for(const auto &uuid:Venue.devices) { |                 for(const auto &uuid:Venue.devices) { | ||||||
|                     auto NewTask = new VenueDeviceRebooter(uuid, Venue.info.name, Logger()); |                     auto NewTask = new VenueDeviceRebooter(uuid, Venue.info.name, Logger()); | ||||||
|                     // std::cout << "Scheduling config push for " << uuid << std::endl; |                     bool TaskAdded=false; | ||||||
|                     bool found_slot = false; |                     while(!TaskAdded) { | ||||||
|                     while (!found_slot) { |                         if (Pool_.available()) { | ||||||
|                         for (auto &cur_task: Tasks) { |                             JobList.push_back(NewTask); | ||||||
|                             if (cur_task.task == nullptr) { |                             Pool_.start(*NewTask); | ||||||
|                                 cur_task.task = NewTask; |                             TaskAdded = true; | ||||||
|                                 cur_task.thr_.start(*NewTask); |                             continue; | ||||||
|                                 found_slot = true; |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|  |                     } | ||||||
|  |  | ||||||
|                         //  Let's look for a slot... |                     for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||||
|                         if (!found_slot) { |                         VenueDeviceRebooter * current_job = *job_it; | ||||||
|                             for (auto &cur_task: Tasks) { |                         if(current_job!= nullptr && current_job->done_) { | ||||||
|                                 if (cur_task.task != nullptr && cur_task.task->started_) { |                             if(current_job->rebooted_) | ||||||
|                                     if (cur_task.thr_.isRunning()) |                                 N.content.success.push_back(current_job->SerialNumber); | ||||||
|                                         continue; |                             else | ||||||
|                                     if (!cur_task.thr_.isRunning() && cur_task.task->done_) { |                                 N.content.warning.push_back(current_job->SerialNumber); | ||||||
|                                         cur_task.thr_.join(); |                             rebooted_ += current_job->rebooted_; | ||||||
|                                         rebooted_ += cur_task.task->rebooted_; |                             failed_ += current_job->failed_; | ||||||
|                                         failed_ += cur_task.task->failed_; |                             job_it = JobList.erase(job_it); | ||||||
|                                         cur_task.task->started_ = cur_task.task->done_ = false; |                             delete current_job; | ||||||
|                                         delete cur_task.task; |                         } else { | ||||||
|                                         cur_task.task = nullptr; |                             ++job_it; | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); |                 Logger().debug("Waiting for outstanding update threads to finish."); | ||||||
|                 bool stillTasksRunning=true; |                 Pool_.joinAll(); | ||||||
|                 while(stillTasksRunning) { |                 for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||||
|                     stillTasksRunning = false; |                     VenueDeviceRebooter * current_job = *job_it; | ||||||
|                     for(auto &cur_task:Tasks) { |                     if(current_job!= nullptr && current_job->done_) { | ||||||
|                         if(cur_task.task!= nullptr && cur_task.task->started_) { |                         if(current_job->rebooted_) | ||||||
|                             if(cur_task.thr_.isRunning()) { |                             N.content.success.push_back(current_job->SerialNumber); | ||||||
|                                 stillTasksRunning = true; |                         else | ||||||
|                                 continue; |                             N.content.warning.push_back(current_job->SerialNumber); | ||||||
|                             } |                         rebooted_ += current_job->rebooted_; | ||||||
|                             if(!cur_task.thr_.isRunning() && cur_task.task->done_) { |                         failed_ += current_job->failed_; | ||||||
|                                 cur_task.thr_.join(); |                         job_it = JobList.erase(job_it); | ||||||
|                                 if(cur_task.task->rebooted_) { |                         delete current_job; | ||||||
|                                     rebooted_++; |                     } else { | ||||||
|                                     N.content.success.push_back(cur_task.task->SerialNumber); |                         ++job_it; | ||||||
|                                 } else if(cur_task.task->failed_) { |  | ||||||
|                                     failed_++; |  | ||||||
|                                     N.content.warning.push_back(cur_task.task->SerialNumber); |  | ||||||
|                                 } |  | ||||||
|                                 cur_task.task->started_ = cur_task.task->done_ = false; |  | ||||||
|                                 delete cur_task.task; |  | ||||||
|                                 cur_task.task = nullptr; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", |                 N.content.details = fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", | ||||||
|                                                 JobId_, rebooted_ ,failed_); |                                                 JobId(), rebooted_ ,failed_); | ||||||
|  |  | ||||||
|             } else { |             } else { | ||||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); |                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||||
|                 Logger().warning(N.content.details); |                 Logger().warning(N.content.details); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N); |             // std::cout << N.content.details << std::endl; | ||||||
|  |             WebSocketClientNotificationVenueRebootCompletionToUser(UserInfo().email,N); | ||||||
|             Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", |             Logger().information(fmt::format("Job {} Completed: {} rebooted, {} failed to reboot.", | ||||||
|                                              JobId_, rebooted_ ,failed_)); |                                              JobId(), rebooted_ ,failed_)); | ||||||
|             delete this; |             Utils::SetThreadName("free"); | ||||||
|  |             Complete(); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ | |||||||
| #include "APConfig.h" | #include "APConfig.h" | ||||||
| #include "sdks/SDK_gw.h" | #include "sdks/SDK_gw.h" | ||||||
| #include "sdks/SDK_fms.h" | #include "sdks/SDK_fms.h" | ||||||
|  | #include "JobController.h" | ||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|     class VenueDeviceUpgrade : public Poco::Runnable { |     class VenueDeviceUpgrade : public Poco::Runnable { | ||||||
| @@ -30,7 +31,7 @@ namespace OpenWifi { | |||||||
|  |  | ||||||
|                 Storage::ApplyRules(rules_,Device.deviceRules); |                 Storage::ApplyRules(rules_,Device.deviceRules); | ||||||
|                 if(Device.deviceRules.firmwareUpgrade=="no") { |                 if(Device.deviceRules.firmwareUpgrade=="no") { | ||||||
|                     std::cout << "Skipped Upgrade:" << Device.serialNumber << std::endl; |                     poco_debug(Logger(),fmt::format("Skipped Upgrade: {}", Device.serialNumber)); | ||||||
|                     skipped_++; |                     skipped_++; | ||||||
|                     done_=true; |                     done_=true; | ||||||
|                     return; |                     return; | ||||||
| @@ -39,24 +40,25 @@ namespace OpenWifi { | |||||||
|                 FMSObjects::Firmware    F; |                 FMSObjects::Firmware    F; | ||||||
|                 if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) { |                 if(SDK::FMS::Firmware::GetLatest(Device.deviceType,Device.deviceRules.rcOnly=="yes",F)) { | ||||||
|                     if (SDK::GW::Device::Upgrade(nullptr, Device.serialNumber, 0, F.uri)) { |                     if (SDK::GW::Device::Upgrade(nullptr, Device.serialNumber, 0, F.uri)) { | ||||||
|                         std::cout << "Upgraded:" << Device.serialNumber << " to " << F.uri << std::endl; |  | ||||||
|                         Logger().debug(fmt::format("{}: Upgraded.",Device.serialNumber)); |                         Logger().debug(fmt::format("{}: Upgraded.",Device.serialNumber)); | ||||||
|                         upgraded_++; |                         upgraded_++; | ||||||
|                     } else { |                     } else { | ||||||
|                         std::cout << "Did not Upgrade:" << Device.serialNumber << " to " << F.uri << std::endl; |  | ||||||
|                         Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber)); |                         Logger().information(fmt::format("{}: Not Upgraded.", Device.serialNumber)); | ||||||
|                         failed_++; |                         not_connected_++; | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     std::cout << "Did not Upgrade:" << Device.serialNumber << " to <unknown>" << std::endl; |                     Logger().information(fmt::format("{}: Not Upgraded. No firmware available.", Device.serialNumber)); | ||||||
|                     failed_++; |                     no_firmware_++; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             done_ = true; |             done_ = true; | ||||||
|             // std::cout << "Done push for " << Device.serialNumber << std::endl; |             // std::cout << "Done push for " << Device.serialNumber << std::endl; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         uint64_t        upgraded_=0, failed_=0, skipped_=0; |         std::uint64_t   upgraded_ = 0, | ||||||
|  |                         not_connected_ = 0, | ||||||
|  |                         skipped_ = 0, | ||||||
|  |                         no_firmware_ = 0; | ||||||
|         bool            started_ = false, |         bool            started_ = false, | ||||||
|                         done_ = false; |                         done_ = false; | ||||||
|         std::string     SerialNumber; |         std::string     SerialNumber; | ||||||
| @@ -69,132 +71,111 @@ namespace OpenWifi { | |||||||
|         inline Poco::Logger & Logger() { return Logger_; } |         inline Poco::Logger & Logger() { return Logger_; } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     class VenueUpgrade: public Poco::Runnable { |     class VenueUpgrade: public Job { | ||||||
|     public: |     public: | ||||||
|         explicit VenueUpgrade(const std::string & VenueUUID, const SecurityObjects::UserInfo &UI, uint64_t When, Poco::Logger &L) : |         VenueUpgrade(const std::string &JobID, const std::string &name, const std::vector<std::string> & parameters, uint64_t when, const SecurityObjects::UserInfo &UI, Poco::Logger &L) : | ||||||
|                 VenueUUID_(VenueUUID), |                 Job(JobID, name, parameters, when, UI, L) { | ||||||
|                 UI_(UI), |  | ||||||
|                 When_(When), |  | ||||||
|                 Logger_(L) |  | ||||||
|         { |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         inline std::string Start() { |         inline virtual void run() final { | ||||||
|             JobId_ = MicroService::CreateUUID(); |  | ||||||
|             Worker_.start(*this); |  | ||||||
|             return JobId_; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     private: |             Utils::SetThreadName("venue-upgr"); | ||||||
|         std::string                 VenueUUID_; |             auto VenueUUID_ = Parameter(0); | ||||||
|         SecurityObjects::UserInfo   UI_; |  | ||||||
|         uint64_t                    When_; |  | ||||||
|         Poco::Logger                &Logger_; |  | ||||||
|         Poco::Thread                Worker_; |  | ||||||
|         std::string                 JobId_; |  | ||||||
|         Poco::ThreadPool            Pool_{2,16,300}; |  | ||||||
|  |  | ||||||
|         inline Poco::Logger & Logger() { return Logger_; } |             WebSocketClientNotificationVenueUpgradeList_t        N; | ||||||
|  |  | ||||||
|         inline void run() final { |  | ||||||
|  |  | ||||||
|             if(When_ && When_>OpenWifi::Now()) |  | ||||||
|                 Poco::Thread::trySleep( (long) (When_ - OpenWifi::Now()) * 1000 ); |  | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootList_t        N; |  | ||||||
|  |  | ||||||
|             Logger().information(fmt::format("Job {} Starting.", JobId_)); |  | ||||||
|  |  | ||||||
|             ProvObjects::Venue  Venue; |             ProvObjects::Venue  Venue; | ||||||
|             uint64_t upgraded_ = 0, failed_ = 0; |             uint64_t    upgraded_ = 0, | ||||||
|  |                         not_connected_ = 0, | ||||||
|  |                         skipped_ = 0, | ||||||
|  |                         no_firmware_ = 0; | ||||||
|             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { |             if(StorageService()->VenueDB().GetRecord("id",VenueUUID_,Venue)) { | ||||||
|                 const std::size_t MaxThreads=16; |  | ||||||
|                 struct tState { |  | ||||||
|                     Poco::Thread                thr_; |  | ||||||
|                     VenueDeviceUpgrade    *task= nullptr; |  | ||||||
|                 }; |  | ||||||
|  |  | ||||||
|                 N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name); |                 N.content.title = fmt::format("Upgrading {} devices.", Venue.info.name); | ||||||
|                 N.content.jobId = JobId_; |                 N.content.jobId = JobId(); | ||||||
|  |  | ||||||
|                 std::array<tState,MaxThreads> Tasks; |                 Poco::ThreadPool                Pool_; | ||||||
|                 ProvObjects::DeviceRules    Rules; |                 std::list<VenueDeviceUpgrade*>  JobList; | ||||||
|  |                 ProvObjects::DeviceRules        Rules; | ||||||
|  |  | ||||||
|                 StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules); |                 StorageService()->VenueDB().EvaluateDeviceRules(Venue.info.id, Rules); | ||||||
|  |  | ||||||
|                 for(const auto &uuid:Venue.devices) { |                 for(const auto &uuid:Venue.devices) { | ||||||
|                     auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules,Logger()); |                     auto NewTask = new VenueDeviceUpgrade(uuid, Venue.info.name, Rules, Logger()); | ||||||
|                     // std::cout << "Scheduling config push for " << uuid << std::endl; |                     bool TaskAdded = false; | ||||||
|                     bool found_slot = false; |                     while (!TaskAdded) { | ||||||
|                     while (!found_slot) { |                         if (Pool_.available()) { | ||||||
|                         for (auto &cur_task: Tasks) { |                             JobList.push_back(NewTask); | ||||||
|                             if (cur_task.task == nullptr) { |                             Pool_.start(*NewTask); | ||||||
|                                 cur_task.task = NewTask; |                             TaskAdded = true; | ||||||
|                                 cur_task.thr_.start(*NewTask); |                             continue; | ||||||
|                                 found_slot = true; |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                         //  Let's look for a slot... |  | ||||||
|                         if (!found_slot) { |  | ||||||
|                             for (auto &cur_task: Tasks) { |  | ||||||
|                                 if (cur_task.task != nullptr && cur_task.task->started_) { |  | ||||||
|                                     if (cur_task.thr_.isRunning()) |  | ||||||
|                                         continue; |  | ||||||
|                                     if (!cur_task.thr_.isRunning() && cur_task.task->done_) { |  | ||||||
|                                         cur_task.thr_.join(); |  | ||||||
|                                         upgraded_ += cur_task.task->upgraded_; |  | ||||||
|                                         failed_ += cur_task.task->failed_; |  | ||||||
|                                         cur_task.task->started_ = cur_task.task->done_ = false; |  | ||||||
|                                         delete cur_task.task; |  | ||||||
|                                         cur_task.task = nullptr; |  | ||||||
|                                     } |  | ||||||
|                                 } |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |  | ||||||
|                 Logger().debug("Waiting for outstanding update threads to finish."); |                     for (auto job_it = JobList.begin(); job_it != JobList.end();) { | ||||||
|                 bool stillTasksRunning=true; |                         VenueDeviceUpgrade *current_job = *job_it; | ||||||
|                 while(stillTasksRunning) { |                         if (current_job != nullptr && current_job->done_) { | ||||||
|                     stillTasksRunning = false; |                             if (current_job->upgraded_) | ||||||
|                     for(auto &cur_task:Tasks) { |                                 N.content.success.push_back(current_job->SerialNumber); | ||||||
|                         if(cur_task.task!= nullptr && cur_task.task->started_) { |                             else  if (current_job->skipped_) | ||||||
|                             if(cur_task.thr_.isRunning()) { |                                 N.content.skipped.push_back(current_job->SerialNumber); | ||||||
|                                 stillTasksRunning = true; |                             else  if (current_job->not_connected_) | ||||||
|                                 continue; |                                 N.content.not_connected.push_back(current_job->SerialNumber); | ||||||
|                             } |                             else  if (current_job->no_firmware_) | ||||||
|                             if(!cur_task.thr_.isRunning() && cur_task.task->done_) { |                                 N.content.no_firmware.push_back(current_job->SerialNumber); | ||||||
|                                 cur_task.thr_.join(); |                             upgraded_ += current_job->upgraded_; | ||||||
|                                 if(cur_task.task->upgraded_) { |                             skipped_ += current_job->skipped_; | ||||||
|                                     upgraded_++; |                             no_firmware_ += current_job->no_firmware_; | ||||||
|                                     N.content.success.push_back(cur_task.task->SerialNumber); |                             not_connected_ += current_job->not_connected_; | ||||||
|                                 } else if(cur_task.task->failed_) { |                             job_it = JobList.erase(job_it); | ||||||
|                                     failed_++; |                             delete current_job; | ||||||
|                                     N.content.warning.push_back(cur_task.task->SerialNumber); |                         } else { | ||||||
|                                 } |                             ++job_it; | ||||||
|                                 cur_task.task->started_ = cur_task.task->done_ = false; |  | ||||||
|                                 delete cur_task.task; |  | ||||||
|                                 cur_task.task = nullptr; |  | ||||||
|                             } |  | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 N.content.details = fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", |                 Logger().debug("Waiting for outstanding upgrade threads to finish."); | ||||||
|                                                 JobId_, upgraded_ ,failed_); |                 Pool_.joinAll(); | ||||||
|  |                 for(auto job_it = JobList.begin(); job_it !=JobList.end();) { | ||||||
|  |                     VenueDeviceUpgrade * current_job = *job_it; | ||||||
|  |                     if(current_job!= nullptr && current_job->done_) { | ||||||
|  |                         if (current_job->upgraded_) | ||||||
|  |                             N.content.success.push_back(current_job->SerialNumber); | ||||||
|  |                         else  if (current_job->skipped_) | ||||||
|  |                             N.content.skipped.push_back(current_job->SerialNumber); | ||||||
|  |                         else  if (current_job->not_connected_) | ||||||
|  |                             N.content.not_connected.push_back(current_job->SerialNumber); | ||||||
|  |                         else  if (current_job->no_firmware_) | ||||||
|  |                             N.content.no_firmware.push_back(current_job->SerialNumber); | ||||||
|  |                         upgraded_ += current_job->upgraded_; | ||||||
|  |                         skipped_ += current_job->skipped_; | ||||||
|  |                         no_firmware_ += current_job->no_firmware_; | ||||||
|  |                         not_connected_ += current_job->not_connected_; | ||||||
|  |                         job_it = JobList.erase(job_it); | ||||||
|  |                         delete current_job; | ||||||
|  |                     } else { | ||||||
|  |                         ++job_it; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 N.content.details = fmt::format("Job {} Completed: {} upgraded, {} not connected, {} skipped, {} no firmware.", | ||||||
|  |                                                 JobId(), | ||||||
|  |                                                 upgraded_ , | ||||||
|  |                                                 not_connected_, | ||||||
|  |                                                 skipped_, | ||||||
|  |                                                 no_firmware_); | ||||||
|             } else { |             } else { | ||||||
|                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); |                 N.content.details = fmt::format("Venue {} no longer exists.",VenueUUID_); | ||||||
|                 Logger().warning(N.content.details); |                 Logger().warning(N.content.details); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             WebSocketClientNotificationVenueRebootCompletionToUser(UI_.email,N); |             // std::cout << N.content.details << std::endl; | ||||||
|             Logger().information(fmt::format("Job {} Completed: {} upgraded, {} failed to upgrade.", |             WebSocketClientNotificationVenueUpgradeCompletionToUser(UserInfo().email,N); | ||||||
|                                              JobId_, upgraded_ ,failed_)); |             Logger().information(N.content.details); | ||||||
|             delete this; |             Utils::SetThreadName("free"); | ||||||
|  |             Complete(); | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @@ -13,9 +13,10 @@ | |||||||
|  |  | ||||||
| namespace OpenWifi { | namespace OpenWifi { | ||||||
|  |  | ||||||
|     static const std::string GitUCentralJSONSchemaFile{"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | static const std::string GitUCentralJSONSchemaFile{ | ||||||
|  | 	"https://raw.githubusercontent.com/blogic/ucentral-schema/main/ucentral.schema.json"}; | ||||||
|  |  | ||||||
|     static json DefaultUCentralSchema = R"( | static json DefaultUCentralSchema = R"( | ||||||
|  |  | ||||||
| { | { | ||||||
| 	"$id": "https://openwrt.org/ucentral.schema.json", | 	"$id": "https://openwrt.org/ucentral.schema.json", | ||||||
| @@ -43,7 +44,7 @@ namespace OpenWifi { | |||||||
| 		"switch": { | 		"switch": { | ||||||
| 			"$ref": "#/$defs/switch" | 			"$ref": "#/$defs/switch" | ||||||
| 		}, | 		}, | ||||||
| 		"radios": { | 		"radiosgrep": { | ||||||
| 			"type": "array", | 			"type": "array", | ||||||
| 			"items": { | 			"items": { | ||||||
| 				"$ref": "#/$defs/radio" | 				"$ref": "#/$defs/radio" | ||||||
| @@ -518,7 +519,7 @@ namespace OpenWifi { | |||||||
| 					"maximum": 4050 | 					"maximum": 4050 | ||||||
| 				}, | 				}, | ||||||
| 				"proto": { | 				"proto": { | ||||||
| 					"decription": "The L2 vlan tag that shall be added (1q,1ad) ", | 					"decription": "The L2 vlan tag that shall be added (1q,1ad ) ", | ||||||
| 					"type": "string", | 					"type": "string", | ||||||
| 					"enum": [ | 					"enum": [ | ||||||
| 						"802.1ad", | 						"802.1ad", | ||||||
| @@ -669,6 +670,47 @@ namespace OpenWifi { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"interface.ipv4.port-forward": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"properties": { | ||||||
|  | 				"protocol": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"enum": [ | ||||||
|  | 						"tcp", | ||||||
|  | 						"udp", | ||||||
|  | 						"any" | ||||||
|  | 					], | ||||||
|  | 					"default": "any" | ||||||
|  | 				}, | ||||||
|  | 				"external-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				}, | ||||||
|  | 				"internal-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "ipv4", | ||||||
|  | 					"example": "0.0.0.120" | ||||||
|  | 				}, | ||||||
|  | 				"internal-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"required": [ | ||||||
|  | 				"external-port", | ||||||
|  | 				"internal-address" | ||||||
|  | 			] | ||||||
|  | 		}, | ||||||
| 		"interface.ipv4": { | 		"interface.ipv4": { | ||||||
| 			"type": "object", | 			"type": "object", | ||||||
| 			"properties": { | 			"properties": { | ||||||
| @@ -722,6 +764,12 @@ namespace OpenWifi { | |||||||
| 					"items": { | 					"items": { | ||||||
| 						"$ref": "#/$defs/interface.ipv4.dhcp-lease" | 						"$ref": "#/$defs/interface.ipv4.dhcp-lease" | ||||||
| 					} | 					} | ||||||
|  | 				}, | ||||||
|  | 				"port-forward": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"items": { | ||||||
|  | 						"$ref": "#/$defs/interface.ipv4.port-forward" | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -751,6 +799,96 @@ namespace OpenWifi { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
|  | 		"interface.ipv6.port-forward": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"properties": { | ||||||
|  | 				"protocol": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"enum": [ | ||||||
|  | 						"tcp", | ||||||
|  | 						"udp", | ||||||
|  | 						"any" | ||||||
|  | 					], | ||||||
|  | 					"default": "any" | ||||||
|  | 				}, | ||||||
|  | 				"external-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				}, | ||||||
|  | 				"internal-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "ipv6", | ||||||
|  | 					"example": "::1234:abcd" | ||||||
|  | 				}, | ||||||
|  | 				"internal-port": { | ||||||
|  | 					"type": [ | ||||||
|  | 						"integer", | ||||||
|  | 						"string" | ||||||
|  | 					], | ||||||
|  | 					"minimum": 0, | ||||||
|  | 					"maximum": 65535, | ||||||
|  | 					"format": "uc-portrange" | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"required": [ | ||||||
|  | 				"external-port", | ||||||
|  | 				"internal-address" | ||||||
|  | 			] | ||||||
|  | 		}, | ||||||
|  | 		"interface.ipv6.traffic-allow": { | ||||||
|  | 			"type": "object", | ||||||
|  | 			"properties": { | ||||||
|  | 				"protocol": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"default": "any" | ||||||
|  | 				}, | ||||||
|  | 				"source-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "uc-cidr6", | ||||||
|  | 					"example": "2001:db8:1234:abcd::/64", | ||||||
|  | 					"default": "::/0" | ||||||
|  | 				}, | ||||||
|  | 				"source-ports": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"minItems": 1, | ||||||
|  | 					"items": { | ||||||
|  | 						"type": [ | ||||||
|  | 							"integer", | ||||||
|  | 							"string" | ||||||
|  | 						], | ||||||
|  | 						"minimum": 0, | ||||||
|  | 						"maximum": 65535, | ||||||
|  | 						"format": "uc-portrange" | ||||||
|  | 					} | ||||||
|  | 				}, | ||||||
|  | 				"destination-address": { | ||||||
|  | 					"type": "string", | ||||||
|  | 					"format": "ipv6", | ||||||
|  | 					"example": "::1000" | ||||||
|  | 				}, | ||||||
|  | 				"destination-ports": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"minItems": 1, | ||||||
|  | 					"items": { | ||||||
|  | 						"type": [ | ||||||
|  | 							"integer", | ||||||
|  | 							"string" | ||||||
|  | 						], | ||||||
|  | 						"minimum": 0, | ||||||
|  | 						"maximum": 65535, | ||||||
|  | 						"format": "uc-portrange" | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			"required": [ | ||||||
|  | 				"destination-address" | ||||||
|  | 			] | ||||||
|  | 		}, | ||||||
| 		"interface.ipv6": { | 		"interface.ipv6": { | ||||||
| 			"type": "object", | 			"type": "object", | ||||||
| 			"properties": { | 			"properties": { | ||||||
| @@ -782,6 +920,18 @@ namespace OpenWifi { | |||||||
| 				}, | 				}, | ||||||
| 				"dhcpv6": { | 				"dhcpv6": { | ||||||
| 					"$ref": "#/$defs/interface.ipv6.dhcpv6" | 					"$ref": "#/$defs/interface.ipv6.dhcpv6" | ||||||
|  | 				}, | ||||||
|  | 				"port-forward": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"items": { | ||||||
|  | 						"$ref": "#/$defs/interface.ipv6.port-forward" | ||||||
|  | 					} | ||||||
|  | 				}, | ||||||
|  | 				"traffic-allow": { | ||||||
|  | 					"type": "array", | ||||||
|  | 					"items": { | ||||||
|  | 						"$ref": "#/$defs/interface.ipv6.traffic-allow" | ||||||
|  | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -866,7 +1016,7 @@ namespace OpenWifi { | |||||||
| 				}, | 				}, | ||||||
| 				"gateway-fqdn": { | 				"gateway-fqdn": { | ||||||
| 					"type": "string", | 					"type": "string", | ||||||
| 					"format": "fqdn", | 					"format": "uc-fqdn", | ||||||
| 					"default": "ucentral.splash" | 					"default": "ucentral.splash" | ||||||
| 				}, | 				}, | ||||||
| 				"max-clients": { | 				"max-clients": { | ||||||
| @@ -901,6 +1051,7 @@ namespace OpenWifi { | |||||||
| 						"psk", | 						"psk", | ||||||
| 						"psk2", | 						"psk2", | ||||||
| 						"psk-mixed", | 						"psk-mixed", | ||||||
|  | 						"psk2-radius", | ||||||
| 						"wpa", | 						"wpa", | ||||||
| 						"wpa2", | 						"wpa2", | ||||||
| 						"wpa-mixed", | 						"wpa-mixed", | ||||||
| @@ -961,6 +1112,10 @@ namespace OpenWifi { | |||||||
| 					"type": "boolean", | 					"type": "boolean", | ||||||
| 					"default": false | 					"default": false | ||||||
| 				}, | 				}, | ||||||
|  | 				"reduced-neighbor-reporting": { | ||||||
|  | 					"type": "boolean", | ||||||
|  | 					"default": false | ||||||
|  | 				}, | ||||||
| 				"lci": { | 				"lci": { | ||||||
| 					"type": "string" | 					"type": "string" | ||||||
| 				}, | 				}, | ||||||
| @@ -1527,6 +1682,11 @@ namespace OpenWifi { | |||||||
| 					"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", | 					"decription": "This option allows embedding custom vendor specific IEs inside the beacons of a BSS in AP mode.", | ||||||
| 					"type": "string" | 					"type": "string" | ||||||
| 				}, | 				}, | ||||||
|  | 				"fils-discovery-interval": { | ||||||
|  | 					"type": "integer", | ||||||
|  | 					"default": 20, | ||||||
|  | 					"maximum": 10000 | ||||||
|  | 				}, | ||||||
| 				"encryption": { | 				"encryption": { | ||||||
| 					"$ref": "#/$defs/interface.ssid.encryption" | 					"$ref": "#/$defs/interface.ssid.encryption" | ||||||
| 				}, | 				}, | ||||||
| @@ -2087,6 +2247,10 @@ namespace OpenWifi { | |||||||
| 				"auto-channel": { | 				"auto-channel": { | ||||||
| 					"type": "boolean", | 					"type": "boolean", | ||||||
| 					"default": false | 					"default": false | ||||||
|  | 				}, | ||||||
|  | 				"ipv6": { | ||||||
|  | 					"type": "boolean", | ||||||
|  | 					"default": false | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| @@ -2193,7 +2357,7 @@ namespace OpenWifi { | |||||||
| 									"properties": { | 									"properties": { | ||||||
| 										"fqdn": { | 										"fqdn": { | ||||||
| 											"type": "string", | 											"type": "string", | ||||||
| 											"format": "fqdn" | 											"format": "uc-fqdn" | ||||||
| 										}, | 										}, | ||||||
| 										"suffix-matching": { | 										"suffix-matching": { | ||||||
| 											"type": "boolean", | 											"type": "boolean", | ||||||
| @@ -2444,8 +2608,7 @@ namespace OpenWifi { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | )"_json; | ||||||
|     )"_json; |  | ||||||
|  |  | ||||||
|     class custom_error_handler : public nlohmann::json_schema::basic_error_handler |     class custom_error_handler : public nlohmann::json_schema::basic_error_handler | ||||||
|     { |     { | ||||||
| @@ -2460,9 +2623,18 @@ namespace OpenWifi { | |||||||
|     void ConfigurationValidator::Init() { |     void ConfigurationValidator::Init() { | ||||||
|         if(Initialized_) |         if(Initialized_) | ||||||
|             return; |             return; | ||||||
|  |  | ||||||
|         std::string GitSchema; |         std::string GitSchema; | ||||||
|  | 		if(MicroService::instance().ConfigGetBool("ucentral.datamodel.internal",true)) { | ||||||
|  | 			RootSchema_ = DefaultUCentralSchema; | ||||||
|  | 			Logger().information("Using uCentral validation from built-in default."); | ||||||
|  | 			Initialized_ = Working_ = true; | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             if(Utils::wgets(GitUCentralJSONSchemaFile, GitSchema)) { | 			auto GitURI = MicroService::instance().ConfigGetString("ucentral.datamodel.uri",GitUCentralJSONSchemaFile); | ||||||
|  |             if(Utils::wgets(GitURI, GitSchema)) { | ||||||
|                 RootSchema_ = json::parse(GitSchema); |                 RootSchema_ = json::parse(GitSchema); | ||||||
|                 Logger().information("Using uCentral validation schema from GIT."); |                 Logger().information("Using uCentral validation schema from GIT."); | ||||||
|             } else { |             } else { | ||||||
| @@ -2528,6 +2700,17 @@ namespace OpenWifi { | |||||||
|         return IsCIDRv4(value) || IsCIDRv6(value); |         return IsCIDRv4(value) || IsCIDRv6(value); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     static inline bool IsPortRangeIsValid(const std::string &r) { | ||||||
|  |         const auto ports = Poco::StringTokenizer("-",r,Poco::StringTokenizer::TOK_TRIM); | ||||||
|  |  | ||||||
|  |         for(const auto &port:ports) { | ||||||
|  |             uint32_t port_num = std::stoul(port); | ||||||
|  |             if(port_num==0 || port_num>65535) | ||||||
|  |                 return false; | ||||||
|  |         } | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) |     void ConfigurationValidator::my_format_checker(const std::string &format, const std::string &value) | ||||||
|     { |     { | ||||||
|         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; |         static const std::regex host_regex{"^(?=.{1,254}$)((?=[a-z0-9-]{1,63}\\.)(xn--+)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}$"}; | ||||||
| @@ -2578,6 +2761,14 @@ namespace OpenWifi { | |||||||
|             } catch (...) { |             } catch (...) { | ||||||
|             } |             } | ||||||
|             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); |             throw std::invalid_argument(value + " is not a valid URI: should be something like https://hello.world.com."); | ||||||
|  |         } else if(format == "uc-portrange") { | ||||||
|  |             try { | ||||||
|  |                 if(IsPortRangeIsValid(value)) | ||||||
|  |                     return; | ||||||
|  |                 throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||||
|  |             } catch (...) { | ||||||
|  |             } | ||||||
|  |             throw std::invalid_argument(value + " is not a valid port range: should an integer between 1-65535 or a port range like post-port."); | ||||||
|         } else if(format == "ip") { |         } else if(format == "ip") { | ||||||
|             if (IsIP(value)) |             if (IsIP(value)) | ||||||
|                 return; |                 return; | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										169
									
								
								src/framework/MicroServiceErrorHandler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/framework/MicroServiceErrorHandler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2022-09-29. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "fmt/format.h" | ||||||
|  | #include "Poco/Util/Application.h" | ||||||
|  | #include "Poco/ErrorHandler.h" | ||||||
|  | #include "Poco/Net/NetException.h" | ||||||
|  | #include "Poco/Net/SSLException.h" | ||||||
|  | #include "Poco/JSON/Template.h" | ||||||
|  | #include "Poco/Thread.h" | ||||||
|  |  | ||||||
|  | namespace OpenWifi { | ||||||
|  |  | ||||||
|  | 	class MicroServiceErrorHandler : public Poco::ErrorHandler { | ||||||
|  | 	  public: | ||||||
|  | 		explicit MicroServiceErrorHandler(Poco::Util::Application &App) : App_(App) { | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		inline void exception(const Poco::Exception & Base) override { | ||||||
|  | 			try { | ||||||
|  | 				if(Poco::Thread::current()!= nullptr) { | ||||||
|  | 					t_name = Poco::Thread::current()->getName(); | ||||||
|  | 					t_id = Poco::Thread::current()->id(); | ||||||
|  | 				} else { | ||||||
|  | 					t_name = "startup_code"; | ||||||
|  | 					t_id = 0; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				App_.logger().log(Base); | ||||||
|  | 				Base.rethrow(); | ||||||
|  |  | ||||||
|  | 			} catch (const Poco::Net::InvalidCertificateException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::InvalidCertificateException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::InvalidSocketException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::InvalidSocketException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::WebSocketException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::WebSocketException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::ConnectionResetException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::ConnectionResetException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::CertificateValidationException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::CertificateValidationException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::SSLConnectionUnexpectedlyClosedException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::SSLContextException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::SSLContextException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Net::SSLException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::SSLException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  |  | ||||||
|  | 			} catch (const Poco::Net::InvalidAddressException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::InvalidAddressException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  |  | ||||||
|  | 			} catch (const Poco::Net::NetException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Net::NetException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  |  | ||||||
|  | 			} catch (const Poco::IOException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::IOException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::RuntimeException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::JSON::JSONTemplateException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::JSON::JSONTemplateException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::JSON::JSONException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::JSON::JSONException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::ApplicationException &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::ApplicationException thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (const Poco::Exception &E) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco::Exception thr_name={} thr_id={} code={} text={} msg={} what={}", | ||||||
|  | 													  t_name, t_id, E.code(), | ||||||
|  | 													  E.displayText(), | ||||||
|  | 													  E.message(), | ||||||
|  | 													  E.what())); | ||||||
|  | 			} catch (...) { | ||||||
|  | 				poco_error(App_.logger(), fmt::format("Poco:Generic thr_name={}",t_name, t_id)); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		inline void exception(const std::exception & E) override { | ||||||
|  | 			if(Poco::Thread::current()!= nullptr) { | ||||||
|  | 				t_name = Poco::Thread::current()->getName(); | ||||||
|  | 				t_id = Poco::Thread::current()->id(); | ||||||
|  | 			} else { | ||||||
|  | 				t_name = "startup_code"; | ||||||
|  | 				t_id = 0; | ||||||
|  | 			} | ||||||
|  | 			poco_warning(App_.logger(), fmt::format("std::exception in {}: {} thr_id={}", | ||||||
|  | 													t_name,E.what(), | ||||||
|  | 													t_id)); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		inline void exception() override { | ||||||
|  | 			if(Poco::Thread::current()!= nullptr) { | ||||||
|  | 				t_name = Poco::Thread::current()->getName(); | ||||||
|  | 				t_id = Poco::Thread::current()->id(); | ||||||
|  | 			} else { | ||||||
|  | 				t_name = "startup_code"; | ||||||
|  | 				t_id = 0; | ||||||
|  | 			} | ||||||
|  | 			poco_warning(App_.logger(), fmt::format("generic exception in {} thr_id={}", | ||||||
|  | 													t_name, t_id)); | ||||||
|  | 		} | ||||||
|  | 	  private: | ||||||
|  | 		Poco::Util::Application	&App_; | ||||||
|  | 		std::string		t_name; | ||||||
|  | 		int 			t_id=0; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -33,7 +33,6 @@ namespace OpenWifi { | |||||||
|         int Start() override { |         int Start() override { | ||||||
|             std::lock_guard		Guard(Mutex_); |             std::lock_guard		Guard(Mutex_); | ||||||
|  |  | ||||||
|             Logger().setLevel(Poco::Message::PRIO_INFORMATION); |  | ||||||
|             Logger().notice("Starting."); |             Logger().notice("Starting."); | ||||||
|             std::string DBType = MicroService::instance().ConfigGetString("storage.type"); |             std::string DBType = MicroService::instance().ConfigGetString("storage.type"); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -146,6 +146,10 @@ namespace OpenWifi { | |||||||
|         WebSocketClientServer()->SendUserNotification(User,N); |         WebSocketClientServer()->SendUserNotification(User,N); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     ///// | ||||||
|  |     ///// | ||||||
|  |     ///// | ||||||
|  |  | ||||||
|     struct WebSocketNotificationRebootList { |     struct WebSocketNotificationRebootList { | ||||||
|         std::string                 title, |         std::string                 title, | ||||||
|                 details, |                 details, | ||||||
| @@ -189,5 +193,58 @@ namespace OpenWifi { | |||||||
|         WebSocketClientServer()->SendUserNotification(User,N); |         WebSocketClientServer()->SendUserNotification(User,N); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     ///// | ||||||
|  |     ///// | ||||||
|  |     ///// | ||||||
|  |  | ||||||
|  |     struct WebSocketNotificationUpgradeList { | ||||||
|  |         std::string                 title, | ||||||
|  |                 details, | ||||||
|  |                 jobId; | ||||||
|  |         std::vector<std::string>    success, | ||||||
|  |                                     skipped, | ||||||
|  |                                     no_firmware, | ||||||
|  |                                     not_connected; | ||||||
|  |         uint64_t                    timeStamp=OpenWifi::Now(); | ||||||
|  |  | ||||||
|  |         void to_json(Poco::JSON::Object &Obj) const; | ||||||
|  |         bool from_json(const Poco::JSON::Object::Ptr &Obj); | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     typedef WebSocketNotification<WebSocketNotificationUpgradeList> WebSocketClientNotificationVenueUpgradeList_t; | ||||||
|  |  | ||||||
|  |     inline void WebSocketNotificationUpgradeList::to_json(Poco::JSON::Object &Obj) const { | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"title",title); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"jobId",jobId); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"success",success); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"notConnected",not_connected); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"noFirmware",no_firmware); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"skipped",skipped); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"timeStamp",timeStamp); | ||||||
|  |         RESTAPI_utils::field_to_json(Obj,"details",details); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline bool WebSocketNotificationUpgradeList::from_json(const Poco::JSON::Object::Ptr &Obj) { | ||||||
|  |         try { | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"title",title); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"jobId",jobId); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"success",success); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"notConnected",not_connected); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"noFirmware",no_firmware); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"skipped",skipped); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"timeStamp",timeStamp); | ||||||
|  |             RESTAPI_utils::field_from_json(Obj,"details",details); | ||||||
|  |             return true; | ||||||
|  |         } catch(...) { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     inline void WebSocketClientNotificationVenueUpgradeCompletionToUser( const std::string & User, WebSocketClientNotificationVenueUpgradeList_t &N) { | ||||||
|  |         N.type = "venue_upgrader"; | ||||||
|  |         WebSocketClientServer()->SendUserNotification(User,N); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } // namespace OpenWifi | } // namespace OpenWifi | ||||||
|  |  | ||||||
|   | |||||||
| @@ -133,6 +133,37 @@ namespace ORM { | |||||||
|         return R; |         return R; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     inline std::string WHERE_AND_(std::string Result) { | ||||||
|  |         return Result; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template <typename T, typename... Args> std::string WHERE_AND_(std::string Result, const char *fieldName, const T &Value, Args... args) { | ||||||
|  |         if constexpr(std::is_same_v<T,std::string>) | ||||||
|  |         { | ||||||
|  |             if(!Value.empty()) { | ||||||
|  |                 if(!Result.empty()) | ||||||
|  |                     Result += " and "; | ||||||
|  |                 Result += fieldName; | ||||||
|  |                 Result += '='; | ||||||
|  |                 Result += "'"; | ||||||
|  |                 Result += Escape(Value); | ||||||
|  |                 Result += "'"; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if(!Result.empty()) | ||||||
|  |                 Result += " and "; | ||||||
|  |             Result += fieldName ; | ||||||
|  |             Result += '='; | ||||||
|  |             Result += std::to_string(Value); | ||||||
|  |         } | ||||||
|  |         return WHERE_AND_(Result,args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template <typename... Args> std::string WHERE_AND(Args... args) { | ||||||
|  |         std::string Result; | ||||||
|  |         return WHERE_AND_(Result, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE }; |     enum SqlComparison { EQ = 0, NEQ, LT, LTE, GT, GTE }; | ||||||
|     enum SqlBinaryOp { AND = 0 , OR }; |     enum SqlBinaryOp { AND = 0 , OR }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <cstring> | ||||||
| #include "Poco/String.h" | #include "Poco/String.h" | ||||||
|  |  | ||||||
| #if defined(__GNUC__) | #if defined(__GNUC__) | ||||||
| @@ -195,6 +196,8 @@ namespace OpenWifi::RESTAPI::Errors { | |||||||
| 	static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."}; | 	static const struct msg InvalidRadiusServerEntry{1142,"RADIUS Server IP address invalid or port missing."}; | ||||||
| 	static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."}; | 	static const struct msg InvalidRadiusServerWeigth{1143,"RADIUS Server IP weight cannot be 0."}; | ||||||
|  |  | ||||||
|  | 	static const struct msg MaximumRTTYSessionsReached{1144,"Too many RTTY sessions currently active"}; | ||||||
|  | 	static const struct msg DeviceIsAlreadyBusy{1145,"Device is already executing a command. Please try later."}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -427,7 +430,9 @@ namespace OpenWifi::uCentralProtocol { | |||||||
| 	static const char *RADIUSDATA = "data"; | 	static const char *RADIUSDATA = "data"; | ||||||
| 	static const char *RADIUSACCT = "acct"; | 	static const char *RADIUSACCT = "acct"; | ||||||
| 	static const char *RADIUSAUTH = "auth"; | 	static const char *RADIUSAUTH = "auth"; | ||||||
|  | 	static const char *RADIUSCOA = "coa"; | ||||||
| 	static const char *RADIUSDST = "dst"; | 	static const char *RADIUSDST = "dst"; | ||||||
|  | 	static const char *IES = "ies"; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| namespace OpenWifi::uCentralProtocol::Events { | namespace OpenWifi::uCentralProtocol::Events { | ||||||
| @@ -442,6 +447,7 @@ namespace OpenWifi::uCentralProtocol::Events { | |||||||
|     static const char *RECOVERY = "recovery"; |     static const char *RECOVERY = "recovery"; | ||||||
|     static const char *TELEMETRY = "telemetry"; |     static const char *TELEMETRY = "telemetry"; | ||||||
|     static const char *DEVICEUPDATE = "deviceupdate"; |     static const char *DEVICEUPDATE = "deviceupdate"; | ||||||
|  | 	static const char *VENUE_BROADCAST = "venue_broadcast"; | ||||||
|  |  | ||||||
|     enum EVENT_MSG { |     enum EVENT_MSG { | ||||||
| 		ET_UNKNOWN, | 		ET_UNKNOWN, | ||||||
| @@ -454,28 +460,34 @@ namespace OpenWifi::uCentralProtocol::Events { | |||||||
| 		ET_CFGPENDING, | 		ET_CFGPENDING, | ||||||
| 		ET_RECOVERY, | 		ET_RECOVERY, | ||||||
| 		ET_DEVICEUPDATE, | 		ET_DEVICEUPDATE, | ||||||
| 		ET_TELEMETRY | 		ET_TELEMETRY, | ||||||
|  | 		ET_VENUEBROADCAST | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	inline static EVENT_MSG EventFromString(const std::string & Method) { | 	inline EVENT_MSG EventFromString(const std::string & Method) { | ||||||
|         static std::vector<std::pair<const char *,EVENT_MSG>>   Values{ | 		if(strcmp(STATE,Method.c_str())==0) | ||||||
|                 { CFGPENDING , ET_CFGPENDING }, | 			return ET_STATE; | ||||||
|                 { CONNECT, ET_CONNECT }, | 		else if(strcmp(HEALTHCHECK,Method.c_str())==0) | ||||||
|                 { CRASHLOG, ET_CRASHLOG }, | 			return ET_HEALTHCHECK; | ||||||
|                 { DEVICEUPDATE, ET_DEVICEUPDATE }, | 		else if(strcmp(CONNECT,Method.c_str())==0) | ||||||
|                 { HEALTHCHECK, ET_HEALTHCHECK }, | 			return ET_CONNECT; | ||||||
|                 { LOG, ET_LOG }, | 		else if(strcmp(CFGPENDING,Method.c_str())==0) | ||||||
|                 { PING, ET_PING }, | 			return ET_CFGPENDING; | ||||||
|                 { RECOVERY, ET_RECOVERY }, | 		else if(strcmp(CRASHLOG,Method.c_str())==0) | ||||||
|                 { STATE, ET_STATE }, | 			return ET_CRASHLOG; | ||||||
|                 { TELEMETRY, ET_TELEMETRY } | 		else if(strcmp(DEVICEUPDATE,Method.c_str())==0) | ||||||
|         }; | 			return ET_DEVICEUPDATE; | ||||||
|  | 		else if(strcmp(LOG,Method.c_str())==0) | ||||||
|         std::string L = Poco::toLower(Method); | 			return ET_LOG; | ||||||
|         auto hint = std::find_if(cbegin(Values),cend(Values),[&](const std::pair<const char *,EVENT_MSG> &v) ->bool { return strcmp(v.first,L.c_str())==0; }); | 		else if(strcmp(PING,Method.c_str())==0) | ||||||
|         if(hint == cend(Values)) | 			return ET_PING; | ||||||
|             return ET_UNKNOWN; | 		else if(strcmp(RECOVERY,Method.c_str())==0) | ||||||
|         return hint->second; | 			return ET_RECOVERY; | ||||||
|  | 		else if(strcmp(TELEMETRY,Method.c_str())==0) | ||||||
|  | 			return ET_TELEMETRY; | ||||||
|  | 		else if(strcmp(VENUE_BROADCAST,Method.c_str())==0) | ||||||
|  | 			return ET_VENUEBROADCAST; | ||||||
|  | 		return ET_UNKNOWN; | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										937
									
								
								src/libs/croncpp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										937
									
								
								src/libs/croncpp.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,937 @@ | |||||||
|  | /* | ||||||
|  |     MIT License | ||||||
|  |  | ||||||
|  |     Copyright (c) 2018 Marius Bancila | ||||||
|  |  | ||||||
|  |     Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  |     of this software and associated documentation files (the "Software"), to deal | ||||||
|  |     in the Software without restriction, including without limitation the rights | ||||||
|  |     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  |     copies of the Software, and to permit persons to whom the Software is | ||||||
|  |     furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  |     The above copyright notice and this permission notice shall be included in all | ||||||
|  |     copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  |     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  |     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  |     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  |     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  |     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  |     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||||
|  |     SOFTWARE. | ||||||
|  |  | ||||||
|  |     This file is from https://github.com/mariusbancila/croncpp.git. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  | #include <string> | ||||||
|  | #include <sstream> | ||||||
|  | #include <bitset> | ||||||
|  | #include <cctype> | ||||||
|  | #include <ctime> | ||||||
|  | #include <iomanip> | ||||||
|  | #include <algorithm> | ||||||
|  | #include <chrono> | ||||||
|  |  | ||||||
|  | #if __cplusplus > 201402L | ||||||
|  | #include <string_view> | ||||||
|  | #define CRONCPP_IS_CPP17 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace cron | ||||||
|  | { | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |    #define  CRONCPP_STRING_VIEW       std::string_view | ||||||
|  |    #define  CRONCPP_STRING_VIEW_NPOS  std::string_view::npos | ||||||
|  |    #define  CRONCPP_CONSTEXPTR        constexpr | ||||||
|  | #else | ||||||
|  |    #define  CRONCPP_STRING_VIEW       std::string const & | ||||||
|  |    #define  CRONCPP_STRING_VIEW_NPOS  std::string::npos | ||||||
|  |    #define  CRONCPP_CONSTEXPTR | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |    using cron_int  = uint8_t; | ||||||
|  |  | ||||||
|  |    constexpr std::time_t INVALID_TIME = static_cast<std::time_t>(-1); | ||||||
|  |  | ||||||
|  |    constexpr size_t INVALID_INDEX = static_cast<size_t>(-1); | ||||||
|  |  | ||||||
|  |    class cronexpr; | ||||||
|  |  | ||||||
|  |    namespace detail | ||||||
|  |    { | ||||||
|  |       enum class cron_field | ||||||
|  |       { | ||||||
|  |          second, | ||||||
|  |          minute, | ||||||
|  |          hour_of_day, | ||||||
|  |          day_of_week, | ||||||
|  |          day_of_month, | ||||||
|  |          month, | ||||||
|  |          year | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       static bool find_next(cronexpr const & cex, | ||||||
|  |                             std::tm& date, | ||||||
|  |                             size_t const dot); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    struct bad_cronexpr : public std::runtime_error | ||||||
|  |    { | ||||||
|  |    public: | ||||||
|  |       explicit bad_cronexpr(CRONCPP_STRING_VIEW message) : | ||||||
|  |          std::runtime_error(message.data()) | ||||||
|  |       {} | ||||||
|  |    }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    struct cron_standard_traits | ||||||
|  |    { | ||||||
|  |       static const cron_int CRON_MIN_SECONDS = 0; | ||||||
|  |       static const cron_int CRON_MAX_SECONDS = 59; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_MINUTES = 0; | ||||||
|  |       static const cron_int CRON_MAX_MINUTES = 59; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_HOURS = 0; | ||||||
|  |       static const cron_int CRON_MAX_HOURS = 23; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_DAYS_OF_WEEK = 0; | ||||||
|  |       static const cron_int CRON_MAX_DAYS_OF_WEEK = 6; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_DAYS_OF_MONTH = 1; | ||||||
|  |       static const cron_int CRON_MAX_DAYS_OF_MONTH = 31; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_MONTHS = 1; | ||||||
|  |       static const cron_int CRON_MAX_MONTHS = 12; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MAX_YEARS_DIFF = 4; | ||||||
|  |  | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |       static const inline std::vector<std::string> DAYS = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; | ||||||
|  |       static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; | ||||||
|  | #else | ||||||
|  |       static std::vector<std::string>& DAYS() | ||||||
|  |       { | ||||||
|  |          static std::vector<std::string> days = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; | ||||||
|  |          return days; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static std::vector<std::string>& MONTHS() | ||||||
|  |       { | ||||||
|  |          static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; | ||||||
|  |          return months; | ||||||
|  |       } | ||||||
|  | #endif | ||||||
|  |    }; | ||||||
|  |  | ||||||
|  |    struct cron_oracle_traits | ||||||
|  |    { | ||||||
|  |       static const cron_int CRON_MIN_SECONDS = 0; | ||||||
|  |       static const cron_int CRON_MAX_SECONDS = 59; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_MINUTES = 0; | ||||||
|  |       static const cron_int CRON_MAX_MINUTES = 59; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_HOURS = 0; | ||||||
|  |       static const cron_int CRON_MAX_HOURS = 23; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_DAYS_OF_WEEK = 1; | ||||||
|  |       static const cron_int CRON_MAX_DAYS_OF_WEEK = 7; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_DAYS_OF_MONTH = 1; | ||||||
|  |       static const cron_int CRON_MAX_DAYS_OF_MONTH = 31; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_MONTHS = 0; | ||||||
|  |       static const cron_int CRON_MAX_MONTHS = 11; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MAX_YEARS_DIFF = 4; | ||||||
|  |  | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |       static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; | ||||||
|  |       static const inline std::vector<std::string> MONTHS = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; | ||||||
|  | #else | ||||||
|  |  | ||||||
|  |       static std::vector<std::string>& DAYS() | ||||||
|  |       { | ||||||
|  |          static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; | ||||||
|  |          return days; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static std::vector<std::string>& MONTHS() | ||||||
|  |       { | ||||||
|  |          static std::vector<std::string> months = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; | ||||||
|  |          return months; | ||||||
|  |       } | ||||||
|  | #endif | ||||||
|  |    }; | ||||||
|  |  | ||||||
|  |    struct cron_quartz_traits | ||||||
|  |    { | ||||||
|  |       static const cron_int CRON_MIN_SECONDS = 0; | ||||||
|  |       static const cron_int CRON_MAX_SECONDS = 59; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_MINUTES = 0; | ||||||
|  |       static const cron_int CRON_MAX_MINUTES = 59; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_HOURS = 0; | ||||||
|  |       static const cron_int CRON_MAX_HOURS = 23; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_DAYS_OF_WEEK = 1; | ||||||
|  |       static const cron_int CRON_MAX_DAYS_OF_WEEK = 7; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_DAYS_OF_MONTH = 1; | ||||||
|  |       static const cron_int CRON_MAX_DAYS_OF_MONTH = 31; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MIN_MONTHS = 1; | ||||||
|  |       static const cron_int CRON_MAX_MONTHS = 12; | ||||||
|  |  | ||||||
|  |       static const cron_int CRON_MAX_YEARS_DIFF = 4; | ||||||
|  |  | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |       static const inline std::vector<std::string> DAYS = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; | ||||||
|  |       static const inline std::vector<std::string> MONTHS = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; | ||||||
|  | #else | ||||||
|  |       static std::vector<std::string>& DAYS() | ||||||
|  |       { | ||||||
|  |          static std::vector<std::string> days = { "NIL", "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" }; | ||||||
|  |          return days; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static std::vector<std::string>& MONTHS() | ||||||
|  |       { | ||||||
|  |          static std::vector<std::string> months = { "NIL", "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" }; | ||||||
|  |          return months; | ||||||
|  |       } | ||||||
|  | #endif | ||||||
|  |    }; | ||||||
|  |  | ||||||
|  |    class cronexpr; | ||||||
|  |  | ||||||
|  |    template <typename Traits = cron_standard_traits> | ||||||
|  |    static cronexpr make_cron(CRONCPP_STRING_VIEW expr); | ||||||
|  |  | ||||||
|  |    class cronexpr | ||||||
|  |    { | ||||||
|  |       std::bitset<60> seconds; | ||||||
|  |       std::bitset<60> minutes; | ||||||
|  |       std::bitset<24> hours; | ||||||
|  |       std::bitset<7>  days_of_week; | ||||||
|  |       std::bitset<31> days_of_month; | ||||||
|  |       std::bitset<12> months; | ||||||
|  |       std::string     expr; | ||||||
|  |  | ||||||
|  |       friend bool operator==(cronexpr const & e1, cronexpr const & e2); | ||||||
|  |       friend bool operator!=(cronexpr const & e1, cronexpr const & e2); | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       friend bool detail::find_next(cronexpr const & cex, | ||||||
|  |                                     std::tm& date, | ||||||
|  |                                     size_t const dot); | ||||||
|  |  | ||||||
|  |       friend std::string to_cronstr(cronexpr const& cex); | ||||||
|  |       friend std::string to_string(cronexpr const & cex); | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       friend cronexpr make_cron(CRONCPP_STRING_VIEW expr); | ||||||
|  |    }; | ||||||
|  |  | ||||||
|  |    inline bool operator==(cronexpr const & e1, cronexpr const & e2) | ||||||
|  |    { | ||||||
|  |       return | ||||||
|  |          e1.seconds == e2.seconds && | ||||||
|  |          e1.minutes == e2.minutes && | ||||||
|  |          e1.hours == e2.hours && | ||||||
|  |          e1.days_of_week == e2.days_of_week && | ||||||
|  |          e1.days_of_month == e2.days_of_month && | ||||||
|  |          e1.months == e2.months; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    inline bool operator!=(cronexpr const & e1, cronexpr const & e2) | ||||||
|  |    { | ||||||
|  |       return !(e1 == e2); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    inline std::string to_string(cronexpr const & cex) | ||||||
|  |    { | ||||||
|  |       return | ||||||
|  |          cex.seconds.to_string() + " " + | ||||||
|  |          cex.minutes.to_string() + " " + | ||||||
|  |          cex.hours.to_string() + " " + | ||||||
|  |          cex.days_of_month.to_string() + " " + | ||||||
|  |          cex.months.to_string() + " " + | ||||||
|  |          cex.days_of_week.to_string(); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    inline std::string to_cronstr(cronexpr const& cex) | ||||||
|  |    { | ||||||
|  |       return cex.expr; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    namespace utils | ||||||
|  |    { | ||||||
|  |       inline std::time_t tm_to_time(std::tm& date) | ||||||
|  |       { | ||||||
|  |          return std::mktime(&date); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline std::tm* time_to_tm(std::time_t const * date, std::tm* const out) | ||||||
|  |       { | ||||||
|  | #ifdef _WIN32 | ||||||
|  |          errno_t err = localtime_s(out, date); | ||||||
|  |          return 0 == err ? out : nullptr; | ||||||
|  | #else | ||||||
|  |          return localtime_r(date, out); | ||||||
|  | #endif | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline std::tm to_tm(CRONCPP_STRING_VIEW time) | ||||||
|  |       { | ||||||
|  |          std::tm result; | ||||||
|  | #if __cplusplus > 201103L | ||||||
|  |          std::istringstream str(time.data()); | ||||||
|  |          str.imbue(std::locale(setlocale(LC_ALL, nullptr))); | ||||||
|  |  | ||||||
|  |          str >> std::get_time(&result, "%Y-%m-%d %H:%M:%S"); | ||||||
|  |          if (str.fail()) throw std::runtime_error("Parsing date failed!"); | ||||||
|  | #else | ||||||
|  |          int year = 1900; | ||||||
|  |          int month = 1; | ||||||
|  |          int day = 1; | ||||||
|  |          int hour = 0; | ||||||
|  |          int minute = 0; | ||||||
|  |          int second = 0; | ||||||
|  |          sscanf(time.data(), "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second); | ||||||
|  |          result.tm_year = year - 1900; | ||||||
|  |          result.tm_mon = month - 1; | ||||||
|  |          result.tm_mday = day; | ||||||
|  |          result.tm_hour = hour; | ||||||
|  |          result.tm_min = minute; | ||||||
|  |          result.tm_sec = second; | ||||||
|  | #endif | ||||||
|  |          result.tm_isdst = -1; // DST info not available | ||||||
|  |  | ||||||
|  |          return result; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline std::string to_string(std::tm const & tm) | ||||||
|  |       { | ||||||
|  | #if __cplusplus > 201103L | ||||||
|  |          std::ostringstream str; | ||||||
|  |          str.imbue(std::locale(setlocale(LC_ALL, nullptr))); | ||||||
|  |          str << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); | ||||||
|  |          if (str.fail()) throw std::runtime_error("Writing date failed!"); | ||||||
|  |  | ||||||
|  |          return str.str(); | ||||||
|  | #else | ||||||
|  |          char buff[70] = {0}; | ||||||
|  |          strftime(buff, sizeof(buff), "%Y-%m-%d %H:%M:%S", &tm); | ||||||
|  |          return std::string(buff); | ||||||
|  | #endif | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline std::string to_upper(std::string text) | ||||||
|  |       { | ||||||
|  |          std::transform(std::begin(text), std::end(text), | ||||||
|  |             std::begin(text), [](char const c) { return static_cast<char>(std::toupper(c)); }); | ||||||
|  |  | ||||||
|  |          return text; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static std::vector<std::string> split(CRONCPP_STRING_VIEW text, char const delimiter) | ||||||
|  |       { | ||||||
|  |          std::vector<std::string> tokens; | ||||||
|  |          std::string token; | ||||||
|  |          std::istringstream tokenStream(text.data()); | ||||||
|  |          while (std::getline(tokenStream, token, delimiter)) | ||||||
|  |          { | ||||||
|  |             tokens.push_back(token); | ||||||
|  |          } | ||||||
|  |          return tokens; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       CRONCPP_CONSTEXPTR inline bool contains(CRONCPP_STRING_VIEW text, char const ch) noexcept | ||||||
|  |       { | ||||||
|  |          return CRONCPP_STRING_VIEW_NPOS != text.find_first_of(ch); | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    namespace detail | ||||||
|  |    { | ||||||
|  |  | ||||||
|  |       inline cron_int to_cron_int(CRONCPP_STRING_VIEW text) | ||||||
|  |       { | ||||||
|  |          try | ||||||
|  |          { | ||||||
|  |             return static_cast<cron_int>(std::stoul(text.data())); | ||||||
|  |          } | ||||||
|  |          catch (std::exception const & ex) | ||||||
|  |          { | ||||||
|  |             throw bad_cronexpr(ex.what()); | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static std::string replace_ordinals( | ||||||
|  |          std::string text, | ||||||
|  |          std::vector<std::string> const & replacement) | ||||||
|  |       { | ||||||
|  |          for (size_t i = 0; i < replacement.size(); ++i) | ||||||
|  |          { | ||||||
|  |             auto pos = text.find(replacement[i]); | ||||||
|  |             if (std::string::npos != pos) | ||||||
|  |                text.replace(pos, 3 ,std::to_string(i)); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          return text; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       static std::pair<cron_int, cron_int> make_range( | ||||||
|  |          CRONCPP_STRING_VIEW field, | ||||||
|  |          cron_int const minval, | ||||||
|  |          cron_int const maxval) | ||||||
|  |       { | ||||||
|  |          cron_int first = 0; | ||||||
|  |          cron_int last = 0; | ||||||
|  |          if (field.size() == 1 && field[0] == '*') | ||||||
|  |          { | ||||||
|  |             first = minval; | ||||||
|  |             last = maxval; | ||||||
|  |          } | ||||||
|  |          else if (!utils::contains(field, '-')) | ||||||
|  |          { | ||||||
|  |             first = to_cron_int(field); | ||||||
|  |             last = first; | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             auto parts = utils::split(field, '-'); | ||||||
|  |             if (parts.size() != 2) | ||||||
|  |                throw bad_cronexpr("Specified range requires two fields"); | ||||||
|  |  | ||||||
|  |             first = to_cron_int(parts[0]); | ||||||
|  |             last = to_cron_int(parts[1]); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          if (first > maxval || last > maxval) | ||||||
|  |          { | ||||||
|  |             throw bad_cronexpr("Specified range exceeds maximum"); | ||||||
|  |          } | ||||||
|  |          if (first < minval || last < minval) | ||||||
|  |          { | ||||||
|  |             throw bad_cronexpr("Specified range is less than minimum"); | ||||||
|  |          } | ||||||
|  |          if (first > last) | ||||||
|  |          { | ||||||
|  |             throw bad_cronexpr("Specified range start exceeds range end"); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          return { first, last }; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <size_t N> | ||||||
|  |       static void set_cron_field( | ||||||
|  |          CRONCPP_STRING_VIEW value, | ||||||
|  |          std::bitset<N>& target, | ||||||
|  |          cron_int const minval, | ||||||
|  |          cron_int const maxval) | ||||||
|  |       { | ||||||
|  |          if(value.length() > 0 && value[value.length()-1] == ',') | ||||||
|  |             throw bad_cronexpr("Value cannot end with comma"); | ||||||
|  |  | ||||||
|  |          auto fields = utils::split(value, ','); | ||||||
|  |          if (fields.empty()) | ||||||
|  |             throw bad_cronexpr("Expression parsing error"); | ||||||
|  |  | ||||||
|  |          for (auto const & field : fields) | ||||||
|  |          { | ||||||
|  |             if (!utils::contains(field, '/')) | ||||||
|  |             { | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |                auto[first, last] = detail::make_range(field, minval, maxval); | ||||||
|  | #else | ||||||
|  |                auto range = detail::make_range(field, minval, maxval); | ||||||
|  |                auto first = range.first; | ||||||
|  |                auto last = range.second; | ||||||
|  | #endif | ||||||
|  |                for (cron_int i = first - minval; i <= last - minval; ++i) | ||||||
|  |                { | ||||||
|  |                   target.set(i); | ||||||
|  |                } | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                auto parts = utils::split(field, '/'); | ||||||
|  |                if (parts.size() != 2) | ||||||
|  |                   throw bad_cronexpr("Incrementer must have two fields"); | ||||||
|  |  | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |                auto[first, last] = detail::make_range(parts[0], minval, maxval); | ||||||
|  | #else | ||||||
|  |                auto range = detail::make_range(parts[0], minval, maxval); | ||||||
|  |                auto first = range.first; | ||||||
|  |                auto last = range.second; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |                if (!utils::contains(parts[0], '-')) | ||||||
|  |                { | ||||||
|  |                   last = maxval; | ||||||
|  |                } | ||||||
|  |  | ||||||
|  |                auto delta = detail::to_cron_int(parts[1]); | ||||||
|  |                if(delta <= 0) | ||||||
|  |                   throw bad_cronexpr("Incrementer must be a positive value"); | ||||||
|  |  | ||||||
|  |                for (cron_int i = first - minval; i <= last - minval; i += delta) | ||||||
|  |                { | ||||||
|  |                   target.set(i); | ||||||
|  |                } | ||||||
|  |             } | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       static void set_cron_days_of_week( | ||||||
|  |          std::string value, | ||||||
|  |          std::bitset<7>& target) | ||||||
|  |       { | ||||||
|  |          auto days = utils::to_upper(value); | ||||||
|  |          auto days_replaced = detail::replace_ordinals( | ||||||
|  |             days, | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |             Traits::DAYS | ||||||
|  | #else | ||||||
|  |             Traits::DAYS() | ||||||
|  | #endif | ||||||
|  |          ); | ||||||
|  |  | ||||||
|  |          if (days_replaced.size() == 1 && days_replaced[0] == '?') | ||||||
|  |             days_replaced[0] = '*'; | ||||||
|  |  | ||||||
|  |          set_cron_field( | ||||||
|  |             days_replaced, | ||||||
|  |             target, | ||||||
|  |             Traits::CRON_MIN_DAYS_OF_WEEK, | ||||||
|  |             Traits::CRON_MAX_DAYS_OF_WEEK); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       static void set_cron_days_of_month( | ||||||
|  |          std::string value, | ||||||
|  |          std::bitset<31>& target) | ||||||
|  |       { | ||||||
|  |          if (value.size() == 1 && value[0] == '?') | ||||||
|  |             value[0] = '*'; | ||||||
|  |  | ||||||
|  |          set_cron_field( | ||||||
|  |             value, | ||||||
|  |             target, | ||||||
|  |             Traits::CRON_MIN_DAYS_OF_MONTH, | ||||||
|  |             Traits::CRON_MAX_DAYS_OF_MONTH); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       static void set_cron_month( | ||||||
|  |          std::string value, | ||||||
|  |          std::bitset<12>& target) | ||||||
|  |       { | ||||||
|  |          auto month = utils::to_upper(value); | ||||||
|  |          auto month_replaced = replace_ordinals( | ||||||
|  |             month, | ||||||
|  | #ifdef CRONCPP_IS_CPP17 | ||||||
|  |             Traits::MONTHS | ||||||
|  | #else | ||||||
|  |             Traits::MONTHS() | ||||||
|  | #endif | ||||||
|  |          ); | ||||||
|  |  | ||||||
|  |          set_cron_field( | ||||||
|  |             month_replaced, | ||||||
|  |             target, | ||||||
|  |             Traits::CRON_MIN_MONTHS, | ||||||
|  |             Traits::CRON_MAX_MONTHS); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <size_t N> | ||||||
|  |       inline size_t next_set_bit( | ||||||
|  |          std::bitset<N> const & target, | ||||||
|  |          size_t /*minimum*/, | ||||||
|  |          size_t /*maximum*/, | ||||||
|  |          size_t offset) | ||||||
|  |       { | ||||||
|  |          for (auto i = offset; i < N; ++i) | ||||||
|  |          { | ||||||
|  |             if (target.test(i)) return i; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          return INVALID_INDEX; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline void add_to_field( | ||||||
|  |          std::tm& date, | ||||||
|  |          cron_field const field, | ||||||
|  |          int const val) | ||||||
|  |       { | ||||||
|  |          switch (field) | ||||||
|  |          { | ||||||
|  |          case cron_field::second: | ||||||
|  |             date.tm_sec += val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::minute: | ||||||
|  |             date.tm_min += val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::hour_of_day: | ||||||
|  |             date.tm_hour += val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::day_of_week: | ||||||
|  |          case cron_field::day_of_month: | ||||||
|  |             date.tm_mday += val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::month: | ||||||
|  |             date.tm_mon += val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::year: | ||||||
|  |             date.tm_year += val; | ||||||
|  |             break; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          if (INVALID_TIME == utils::tm_to_time(date)) | ||||||
|  |             throw bad_cronexpr("Invalid time expression"); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline void set_field( | ||||||
|  |          std::tm& date, | ||||||
|  |          cron_field const field, | ||||||
|  |          int const val) | ||||||
|  |       { | ||||||
|  |          switch (field) | ||||||
|  |          { | ||||||
|  |          case cron_field::second: | ||||||
|  |             date.tm_sec = val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::minute: | ||||||
|  |             date.tm_min = val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::hour_of_day: | ||||||
|  |             date.tm_hour = val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::day_of_week: | ||||||
|  |             date.tm_wday = val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::day_of_month: | ||||||
|  |             date.tm_mday = val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::month: | ||||||
|  |             date.tm_mon = val; | ||||||
|  |             break; | ||||||
|  |          case cron_field::year: | ||||||
|  |             date.tm_year = val; | ||||||
|  |             break; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          if (INVALID_TIME == utils::tm_to_time(date)) | ||||||
|  |             throw bad_cronexpr("Invalid time expression"); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline void reset_field( | ||||||
|  |          std::tm& date, | ||||||
|  |          cron_field const field) | ||||||
|  |       { | ||||||
|  |          switch (field) | ||||||
|  |          { | ||||||
|  |          case cron_field::second: | ||||||
|  |             date.tm_sec = 0; | ||||||
|  |             break; | ||||||
|  |          case cron_field::minute: | ||||||
|  |             date.tm_min = 0; | ||||||
|  |             break; | ||||||
|  |          case cron_field::hour_of_day: | ||||||
|  |             date.tm_hour = 0; | ||||||
|  |             break; | ||||||
|  |          case cron_field::day_of_week: | ||||||
|  |             date.tm_wday = 0; | ||||||
|  |             break; | ||||||
|  |          case cron_field::day_of_month: | ||||||
|  |             date.tm_mday = 1; | ||||||
|  |             break; | ||||||
|  |          case cron_field::month: | ||||||
|  |             date.tm_mon = 0; | ||||||
|  |             break; | ||||||
|  |          case cron_field::year: | ||||||
|  |             date.tm_year = 0; | ||||||
|  |             break; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          if (INVALID_TIME == utils::tm_to_time(date)) | ||||||
|  |             throw bad_cronexpr("Invalid time expression"); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline void reset_all_fields( | ||||||
|  |          std::tm& date, | ||||||
|  |          std::bitset<7> const & marked_fields) | ||||||
|  |       { | ||||||
|  |          for (size_t i = 0; i < marked_fields.size(); ++i) | ||||||
|  |          { | ||||||
|  |             if (marked_fields.test(i)) | ||||||
|  |                reset_field(date, static_cast<cron_field>(i)); | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       inline void mark_field( | ||||||
|  |          std::bitset<7> & orders, | ||||||
|  |          cron_field const field) | ||||||
|  |       { | ||||||
|  |          if (!orders.test(static_cast<size_t>(field))) | ||||||
|  |             orders.set(static_cast<size_t>(field)); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <size_t N> | ||||||
|  |       static size_t find_next( | ||||||
|  |          std::bitset<N> const & target, | ||||||
|  |          std::tm& date, | ||||||
|  |          unsigned int const minimum, | ||||||
|  |          unsigned int const maximum, | ||||||
|  |          unsigned int const value, | ||||||
|  |          cron_field const field, | ||||||
|  |          cron_field const next_field, | ||||||
|  |          std::bitset<7> const & marked_fields) | ||||||
|  |       { | ||||||
|  |          auto next_value = next_set_bit(target, minimum, maximum, value); | ||||||
|  |          if (INVALID_INDEX == next_value) | ||||||
|  |          { | ||||||
|  |             add_to_field(date, next_field, 1); | ||||||
|  |             reset_field(date, field); | ||||||
|  |             next_value = next_set_bit(target, minimum, maximum, 0); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          if (INVALID_INDEX == next_value || next_value != value) | ||||||
|  |          { | ||||||
|  |             set_field(date, field, static_cast<int>(next_value)); | ||||||
|  |             reset_all_fields(date, marked_fields); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          return next_value; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       static size_t find_next_day( | ||||||
|  |          std::tm& date, | ||||||
|  |          std::bitset<31> const & days_of_month, | ||||||
|  |          size_t day_of_month, | ||||||
|  |          std::bitset<7> const & days_of_week, | ||||||
|  |          size_t day_of_week, | ||||||
|  |          std::bitset<7> const & marked_fields) | ||||||
|  |       { | ||||||
|  |          unsigned int count = 0; | ||||||
|  |          unsigned int maximum = 366; | ||||||
|  |          while ( | ||||||
|  |             (!days_of_month.test(day_of_month - Traits::CRON_MIN_DAYS_OF_MONTH) || | ||||||
|  |             !days_of_week.test(day_of_week - Traits::CRON_MIN_DAYS_OF_WEEK)) | ||||||
|  |             && count++ < maximum) | ||||||
|  |          { | ||||||
|  |             add_to_field(date, cron_field::day_of_month, 1); | ||||||
|  |  | ||||||
|  |             day_of_month = date.tm_mday; | ||||||
|  |             day_of_week = date.tm_wday; | ||||||
|  |  | ||||||
|  |             reset_all_fields(date, marked_fields); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          return day_of_month; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       template <typename Traits> | ||||||
|  |       static bool find_next(cronexpr const & cex, | ||||||
|  |                             std::tm& date, | ||||||
|  |                             size_t const dot) | ||||||
|  |       { | ||||||
|  |          bool res = true; | ||||||
|  |  | ||||||
|  |          std::bitset<7> marked_fields{ 0 }; | ||||||
|  |          std::bitset<7> empty_list{ 0 }; | ||||||
|  |  | ||||||
|  |          unsigned int second = date.tm_sec; | ||||||
|  |          auto updated_second = find_next( | ||||||
|  |             cex.seconds, | ||||||
|  |             date, | ||||||
|  |             Traits::CRON_MIN_SECONDS, | ||||||
|  |             Traits::CRON_MAX_SECONDS, | ||||||
|  |             second, | ||||||
|  |             cron_field::second, | ||||||
|  |             cron_field::minute, | ||||||
|  |             empty_list); | ||||||
|  |  | ||||||
|  |          if (second == updated_second) | ||||||
|  |          { | ||||||
|  |             mark_field(marked_fields, cron_field::second); | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          unsigned int minute = date.tm_min; | ||||||
|  |          auto update_minute = find_next( | ||||||
|  |             cex.minutes, | ||||||
|  |             date, | ||||||
|  |             Traits::CRON_MIN_MINUTES, | ||||||
|  |             Traits::CRON_MAX_MINUTES, | ||||||
|  |             minute, | ||||||
|  |             cron_field::minute, | ||||||
|  |             cron_field::hour_of_day, | ||||||
|  |             marked_fields); | ||||||
|  |          if (minute == update_minute) | ||||||
|  |          { | ||||||
|  |             mark_field(marked_fields, cron_field::minute); | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             res = find_next<Traits>(cex, date, dot); | ||||||
|  |             if (!res) return res; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          unsigned int hour = date.tm_hour; | ||||||
|  |          auto updated_hour = find_next( | ||||||
|  |             cex.hours, | ||||||
|  |             date, | ||||||
|  |             Traits::CRON_MIN_HOURS, | ||||||
|  |             Traits::CRON_MAX_HOURS, | ||||||
|  |             hour, | ||||||
|  |             cron_field::hour_of_day, | ||||||
|  |             cron_field::day_of_week, | ||||||
|  |             marked_fields); | ||||||
|  |          if (hour == updated_hour) | ||||||
|  |          { | ||||||
|  |             mark_field(marked_fields, cron_field::hour_of_day); | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             res = find_next<Traits>(cex, date, dot); | ||||||
|  |             if (!res) return res; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          unsigned int day_of_week = date.tm_wday; | ||||||
|  |          unsigned int day_of_month = date.tm_mday; | ||||||
|  |          auto updated_day_of_month = find_next_day<Traits>( | ||||||
|  |             date, | ||||||
|  |             cex.days_of_month, | ||||||
|  |             day_of_month, | ||||||
|  |             cex.days_of_week, | ||||||
|  |             day_of_week, | ||||||
|  |             marked_fields); | ||||||
|  |          if (day_of_month == updated_day_of_month) | ||||||
|  |          { | ||||||
|  |             mark_field(marked_fields, cron_field::day_of_month); | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |          { | ||||||
|  |             res = find_next<Traits>(cex, date, dot); | ||||||
|  |             if (!res) return res; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          unsigned int month = date.tm_mon; | ||||||
|  |          auto updated_month = find_next( | ||||||
|  |             cex.months, | ||||||
|  |             date, | ||||||
|  |             Traits::CRON_MIN_MONTHS, | ||||||
|  |             Traits::CRON_MAX_MONTHS, | ||||||
|  |             month, | ||||||
|  |             cron_field::month, | ||||||
|  |             cron_field::year, | ||||||
|  |             marked_fields); | ||||||
|  |          if (month != updated_month) | ||||||
|  |          { | ||||||
|  |             if (date.tm_year - dot > Traits::CRON_MAX_YEARS_DIFF) | ||||||
|  |                return false; | ||||||
|  |  | ||||||
|  |             res = find_next<Traits>(cex, date, dot); | ||||||
|  |             if (!res) return res; | ||||||
|  |          } | ||||||
|  |  | ||||||
|  |          return res; | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    template <typename Traits> | ||||||
|  |    static cronexpr make_cron(CRONCPP_STRING_VIEW expr) | ||||||
|  |    { | ||||||
|  |       cronexpr cex; | ||||||
|  |  | ||||||
|  |       if (expr.empty()) | ||||||
|  |          throw bad_cronexpr("Invalid empty cron expression"); | ||||||
|  |  | ||||||
|  |       auto fields = utils::split(expr, ' '); | ||||||
|  |       fields.erase( | ||||||
|  |          std::remove_if(std::begin(fields), std::end(fields), | ||||||
|  |             [](CRONCPP_STRING_VIEW s) {return s.empty(); }), | ||||||
|  |          std::end(fields)); | ||||||
|  |       if (fields.size() != 6) | ||||||
|  |          throw bad_cronexpr("cron expression must have six fields"); | ||||||
|  |  | ||||||
|  |       detail::set_cron_field(fields[0], cex.seconds, Traits::CRON_MIN_SECONDS, Traits::CRON_MAX_SECONDS); | ||||||
|  |       detail::set_cron_field(fields[1], cex.minutes, Traits::CRON_MIN_MINUTES, Traits::CRON_MAX_MINUTES); | ||||||
|  |       detail::set_cron_field(fields[2], cex.hours, Traits::CRON_MIN_HOURS, Traits::CRON_MAX_HOURS); | ||||||
|  |  | ||||||
|  |       detail::set_cron_days_of_week<Traits>(fields[5], cex.days_of_week); | ||||||
|  |  | ||||||
|  |       detail::set_cron_days_of_month<Traits>(fields[3], cex.days_of_month); | ||||||
|  |  | ||||||
|  |       detail::set_cron_month<Traits>(fields[4], cex.months); | ||||||
|  |  | ||||||
|  |       cex.expr = expr; | ||||||
|  |  | ||||||
|  |       return cex; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    template <typename Traits = cron_standard_traits> | ||||||
|  |    static std::tm cron_next(cronexpr const & cex, std::tm date) | ||||||
|  |    { | ||||||
|  |       time_t original = utils::tm_to_time(date); | ||||||
|  |       if (INVALID_TIME == original) return {}; | ||||||
|  |  | ||||||
|  |       if (!detail::find_next<Traits>(cex, date, date.tm_year)) | ||||||
|  |          return {}; | ||||||
|  |  | ||||||
|  |       time_t calculated = utils::tm_to_time(date); | ||||||
|  |       if (INVALID_TIME == calculated) return {}; | ||||||
|  |  | ||||||
|  |       if (calculated == original) | ||||||
|  |       { | ||||||
|  |          add_to_field(date, detail::cron_field::second, 1); | ||||||
|  |          if (!detail::find_next<Traits>(cex, date, date.tm_year)) | ||||||
|  |             return {}; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return date; | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |    template <typename Traits = cron_standard_traits> | ||||||
|  |    static std::time_t cron_next(cronexpr const & cex, std::time_t const & date) | ||||||
|  |    { | ||||||
|  |       std::tm val; | ||||||
|  |       std::tm* dt = utils::time_to_tm(&date, &val); | ||||||
|  |       if (dt == nullptr) return INVALID_TIME; | ||||||
|  |  | ||||||
|  |       time_t original = utils::tm_to_time(*dt); | ||||||
|  |       if (INVALID_TIME == original) return INVALID_TIME; | ||||||
|  |  | ||||||
|  |       if(!detail::find_next<Traits>(cex, *dt, dt->tm_year)) | ||||||
|  |          return INVALID_TIME; | ||||||
|  |  | ||||||
|  |       time_t calculated = utils::tm_to_time(*dt); | ||||||
|  |       if (INVALID_TIME == calculated) return calculated; | ||||||
|  |  | ||||||
|  |       if (calculated == original) | ||||||
|  |       { | ||||||
|  |          add_to_field(*dt, detail::cron_field::second, 1); | ||||||
|  |          if(!detail::find_next<Traits>(cex, *dt, dt->tm_year)) | ||||||
|  |             return INVALID_TIME; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return utils::tm_to_time(*dt); | ||||||
|  |    } | ||||||
|  |  | ||||||
|  |   template <typename Traits = cron_standard_traits> | ||||||
|  |   static std::chrono::system_clock::time_point cron_next(cronexpr const & cex, std::chrono::system_clock::time_point const & time_point) { | ||||||
|  |      return std::chrono::system_clock::from_time_t(cron_next<Traits>(cex, std::chrono::system_clock::to_time_t(time_point))); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										13
									
								
								src/ow_version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/ow_version.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | // | ||||||
|  | // Created by stephane bourque on 2021-12-06. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | namespace OW_VERSION { | ||||||
|  |     inline static const std::string VERSION{"2.6.0"}; | ||||||
|  |     inline static const std::string BUILD{"128"}; | ||||||
|  |     inline static const std::string HASH{"3b0f2a0"}; | ||||||
|  | } | ||||||
| @@ -96,40 +96,42 @@ namespace OpenWifi { | |||||||
|     void EntityDB::AddVenues(Poco::JSON::Object &Tree, const std::string & Node) { |     void EntityDB::AddVenues(Poco::JSON::Object &Tree, const std::string & Node) { | ||||||
|         ProvObjects::Venue E; |         ProvObjects::Venue E; | ||||||
|         // std::cout << "Adding venue:" << Node << std::endl; |         // std::cout << "Adding venue:" << Node << std::endl; | ||||||
|         StorageService()->VenueDB().GetRecord("id",Node,E); |         if(StorageService()->VenueDB().GetRecord("id",Node,E)) { | ||||||
|         Poco::JSON::Array   Venues; |             Poco::JSON::Array Venues; | ||||||
|         for(const auto &i:E.children) { |             for (const auto &i: E.children) { | ||||||
|             Poco::JSON::Object Venue; |                 Poco::JSON::Object Venue; | ||||||
|             AddVenues(Venue, i); |                 AddVenues(Venue, i); | ||||||
|             Venues.add(Venue); |                 Venues.add(Venue); | ||||||
|  |             } | ||||||
|  |             Tree.set("type", "venue"); | ||||||
|  |             Tree.set("name", E.info.name); | ||||||
|  |             Tree.set("uuid", E.info.id); | ||||||
|  |             Tree.set("children", Venues); | ||||||
|         } |         } | ||||||
|         Tree.set("type","venue"); |  | ||||||
|         Tree.set("name",E.info.name); |  | ||||||
|         Tree.set("uuid",E.info.id); |  | ||||||
|         Tree.set("children",Venues); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void EntityDB::BuildTree(Poco::JSON::Object &Tree, const std::string & Node) { |     void EntityDB::BuildTree(Poco::JSON::Object &Tree, const std::string & Node) { | ||||||
|         ProvObjects::Entity E; |         ProvObjects::Entity E; | ||||||
|         // std::cout << "Adding node:" << Node << std::endl; |         // std::cout << "Adding node:" << Node << std::endl; | ||||||
|         StorageService()->EntityDB().GetRecord("id",Node,E); |         if(StorageService()->EntityDB().GetRecord("id",Node,E)) { | ||||||
|         Poco::JSON::Array   Children; |             Poco::JSON::Array Children; | ||||||
|         for(const auto &i:E.children) { |             for (const auto &i: E.children) { | ||||||
|             Poco::JSON::Object  Child; |                 Poco::JSON::Object Child; | ||||||
|             BuildTree(Child,i); |                 BuildTree(Child, i); | ||||||
|             Children.add(Child); |                 Children.add(Child); | ||||||
|  |             } | ||||||
|  |             Poco::JSON::Array Venues; | ||||||
|  |             for (const auto &i: E.venues) { | ||||||
|  |                 Poco::JSON::Object Venue; | ||||||
|  |                 AddVenues(Venue, i); | ||||||
|  |                 Venues.add(Venue); | ||||||
|  |             } | ||||||
|  |             Tree.set("type", "entity"); | ||||||
|  |             Tree.set("name", E.info.name); | ||||||
|  |             Tree.set("uuid", E.info.id); | ||||||
|  |             Tree.set("children", Children); | ||||||
|  |             Tree.set("venues", Venues); | ||||||
|         } |         } | ||||||
|         Poco::JSON::Array   Venues; |  | ||||||
|         for(const auto &i:E.venues) { |  | ||||||
|             Poco::JSON::Object Venue; |  | ||||||
|             AddVenues(Venue, i); |  | ||||||
|             Venues.add(Venue); |  | ||||||
|         } |  | ||||||
|         Tree.set("type","entity"); |  | ||||||
|         Tree.set("name",E.info.name); |  | ||||||
|         Tree.set("uuid",E.info.id); |  | ||||||
|         Tree.set("children",Children); |  | ||||||
|         Tree.set("venues", Venues); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void EntityDB::ImportVenues(const Poco::JSON::Object::Ptr &O, const std::string &Parent) { |     void EntityDB::ImportVenues(const Poco::JSON::Object::Ptr &O, const std::string &Parent) { | ||||||
|   | |||||||
| @@ -83,12 +83,13 @@ namespace OpenWifi { | |||||||
|     InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : |     InventoryDB::InventoryDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : | ||||||
|         DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {} |         DB(T, "inventory", InventoryDB_Fields, InventoryDB_Indexes, P, L, "inv") {} | ||||||
|  |  | ||||||
|     bool InventoryDB::CreateFromConnection( const std::string &SerialNumber, |     bool InventoryDB::CreateFromConnection( const std::string &SerialNumberRaw, | ||||||
|                                             const std::string &ConnectionInfo, |                                             const std::string &ConnectionInfo, | ||||||
|                                             const std::string &DeviceType, |                                             const std::string &DeviceType, | ||||||
|                                             const std::string &Locale) { |                                             const std::string &Locale) { | ||||||
|  |  | ||||||
|         ProvObjects::InventoryTag   ExistingDevice; |         ProvObjects::InventoryTag   ExistingDevice; | ||||||
|  |         auto SerialNumber = Poco::toLower(SerialNumberRaw); | ||||||
|         if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) { |         if(!GetRecord("serialNumber",SerialNumber,ExistingDevice)) { | ||||||
|             ProvObjects::InventoryTag   NewDevice; |             ProvObjects::InventoryTag   NewDevice; | ||||||
|             uint64_t Now = OpenWifi::Now(); |             uint64_t Now = OpenWifi::Now(); | ||||||
| @@ -223,7 +224,7 @@ namespace OpenWifi { | |||||||
|             ProvObjects::DeviceRules    Rules; |             ProvObjects::DeviceRules    Rules; | ||||||
|             std::string     SerialNumber = Utils::IntToSerialNumber(i); |             std::string     SerialNumber = Utils::IntToSerialNumber(i); | ||||||
|             if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) { |             if(EvaluateDeviceSerialNumberRules(SerialNumber,Rules)) { | ||||||
|                 if(Rules.rrm=="yes") |                 if(Rules.rrm!="no" && Rules.rrm!="inherit") | ||||||
|                     DeviceList.push_back(SerialNumber); |                     DeviceList.push_back(SerialNumber); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,51 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-28. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include "storage_jobs.h" |  | ||||||
| #include "framework/OpenWifiTypes.h" |  | ||||||
| #include "framework/MicroService.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|  |  | ||||||
|     static  ORM::FieldVec    JobDB_Fields{ |  | ||||||
|         // object info |  | ||||||
|         ORM::Field{"id",64, true}, |  | ||||||
|         ORM::Field{"name",ORM::FieldType::FT_TEXT}, |  | ||||||
|         ORM::Field{"description",ORM::FieldType::FT_TEXT}, |  | ||||||
|         ORM::Field{"type",ORM::FieldType::FT_TEXT}, |  | ||||||
|         ORM::Field{"progress",ORM::FieldType::FT_BIGINT}, |  | ||||||
|         ORM::Field{"total",ORM::FieldType::FT_BIGINT}, |  | ||||||
|         ORM::Field{"parameters",ORM::FieldType::FT_TEXT} |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     static  ORM::IndexVec    JobDB_Indexes{ |  | ||||||
|         { std::string("job_name_index"), |  | ||||||
|           ORM::IndexEntryVec{ |  | ||||||
|             {std::string("name"), |  | ||||||
|              ORM::Indextype::ASC} } } |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     JobDB::JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) : |  | ||||||
|     DB(T, "jobs", JobDB_Fields, JobDB_Indexes, P, L, "job") {} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobDBRecordType &In, OpenWifi::JobRecord &Out) { |  | ||||||
|     Out.id = In.get<0>(); |  | ||||||
|     Out.name = In.get<1>(); |  | ||||||
|     Out.description = In.get<2>(); |  | ||||||
|     Out.type = In.get<3>(); |  | ||||||
|     Out.progress = In.get<4>(); |  | ||||||
|     Out.total = In.get<5>(); |  | ||||||
|     Out.parameters = OpenWifi::RESTAPI_utils::to_array_of_array_of_object<OpenWifi::Job::Parameter>(In.get<3>()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<> void ORM::DB<OpenWifi::JobDBRecordType, OpenWifi::JobRecord>::Convert(const OpenWifi::JobRecord &In, OpenWifi::JobDBRecordType &Out) { |  | ||||||
|     Out.set<0>(In.id); |  | ||||||
|     Out.set<1>(In.name); |  | ||||||
|     Out.set<2>(In.description); |  | ||||||
|     Out.set<3>(In.type); |  | ||||||
|     Out.set<4>(In.progress); |  | ||||||
|     Out.set<5>(In.total); |  | ||||||
|     Out.set<6>(OpenWifi::RESTAPI_utils::to_string(In.parameters)); |  | ||||||
| } |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| // |  | ||||||
| // Created by stephane bourque on 2021-10-28. |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "framework/orm.h" |  | ||||||
| #include "JobController.h" |  | ||||||
|  |  | ||||||
| namespace OpenWifi { |  | ||||||
|     typedef Poco::Tuple< |  | ||||||
|         std::string, |  | ||||||
|         std::string, |  | ||||||
|         std::string, |  | ||||||
|         std::string, |  | ||||||
|         uint64_t, |  | ||||||
|         uint64_t, |  | ||||||
|         std::string |  | ||||||
|     > JobDBRecordType; |  | ||||||
|  |  | ||||||
|     struct JobRecord { |  | ||||||
|         Types::UUID_t       id; |  | ||||||
|         std::string         name; |  | ||||||
|         std::string         description; |  | ||||||
|         std::string         type; |  | ||||||
|         uint64_t            progress; |  | ||||||
|         uint64_t            total; |  | ||||||
|         Job::ParametersVec  parameters; |  | ||||||
|  |  | ||||||
|         // void from_string(const std::string &S); |  | ||||||
|         // std::string to_string() const; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     class JobDB : public ORM::DB<JobDBRecordType, JobRecord> { |  | ||||||
|     public: |  | ||||||
|         JobDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L); |  | ||||||
|         virtual ~JobDB() {}; |  | ||||||
|     private: |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
| @@ -97,7 +97,7 @@ if [ -z ${OWPROV_OVERRIDE+x} ]; then | |||||||
| 		port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')" | 		port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')" | ||||||
| 		path="$(echo $url | grep / | cut -d/ -f2-)" | 		path="$(echo $url | grep / | cut -d/ -f2-)" | ||||||
| 		export OWPROV=${url} | 		export OWPROV=${url} | ||||||
| 		echo "Using ${OWPROV}..." | 		echo "Using PROV=${OWPROV}..." | ||||||
| 	else | 	else | ||||||
| 		echo "OWPROV endpoint is not found:" | 		echo "OWPROV endpoint is not found:" | ||||||
| 		jq < ${result_file} | 		jq < ${result_file} | ||||||
| @@ -108,6 +108,33 @@ else | |||||||
| fi | fi | ||||||
| } | } | ||||||
|  |  | ||||||
|  | setrrm() { | ||||||
|  |     if [ -z ${OWRRM_OVERRIDE+x} ]; then | ||||||
|  |     curl  ${FLAGS} -X GET "https://${OWSEC}/api/v1/systemEndpoints" \ | ||||||
|  |         -H "Accept: application/json" \ | ||||||
|  |         -H "Content-Type: application/json" \ | ||||||
|  |         -H "Authorization: Bearer ${token}"  > ${result_file} | ||||||
|  |     rawurl="$(cat ${result_file} | jq -r '.endpoints[] | select( .type == "owrrm" ) | .uri')" | ||||||
|  |     if [[ ! -z "${rawurl}" ]]; then | ||||||
|  |             proto="$(echo $rawurl | grep :// | sed -e's,^\(.*://\).*,\1,g')" | ||||||
|  |     url="$(echo ${rawurl/$proto/})" | ||||||
|  |     user="$(echo $url | grep @ | cut -d@ -f1)" | ||||||
|  |     hostport="$(echo ${url/$user@/} | cut -d/ -f1)" | ||||||
|  |     host="$(echo $hostport | sed -e 's,:.*,,g')" | ||||||
|  |     port="$(echo $hostport | sed -e 's,^.*:,:,g' -e 's,.*:\([0-9]*\).*,\1,g' -e 's,[^0-9],,g')" | ||||||
|  |     path="$(echo $url | grep / | cut -d/ -f2-)" | ||||||
|  |     export OWRRM=${url} | ||||||
|  |     echo "Using RRM=${OWRRM}..." | ||||||
|  |     else | ||||||
|  |     echo "OWRRM endpoint is not found:" | ||||||
|  |     jq < ${result_file} | ||||||
|  |     exit 1 | ||||||
|  |     fi | ||||||
|  |     else | ||||||
|  |     export OWRRM=${OWRRM_OVERRIDE} | ||||||
|  |     fi | ||||||
|  | } | ||||||
|  |  | ||||||
| logout() { | logout() { | ||||||
|   curl  ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \ |   curl  ${FLAGS} -X DELETE "https://${OWSEC}/api/v1/oauth2/${token}" \ | ||||||
|         -H "Content-Type: application/json" \ |         -H "Content-Type: application/json" \ | ||||||
| @@ -499,6 +526,32 @@ listvenues() { | |||||||
|     jq < ${result_file} |     jq < ${result_file} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | getvenuedevices() { | ||||||
|  |     curl    ${FLAGS} -X GET "https://${OWPROV}/api/v1/venue/$1?getDevices=true&getChildren=true" \ | ||||||
|  |         -H "Content-Type: application/json" \ | ||||||
|  |         -H "Authorization: Bearer ${token}" \ | ||||||
|  |         -H "Accept: application/json" > ${result_file} | ||||||
|  |     jq < ${result_file} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | listrrmalgos() { | ||||||
|  |     setrrm | ||||||
|  |     curl    ${FLAGS} -X GET "http://${OWRRM}/api/v1/algorithms" \ | ||||||
|  |         -H "Content-Type: application/json" \ | ||||||
|  |         -H "Authorization: Bearer ${token}" \ | ||||||
|  |         -H "Accept: application/json" > ${result_file} | ||||||
|  |     jq < ${result_file} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | rrmprovider() { | ||||||
|  |     setrrm | ||||||
|  |     curl    ${FLAGS} -X GET "http://${OWRRM}/api/v1/provider" \ | ||||||
|  |         -H "Content-Type: application/json" \ | ||||||
|  |         -H "Authorization: Bearer ${token}" \ | ||||||
|  |         -H "Accept: application/json" > ${result_file} | ||||||
|  |     jq < ${result_file} | ||||||
|  | } | ||||||
|  |  | ||||||
| shopt -s nocasematch | shopt -s nocasematch | ||||||
| case "$1" in | case "$1" in | ||||||
|     "login") login; echo "You are logged in..."  ; logout ;; |     "login") login; echo "You are logged in..."  ; logout ;; | ||||||
| @@ -546,6 +599,9 @@ case "$1" in | |||||||
|     "getsignup") login; getsignup $2; logout;; |     "getsignup") login; getsignup $2; logout;; | ||||||
|     "getsubdevs") login; getsubdevs $2; logout;; |     "getsubdevs") login; getsubdevs $2; logout;; | ||||||
|     "listvenues") login; listvenues $2; logout;; |     "listvenues") login; listvenues $2; logout;; | ||||||
|  |     "getvenuedevices") login; getvenuedevices $2; logout;; | ||||||
|  |     "listrrmalgos") login; listrrmalgos; logout;; | ||||||
|  |     "rrmprovider") login; rrmprovider; logout;; | ||||||
|     *) help ;; |     *) help ;; | ||||||
| esac | esac | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								test_scripts/update_objects.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								test_scripts/update_objects.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | #!/bin/bash | ||||||
|  |  | ||||||
|  | dst=~/Desktop/Dropbox/clion/last_obj_update | ||||||
|  | src=~/Desktop/Dropbox/clion | ||||||
|  | rm -rf ${dst} | ||||||
|  | mkdir ${dst} | ||||||
|  |  | ||||||
|  | cp ${src}/wlan-cloud-ucentralgw/src/RESTObjects/RESTAPI_GWobjects.* ${dst}/. | ||||||
|  | cp ${src}/wlan-cloud-ucentralsec/src/RESTObjects/RESTAPI_SecurityObjects.* ${dst}/. | ||||||
|  | cp ${src}/wlan-cloud-ucentralfms/src/RESTObjects/RESTAPI_FMSObjects.* ${dst}/. | ||||||
|  | cp ${src}/wlan-cloud-prov/src/RESTObjects/RESTAPI_ProvObjects.* ${dst}/. | ||||||
|  | cp ${src}/wlan-cloud-analytics/src/RESTObjects/RESTAPI_AnalyticsObjects.* ${dst}/. | ||||||
|  | cp ${src}/wlan-cloud-certportal/src/RESTObjects/RESTAPI_CertObjects.* ${dst}/. | ||||||
|  | cp ${src}/wlan-cloud-userportal/src/RESTObjects/RESTAPI_SubObjects.* ${dst}/. | ||||||
|  | cp ${src}/ucentralsim/src/RESTObjects/RESTAPI_OWLSobjects.* ${dst}/. | ||||||
|  |  | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-ucentralgw/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-ucentralsec/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-ucentralfms/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-prov/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-analytics/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-certportal/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/wlan-cloud-userportal/src/RESTObjects/. | ||||||
|  | cp ${dst}/*.* ${src}/ucentralsim/src/RESTObjects/. | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| #!/bin/sh | #!/bin/bash | ||||||
| # wait-for-postgres.sh | # wait-for-postgres.sh | ||||||
|  |  | ||||||
| set -e | set -e | ||||||
| @@ -20,7 +20,7 @@ if [ "$1" = '/openwifi/owprov' -a "$(id -u)" = '0' ]; then | |||||||
|     if [ "$RUN_CHOWN" = 'true' ]; then |     if [ "$RUN_CHOWN" = 'true' ]; then | ||||||
|       chown -R "$OWPROV_USER": "$OWPROV_ROOT" "$OWPROV_CONFIG" |       chown -R "$OWPROV_USER": "$OWPROV_ROOT" "$OWPROV_CONFIG" | ||||||
|     fi |     fi | ||||||
|     exec su-exec "$OWPROV_USER" "$@" |     exec gosu "$OWPROV_USER" "$@" | ||||||
| fi | fi | ||||||
|  |  | ||||||
| exec "$@" | exec "$@" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user