mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralfms.git
synced 2025-10-29 18:02:20 +00:00
Compare commits
138 Commits
v2.6.0-RC2
...
release/v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07f2b3944e | ||
|
|
7760230f02 | ||
|
|
6223ade0f6 | ||
|
|
64e6a6f70a | ||
|
|
c67367ec4d | ||
|
|
fe3c5d7c4a | ||
|
|
da52cf5823 | ||
|
|
3c8d8697e0 | ||
|
|
7b0c61ff5e | ||
|
|
e9a9416332 | ||
|
|
2255988b4c | ||
|
|
106c9353fc | ||
|
|
6c7fc8e310 | ||
|
|
e151b45d51 | ||
|
|
1584ff1ebe | ||
|
|
82ccb08d6b | ||
|
|
82b184a79f | ||
|
|
71c37edde7 | ||
|
|
0c8fa44935 | ||
|
|
32714f95b6 | ||
|
|
13cbf8c603 | ||
|
|
48c95c3101 | ||
|
|
857055750f | ||
|
|
96b22ef09b | ||
|
|
acff9afff2 | ||
|
|
1e250be2cd | ||
|
|
93a8624645 | ||
|
|
b9bf57e1f2 | ||
|
|
f203622299 | ||
|
|
698282658c | ||
|
|
5baacac9bf | ||
|
|
8ca4531c99 | ||
|
|
a6e0cd453b | ||
|
|
5e39f63fd2 | ||
|
|
9b081c6924 | ||
|
|
be2150d845 | ||
|
|
2d6f1879f5 | ||
|
|
e870a381a8 | ||
|
|
0cc0d0204e | ||
|
|
498e55f933 | ||
|
|
a9b3cb9821 | ||
|
|
29736da681 | ||
|
|
28f890002b | ||
|
|
0ec0a4fd95 | ||
|
|
6dce398ddc | ||
|
|
eca0e8883a | ||
|
|
43cc667a59 | ||
|
|
a084230cbd | ||
|
|
59c5ed51c0 | ||
|
|
1128fd3c23 | ||
|
|
ee4f1fac93 | ||
|
|
a1a600de77 | ||
|
|
9d64c2dabd | ||
|
|
4f6c9728ef | ||
|
|
167933e422 | ||
|
|
f661bb579a | ||
|
|
1e14eb1611 | ||
|
|
dae57a7492 | ||
|
|
d30014372b | ||
|
|
a9f37ae30d | ||
|
|
23bc11f26e | ||
|
|
caa25f0a1e | ||
|
|
b86e80be6d | ||
|
|
880a14b651 | ||
|
|
fa5d1b982a | ||
|
|
e803885d24 | ||
|
|
17b7e1de59 | ||
|
|
15d7ae635c | ||
|
|
244423132e | ||
|
|
ad149a8e40 | ||
|
|
59020f8809 | ||
|
|
4c5dbea4fb | ||
|
|
8fa42ab75d | ||
|
|
ad1d7301a1 | ||
|
|
6ad2f0ba1b | ||
|
|
aad7cf752a | ||
|
|
ff8fa5e625 | ||
|
|
6e38083912 | ||
|
|
98509fdab7 | ||
|
|
2bbaf44e88 | ||
|
|
c187710ddf | ||
|
|
c04a0c47ba | ||
|
|
7492e68a73 | ||
|
|
912903cc49 | ||
|
|
2a1cc8dc2a | ||
|
|
4e344eac03 | ||
|
|
9be24a146d | ||
|
|
2b9e934ac1 | ||
|
|
db5dffe2b8 | ||
|
|
e527983fa6 | ||
|
|
e0ef8d1dbf | ||
|
|
bc1a2b2ab8 | ||
|
|
06da583a6d | ||
|
|
39e8fbc863 | ||
|
|
88adcf6e78 | ||
|
|
dc6455813a | ||
|
|
fed5739afc | ||
|
|
f2fd761558 | ||
|
|
139c3ba217 | ||
|
|
ec8d304ae7 | ||
|
|
578580ad95 | ||
|
|
5e719c9b90 | ||
|
|
96b59c700a | ||
|
|
bbaa5da556 | ||
|
|
5df2701c21 | ||
|
|
ebd890dc79 | ||
|
|
23729bdde0 | ||
|
|
f02d932059 | ||
|
|
c450328e05 | ||
|
|
cf461eadb0 | ||
|
|
73ee40acde | ||
|
|
acd5800206 | ||
|
|
c5b613ecff | ||
|
|
892a756aae | ||
|
|
ccf1834c0b | ||
|
|
f5c4b3b37b | ||
|
|
33f8d5afb2 | ||
|
|
8b37fe2c8c | ||
|
|
66433efb61 | ||
|
|
085aa109c3 | ||
|
|
63043acce8 | ||
|
|
2612a74567 | ||
|
|
38e86e4de6 | ||
|
|
d0ba0eac22 | ||
|
|
0a59afa1fa | ||
|
|
7df6151da8 | ||
|
|
6351082acf | ||
|
|
de6abed9ae | ||
|
|
ba97fd59df | ||
|
|
8ef97f6300 | ||
|
|
f24fb790eb | ||
|
|
1c786ec360 | ||
|
|
c001eb77d8 | ||
|
|
7e7ddd953f | ||
|
|
477f59ca9b | ||
|
|
e0548a2696 | ||
|
|
a900b7e28e | ||
|
|
ef63dcd5b9 |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
DOCKER_REGISTRY_USERNAME: ucentral
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
@@ -58,11 +58,11 @@ jobs:
|
||||
- name: Get base branch name and set as output
|
||||
id: get_base_branch
|
||||
run: |
|
||||
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
|
||||
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
|
||||
echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
|
||||
echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
- docker
|
||||
steps:
|
||||
- name: Checkout actions repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Telecominfraproject/.github
|
||||
path: github
|
||||
|
||||
41
.github/workflows/openapi-pages.yml
vendored
Normal file
41
.github/workflows/openapi-pages.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Update OpenAPI docs on GitHub Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'openapi/**'
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
docsgen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Generate static HTML page with docs from OpenAPI definition
|
||||
run: |
|
||||
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralfms/main/openapi/owfms.yaml -g html2 --skip-validate-spec -o /local/
|
||||
|
||||
- name: Update OpenAPI docs
|
||||
run: |
|
||||
mkdir tmp-docs
|
||||
mv index.html tmp-docs/index.html
|
||||
mkdir -p ~/.ssh
|
||||
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
|
||||
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
|
||||
git config --global credential.helper store
|
||||
git config --global user.email "tip-automation@telecominfraproject.com"
|
||||
git config --global user.name "TIP Automation User"
|
||||
git pull
|
||||
git checkout gh-pages || git checkout -b gh-pages
|
||||
rm -rf docs
|
||||
mv tmp-docs docs
|
||||
git add docs
|
||||
git commit -m'Update OpenAPI docs for GitHub pages'
|
||||
git push --set-upstream origin gh-pages
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(owfms VERSION 2.6.0)
|
||||
project(owfms VERSION 2.8.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -27,12 +27,12 @@ endif()
|
||||
|
||||
find_package(Git QUIET)
|
||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
RESULT_VARIABLE GIT_RESULT
|
||||
OUTPUT_VARIABLE GIT_HASH)
|
||||
if(NOT GIT_RESULT EQUAL "0")
|
||||
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
|
||||
message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
|
||||
endif()
|
||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||
endif()
|
||||
@@ -42,8 +42,10 @@ endif()
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||
find_package(AWSSDK REQUIRED COMPONENTS s3)
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
if(SMALL_BUILD)
|
||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||
@@ -59,6 +61,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)
|
||||
|
||||
add_compile_options(-Wall -Wextra)
|
||||
add_definitions(-DPOCO_LOG_DEBUG="1")
|
||||
|
||||
if(ASAN)
|
||||
add_compile_options(-fsanitize=address)
|
||||
add_link_options(-fsanitize=address)
|
||||
@@ -73,12 +77,54 @@ add_executable( owfms
|
||||
src/framework/OpenWifiTypes.h
|
||||
src/framework/orm.h
|
||||
src/framework/StorageClass.h
|
||||
src/framework/ow_constants.h
|
||||
src/framework/WebSocketClientNotifications.h
|
||||
src/framework/MicroServiceErrorHandler.h
|
||||
src/framework/UI_WebSocketClientServer.cpp
|
||||
src/framework/UI_WebSocketClientServer.h
|
||||
src/framework/UI_WebSocketClientNotifications.cpp
|
||||
src/framework/UI_WebSocketClientNotifications.h
|
||||
src/framework/utils.h
|
||||
src/framework/utils.cpp
|
||||
src/framework/AppServiceRegistry.h
|
||||
src/framework/SubSystemServer.cpp
|
||||
src/framework/SubSystemServer.h
|
||||
src/framework/RESTAPI_utils.h
|
||||
src/framework/AuthClient.cpp
|
||||
src/framework/AuthClient.h
|
||||
src/framework/MicroServiceNames.h
|
||||
src/framework/MicroServiceFuncs.h
|
||||
src/framework/OpenAPIRequests.cpp
|
||||
src/framework/OpenAPIRequests.h
|
||||
src/framework/MicroServiceFuncs.cpp
|
||||
src/framework/ALBserver.cpp
|
||||
src/framework/ALBserver.h
|
||||
src/framework/KafkaManager.cpp
|
||||
src/framework/KafkaManager.h
|
||||
src/framework/RESTAPI_RateLimiter.h
|
||||
src/framework/WebSocketLogger.h
|
||||
src/framework/RESTAPI_GenericServerAccounting.h
|
||||
src/framework/RESTAPI_SystemConfiguration.h
|
||||
src/framework/CIDR.h
|
||||
src/framework/RESTAPI_Handler.cpp
|
||||
src/framework/RESTAPI_Handler.h
|
||||
src/framework/RESTAPI_ExtServer.h
|
||||
src/framework/RESTAPI_ExtServer.cpp
|
||||
src/framework/RESTAPI_IntServer.cpp
|
||||
src/framework/RESTAPI_IntServer.h
|
||||
src/framework/RESTAPI_SystemCommand.h
|
||||
src/framework/RESTAPI_WebSocketServer.h
|
||||
src/framework/EventBusManager.cpp
|
||||
src/framework/EventBusManager.h
|
||||
src/framework/RESTAPI_PartHandler.h
|
||||
src/framework/MicroService.cpp
|
||||
src/framework/MicroServiceExtra.h
|
||||
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
|
||||
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
|
||||
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
|
||||
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
|
||||
src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
|
||||
src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
|
||||
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
|
||||
src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
|
||||
src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
|
||||
src/RESTAPI/RESTAPI_firmwaresHandler.cpp src/RESTAPI/RESTAPI_firmwaresHandler.h
|
||||
src/RESTAPI/RESTAPI_firmwareHandler.cpp src/RESTAPI/RESTAPI_firmwareHandler.h
|
||||
src/RESTAPI/RESTAPI_historyHandler.cpp src/RESTAPI/RESTAPI_historyHandler.h
|
||||
@@ -91,7 +137,6 @@ add_executable( owfms
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
src/StorageService.cpp src/StorageService.h
|
||||
src/ManifestCreator.cpp src/ManifestCreator.h
|
||||
src/framework/MicroService.h
|
||||
src/NewConnectionHandler.cpp src/NewConnectionHandler.h
|
||||
src/LatestFirmwareCache.cpp src/LatestFirmwareCache.h
|
||||
src/DeviceCache.cpp src/DeviceCache.h
|
||||
@@ -101,7 +146,9 @@ add_executable( owfms
|
||||
src/NewCommandHandler.cpp src/NewCommandHandler.h
|
||||
src/storage/orm_history.cpp src/storage/orm_history.h
|
||||
src/storage/orm_firmwares.cpp src/storage/orm_firmwares.h
|
||||
src/storage/orm_deviceInfo.cpp src/storage/orm_deviceInfo.h src/RESTAPI/RESTAPI_deviceInformation_handler.cpp src/RESTAPI/RESTAPI_deviceInformation_handler.h)
|
||||
src/storage/orm_deviceInfo.cpp src/storage/orm_deviceInfo.h
|
||||
src/RESTAPI/RESTAPI_deviceInformation_handler.cpp
|
||||
src/RESTAPI/RESTAPI_deviceInformation_handler.h)
|
||||
|
||||
target_link_libraries( owfms PUBLIC
|
||||
${Poco_LIBRARIES}
|
||||
|
||||
108
Dockerfile
108
Dockerfile
@@ -1,16 +1,21 @@
|
||||
FROM alpine:3.15 AS build-base
|
||||
ARG DEBIAN_VERSION=11.5-slim
|
||||
ARG POCO_VERSION=poco-tip-v2
|
||||
ARG CPPKAFKA_VERSION=tip-v1
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
make cmake g++ git \
|
||||
unixodbc-dev postgresql-dev mariadb-dev \
|
||||
librdkafka-dev boost-dev openssl-dev \
|
||||
zlib-dev nlohmann-json \
|
||||
curl-dev
|
||||
FROM debian:$DEBIAN_VERSION AS build-base
|
||||
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
make cmake g++ git curl zip unzip pkg-config \
|
||||
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
||||
librdkafka-dev libboost-all-dev libssl-dev \
|
||||
zlib1g-dev ca-certificates libcurl4-openssl-dev libfmt-dev
|
||||
|
||||
FROM build-base AS poco-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
ARG POCO_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
|
||||
|
||||
WORKDIR /poco
|
||||
RUN mkdir cmake-build
|
||||
@@ -19,22 +24,12 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target 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 cppkafka-build
|
||||
|
||||
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
ARG CPPKAFKA_VERSION
|
||||
|
||||
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
|
||||
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -43,74 +38,47 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS json-schema-validator-build
|
||||
|
||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
FROM build-base AS aws-sdk-cpp-build
|
||||
|
||||
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json
|
||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp
|
||||
|
||||
WORKDIR /aws-sdk-cpp
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake .. -DBUILD_ONLY="sns;s3" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \
|
||||
-DAUTORUN_UNIT_TESTS=OFF
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
FROM build-base AS owfms-build
|
||||
|
||||
ADD CMakeLists.txt build /owfms/
|
||||
ADD overlays /owfms/overlays
|
||||
ADD cmake /owfms/cmake
|
||||
ADD src /owfms/src
|
||||
ADD .git /owfms/.git
|
||||
ARG VCPKG_VERSION=2022.11.14
|
||||
RUN git clone --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg && \
|
||||
./vcpkg/bootstrap-vcpkg.sh && \
|
||||
mkdir /vcpkg/custom-triplets && \
|
||||
cp /vcpkg/triplets/x64-linux.cmake /vcpkg/custom-triplets/x64-linux.cmake && \
|
||||
sed -i 's/set(VCPKG_LIBRARY.*/set(VCPKG_LIBRARY_LINKAGE dynamic)/g' /vcpkg/custom-triplets/x64-linux.cmake && \
|
||||
./vcpkg/vcpkg install aws-sdk-cpp[s3]:x64-linux json-schema-validator:x64-linux --overlay-triplets=/vcpkg/custom-triplets --overlay-ports=/owfms/overlays
|
||||
|
||||
COPY --from=poco-build /usr/local/include /usr/local/include
|
||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=cppkafka-build /usr/local/include /usr/local/include
|
||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
|
||||
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include
|
||||
COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib
|
||||
COPY --from=fmtlib-build /usr/local/include /usr/local/include
|
||||
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
|
||||
|
||||
WORKDIR /owfms
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR /owfms/cmake-build
|
||||
RUN cmake .. \
|
||||
-Dcrypto_LIBRARY=/usr/lib/libcrypto.so \
|
||||
-DBUILD_SHARED_LIBS=ON
|
||||
RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine:3.15
|
||||
FROM debian:$DEBIAN_VERSION
|
||||
|
||||
ENV OWFMS_USER=owfms \
|
||||
OWFMS_ROOT=/owfms-data \
|
||||
OWFMS_CONFIG=/owfms-data
|
||||
|
||||
RUN addgroup -S "$OWFMS_USER" && \
|
||||
adduser -S -G "$OWFMS_USER" "$OWFMS_USER"
|
||||
RUN useradd "$OWFMS_USER"
|
||||
|
||||
RUN mkdir /openwifi
|
||||
RUN mkdir -p "$OWFMS_ROOT" "$OWFMS_CONFIG" && \
|
||||
chown "$OWFMS_USER": "$OWFMS_ROOT" "$OWFMS_CONFIG"
|
||||
|
||||
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
|
||||
mariadb-connector-c libpq unixodbc postgresql-client
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
||||
libmariadb-dev-compat libpq5 postgresql-client libfmt7 sqlite3
|
||||
|
||||
COPY readiness_check /readiness_check
|
||||
COPY test_scripts/curl/cli /cli
|
||||
@@ -119,14 +87,14 @@ COPY owfms.properties.tmpl /
|
||||
COPY docker-entrypoint.sh /
|
||||
COPY wait-for-postgres.sh /
|
||||
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=owfms-build /owfms/cmake-build/owfms /openwifi/owfms
|
||||
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=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib
|
||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib
|
||||
COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib
|
||||
COPY --from=owfms-build /vcpkg/installed/x64-linux/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/
|
||||
|
||||
RUN ldconfig
|
||||
|
||||
EXPOSE 16004 17004 16104
|
||||
|
||||
|
||||
@@ -5,6 +5,11 @@ The uCentralFMS is a micro-service part of the OpenWiFi ecosystem. uCentralFMS i
|
||||
to facilitate the task of upgrade and maintaining the proper firmware for all the devices
|
||||
used in your OpenWiFi solution. You may either [build it](#building) or use the [Docker version](#docker).
|
||||
|
||||
## OpenAPI
|
||||
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-ucentralfms/).
|
||||
|
||||
Also you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentralfms/main/openapi/owfms.yaml)) to get interactive docs page.
|
||||
|
||||
## Building
|
||||
In order to build the uCentralFMS, you will need to install its dependencies, which includes the following:
|
||||
- cmake
|
||||
@@ -216,4 +221,4 @@ s3.key = *******************************************
|
||||
s3.retry = 60
|
||||
s3.bucket.uri = ucentral-ap-firmware.s3.amazonaws.com
|
||||
|
||||
```
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
@@ -22,6 +22,9 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
||||
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17004"} \
|
||||
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16004"} \
|
||||
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
||||
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
|
||||
FIRMWAREDB_REFRESH=${FIRMWAREDB_REFRESH:-"86400"} \
|
||||
FIRMWAREDB_MAXAGE=${FIRMWAREDB_MAXAGE:-"90"} \
|
||||
S3_BUCKETNAME=${S3_BUCKETNAME:-"ucentral-ap-firmware"} \
|
||||
S3_REGION=${S3_REGION:-"us-east-1"} \
|
||||
S3_SECRET=${S3_SECRET:-"*******************************************"} \
|
||||
@@ -51,7 +54,7 @@ if [ "$1" = '/openwifi/owfms' -a "$(id -u)" = '0' ]; then
|
||||
if [ "$RUN_CHOWN" = 'true' ]; then
|
||||
chown -R "$OWFMS_USER": "$OWFMS_ROOT" "$OWFMS_CONFIG"
|
||||
fi
|
||||
exec su-exec "$OWFMS_USER" "$@"
|
||||
exec gosu "$OWFMS_USER" "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
2
helm/.gitignore
vendored
2
helm/.gitignore
vendored
@@ -1 +1,3 @@
|
||||
*.swp
|
||||
Chart.lock
|
||||
charts/
|
||||
|
||||
@@ -70,7 +70,8 @@ The following table lists the configurable parameters of the chart and their def
|
||||
| persistence.size | string | Defines PV size | `'10Gi'` |
|
||||
| public_env_variables | hash | Defines list of environment variables to be passed to the Firmware | |
|
||||
| configProperties | hash | Configuration properties that should be passed to the application in `owfms.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 Firmware (PEM format is adviced to be used) (see `volumes.owfms` 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.owfms` 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,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{{- $root := . -}}
|
||||
{{- $storageType := index .Values.configProperties "storage.type" -}}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -46,6 +47,39 @@ spec:
|
||||
- -timeout
|
||||
- 600s
|
||||
|
||||
{{- if eq $storageType "postgresql" }}
|
||||
- name: wait-postgres
|
||||
image: "{{ .Values.images.owfms.repository }}:{{ .Values.images.owfms.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owfms.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 "owfms.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.owfms }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
subPath: {{ .subPath }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
containers:
|
||||
|
||||
- name: owfms
|
||||
@@ -97,8 +131,10 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
fsGroup: 101
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
imagePullSecrets:
|
||||
{{- range $image, $imageValue := .Values.images }}
|
||||
|
||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
||||
images:
|
||||
owfms:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owfms
|
||||
tag: main
|
||||
tag: v2.8.0
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
@@ -71,7 +71,7 @@ volumes:
|
||||
mountPath: /owfms-data/certs
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ include "owfms.fullname" . }}-certs
|
||||
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owfms.fullname" . }}-certs{{ end }}
|
||||
# Change this if you want to use another volume type
|
||||
- name: persist
|
||||
mountPath: /owfms-data/persist
|
||||
@@ -91,6 +91,9 @@ resources: {}
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
@@ -144,7 +147,7 @@ configProperties:
|
||||
s3.region: us-east-1
|
||||
s3.retry: 60
|
||||
s3.bucket.uri: ucentral-ap-firmware.s3.amazonaws.com
|
||||
firmwaredb.refresh: 1800
|
||||
firmwaredb.refresh: 86400
|
||||
# ALB
|
||||
alb.enable: "true"
|
||||
alb.port: 16104
|
||||
@@ -207,6 +210,9 @@ configProperties:
|
||||
storage.type.mysql.username: stephb
|
||||
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:
|
||||
# restapi-ca.pem: ""
|
||||
# restapi-cert.pem: ""
|
||||
|
||||
@@ -30,58 +30,13 @@ components:
|
||||
|
||||
responses:
|
||||
NotFound:
|
||||
description: The specified resource was not found.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
|
||||
Unauthorized:
|
||||
description: The requested does not have sufficient rights to perform the operation.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
ErrorCode:
|
||||
type: integer
|
||||
enum:
|
||||
- 0 # Success
|
||||
- 1 # PASSWORD_CHANGE_REQUIRED,
|
||||
- 2 # INVALID_CREDENTIALS,
|
||||
- 3 # PASSWORD_ALREADY_USED,
|
||||
- 4 # USERNAME_PENDING_VERIFICATION,
|
||||
- 5 # PASSWORD_INVALID,
|
||||
- 6 # INTERNAL_ERROR,
|
||||
- 7 # ACCESS_DENIED,
|
||||
- 8 # INVALID_TOKEN
|
||||
- 9 # EXPIRED_TOKEN
|
||||
- 10 # RATE_LIMIT_EXCEEDED
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
type: string
|
||||
|
||||
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
|
||||
Success:
|
||||
description: The requested operation was performed.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
Operation:
|
||||
type: string
|
||||
Details:
|
||||
type: string
|
||||
Code:
|
||||
type: integer
|
||||
$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:
|
||||
FirmwareDetails:
|
||||
|
||||
1
overlays/curl/portfile.cmake
Normal file
1
overlays/curl/portfile.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
||||
4
overlays/curl/vcpkg.json
Normal file
4
overlays/curl/vcpkg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "curl",
|
||||
"version-string": "7.74.0-1.3+deb11u3"
|
||||
}
|
||||
1
overlays/openssl/portfile.cmake
Normal file
1
overlays/openssl/portfile.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
||||
4
overlays/openssl/vcpkg.json
Normal file
4
overlays/openssl/vcpkg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "openssl",
|
||||
"version-string": "1.1.1n-0+deb11u3"
|
||||
}
|
||||
1
overlays/zlib/portfile.cmake
Normal file
1
overlays/zlib/portfile.cmake
Normal file
@@ -0,0 +1 @@
|
||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
||||
4
overlays/zlib/vcpkg.json
Normal file
4
overlays/zlib/vcpkg.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "zlib",
|
||||
"version-string": "1:1.2.11.dfsg-2+deb11u2"
|
||||
}
|
||||
@@ -35,6 +35,7 @@ openwifi.system.uri.private = https://localhost:17004
|
||||
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16004
|
||||
openwifi.system.commandchannel = /tmp/app.owfms
|
||||
openwifi.system.uri.ui = ucentral-ui.arilia.com
|
||||
openwifi.security.restapi.disable = false
|
||||
|
||||
firmwaredb.refresh = 1800
|
||||
firmwaredb.maxage = 90
|
||||
|
||||
@@ -36,8 +36,10 @@ openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
|
||||
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralfms
|
||||
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
||||
firmwaredb.refresh = 1800
|
||||
firmwaredb.maxage = 90
|
||||
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
|
||||
|
||||
firmwaredb.refresh = ${FIRMWAREDB_REFRESH}
|
||||
firmwaredb.maxage = ${FIRMWAREDB_MAXAGE}
|
||||
|
||||
#
|
||||
# Firmware Microservice Specific Section
|
||||
|
||||
@@ -8,13 +8,19 @@
|
||||
#include "LatestFirmwareCache.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
int AutoUpdater::Start() {
|
||||
AutoUpdaterEnabled_ = MicroService::instance().ConfigGetBool("autoupdater.enabled", false);
|
||||
poco_information(Logger(),"Starting...");
|
||||
AutoUpdaterEnabled_ = MicroServiceConfigGetBool("autoupdater.enabled", false);
|
||||
if(AutoUpdaterEnabled_) {
|
||||
Running_ = false;
|
||||
AutoUpdaterFrequency_ = MicroService::instance().ConfigGetInt("autoupdater.frequency",600);
|
||||
AutoUpdaterFrequency_ = MicroServiceConfigGetInt("autoupdater.frequency",600);
|
||||
AutoUpdaterCallBack_ = std::make_unique<Poco::TimerCallback<AutoUpdater>>(*this, &AutoUpdater::onTimer);
|
||||
Timer_.setStartInterval(5 * 60 * 1000); // first run in 5 minutes
|
||||
Timer_.setPeriodicInterval(AutoUpdaterFrequency_ * 1000);
|
||||
@@ -24,10 +30,12 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void AutoUpdater::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
if(AutoUpdaterEnabled_) {
|
||||
Timer_.stop();
|
||||
}
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void AutoUpdater::ToBeUpgraded(std::string serialNumber, std::string DeviceType) {
|
||||
@@ -45,9 +53,9 @@ namespace OpenWifi {
|
||||
auto Entry = Queue_.front();
|
||||
Queue_.pop_front();
|
||||
try {
|
||||
Logger().debug(fmt::format("Preparing to upgrade {}",Entry.first));
|
||||
poco_debug(Logger(),fmt::format("Preparing to upgrade {}",Entry.first));
|
||||
auto CacheEntry = Cache_.find(Entry.first);
|
||||
uint64_t now = OpenWifi::Now();
|
||||
uint64_t now = Utils::Now();
|
||||
std::string firmwareUpgrade;
|
||||
if(CacheEntry == Cache_.end() || (CacheEntry->second.LastCheck-now)>300) {
|
||||
// get the firmware settings for that device.
|
||||
@@ -55,11 +63,11 @@ namespace OpenWifi {
|
||||
C.LastCheck = now;
|
||||
bool firmwareRCOnly;
|
||||
if(OpenWifi::SDK::Prov::GetFirmwareOptions(Entry.first, firmwareUpgrade, firmwareRCOnly)) {
|
||||
Logger().debug(fmt::format("Found firmware options for {}",Entry.first));
|
||||
poco_debug(Logger(),fmt::format("Found firmware options for {}",Entry.first));
|
||||
C.firmwareRCOnly = firmwareRCOnly;
|
||||
C.firmwareUpgrade = firmwareUpgrade;
|
||||
} else {
|
||||
Logger().debug(fmt::format("Found no firmware options for {}",Entry.first));
|
||||
poco_debug(Logger(),fmt::format("Found no firmware options for {}",Entry.first));
|
||||
C.firmwareRCOnly = firmwareRCOnly;
|
||||
C.firmwareUpgrade = firmwareUpgrade;
|
||||
}
|
||||
@@ -69,7 +77,7 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
if(firmwareUpgrade=="no") {
|
||||
Logger().information(fmt::format("Device {} not upgradable. Provisioning service settings.",Entry.first));
|
||||
poco_information(Logger(),fmt::format("Device {} not upgradable. Provisioning service settings.",Entry.first));
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -79,26 +87,26 @@ namespace OpenWifi {
|
||||
if(LF) {
|
||||
if(StorageService()->FirmwaresDB().GetFirmware(fwEntry.Id,fwDetails)) {
|
||||
// send the command to upgrade this device...
|
||||
Logger().information(fmt::format("Upgrading {} to version {}", Entry.first, fwEntry.Revision));
|
||||
poco_information(Logger(),fmt::format("Upgrading {} to version {}", Entry.first, fwEntry.Revision));
|
||||
if(OpenWifi::SDK::GW::SendFirmwareUpgradeCommand(Entry.first,fwDetails.uri)) {
|
||||
Logger().information(fmt::format("Upgrade command sent for {}",Entry.first));
|
||||
poco_information(Logger(),fmt::format("Upgrade command sent for {}",Entry.first));
|
||||
} else {
|
||||
Logger().information(fmt::format("Upgrade command not sent for {}",Entry.first));
|
||||
poco_information(Logger(),fmt::format("Upgrade command not sent for {}",Entry.first));
|
||||
}
|
||||
} else {
|
||||
Logger().information(fmt::format("Firmware for device {} ({}) cannot be found.", Entry.first, Entry.second ));
|
||||
poco_information(Logger(),fmt::format("Firmware for device {} ({}) cannot be found.", Entry.first, Entry.second ));
|
||||
}
|
||||
} else {
|
||||
Logger().information(fmt::format("Firmware for device {} ({}) cannot be found.", Entry.first, Entry.second ));
|
||||
poco_information(Logger(),fmt::format("Firmware for device {} ({}) cannot be found.", Entry.first, Entry.second ));
|
||||
}
|
||||
} catch (...) {
|
||||
Logger().information(fmt::format("Exception during auto update for device {}.", Entry.first ));
|
||||
poco_information(Logger(),fmt::format("Exception during auto update for device {}.", Entry.first ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutoUpdater::reinitialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||
Logger().information("Reinitializing.");
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
// Created by stephane bourque on 2021-10-04.
|
||||
//
|
||||
|
||||
#ifndef OWFMS_AUTOUPDATER_H
|
||||
#define OWFMS_AUTOUPDATER_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <deque>
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "Poco/Util/Application.h"
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
@@ -55,4 +55,3 @@ namespace OpenWifi {
|
||||
inline auto AutoUpdater() { return AutoUpdater::instance(); }
|
||||
}
|
||||
|
||||
#endif //OWFMS_AUTOUPDATER_H
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "AutoUpdater.h"
|
||||
#include "NewCommandHandler.h"
|
||||
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance_ = nullptr;
|
||||
|
||||
@@ -37,7 +39,8 @@ namespace OpenWifi {
|
||||
NewConnectionHandler(),
|
||||
ManifestCreator(),
|
||||
AutoUpdater(),
|
||||
NewCommandHandler()
|
||||
NewCommandHandler(),
|
||||
UI_WebSocketClientServer()
|
||||
});
|
||||
}
|
||||
return instance_;
|
||||
@@ -45,6 +48,11 @@ namespace OpenWifi {
|
||||
|
||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||
}
|
||||
|
||||
void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
Daemon()->PostInitialization(self);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "framework/MicroServiceNames.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||
#include "Dashboard.h"
|
||||
|
||||
@@ -30,9 +32,7 @@ namespace OpenWifi {
|
||||
|
||||
void PostInitialization(Poco::Util::Application &self);
|
||||
static Daemon *instance();
|
||||
inline void ResetDashboard() { DB_.Reset(); }
|
||||
inline void CreateDashboard() { DB_.Create(); }
|
||||
inline const FMSObjects::DeviceReport & GetDashboard() { return DB_.Report(); }
|
||||
inline DeviceDashboard & GetDashboard() { return DB_; }
|
||||
|
||||
private:
|
||||
static Daemon *instance_;
|
||||
@@ -40,9 +40,6 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||
inline void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||
Daemon()->PostInitialization(self);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_DAEMON_H
|
||||
|
||||
@@ -4,15 +4,48 @@
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void DeviceDashboard::Create() {
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
|
||||
if(LastRun_==0 || (Now-LastRun_)>120) {
|
||||
DB_.reset();
|
||||
StorageService()->DevicesDB().GenerateDeviceReport(DB_);
|
||||
LastRun_ = Now;
|
||||
}
|
||||
}
|
||||
bool DeviceDashboard::Get(FMSObjects::DeviceReport &D, Poco::Logger & Logger) {
|
||||
uint64_t Now = Utils::Now();
|
||||
if(!ValidDashboard_ || LastRun_==0 || (Now-LastRun_)>120) {
|
||||
Generate(D, Logger);
|
||||
} else {
|
||||
std::lock_guard G(DataMutex_);
|
||||
D = DB_;
|
||||
}
|
||||
return ValidDashboard_;
|
||||
};
|
||||
|
||||
void DeviceDashboard::Generate(FMSObjects::DeviceReport &D, Poco::Logger & Logger ) {
|
||||
if (GeneratingDashboard_.load()) {
|
||||
// std::cout << "Trying to generate dashboard but already being generated" << std::endl;
|
||||
while(GeneratingDashboard_.load()) {
|
||||
Poco::Thread::trySleep(100);
|
||||
}
|
||||
std::lock_guard G(DataMutex_);
|
||||
D = DB_;
|
||||
} else {
|
||||
GeneratingDashboard_ = true;
|
||||
ValidDashboard_ = false;
|
||||
try {
|
||||
// std::cout << "Generating dashboard." << std::endl;
|
||||
poco_information(Logger, "DASHBOARD: Generating a new dashboard.");
|
||||
FMSObjects::DeviceReport NewData;
|
||||
StorageService()->DevicesDB().GenerateDeviceReport(NewData);
|
||||
LastRun_ = Utils::Now();
|
||||
NewData.snapshot = LastRun_;
|
||||
D = NewData;
|
||||
std::lock_guard G(DataMutex_);
|
||||
DB_ = NewData;
|
||||
ValidDashboard_=true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
GeneratingDashboard_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,22 +2,26 @@
|
||||
// Created by stephane bourque on 2021-07-21.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALGW_DASHBOARD_H
|
||||
#define UCENTRALGW_DASHBOARD_H
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||
#include "Poco/Logger.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class DeviceDashboard {
|
||||
public:
|
||||
void Create();
|
||||
const FMSObjects::DeviceReport & Report() const { return DB_;}
|
||||
inline void Reset() { LastRun_=0; DB_.reset(); }
|
||||
private:
|
||||
FMSObjects::DeviceReport DB_;
|
||||
uint64_t LastRun_=0;
|
||||
};
|
||||
}
|
||||
class DeviceDashboard {
|
||||
public:
|
||||
bool Get(FMSObjects::DeviceReport &D, Poco::Logger &Logger);
|
||||
|
||||
#endif // UCENTRALGW_DASHBOARD_H
|
||||
private:
|
||||
std::mutex DataMutex_;
|
||||
volatile std::atomic_bool GeneratingDashboard_ = false;
|
||||
volatile bool ValidDashboard_ = false;
|
||||
FMSObjects::DeviceReport DB_;
|
||||
uint64_t LastRun_ = 0;
|
||||
|
||||
void Generate(FMSObjects::DeviceReport &D, Poco::Logger &Logger);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,10 +7,13 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
int DeviceCache::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeviceCache::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
void DeviceCache::AddToCache(
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
// Created by stephane bourque on 2021-07-13.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_DEVICECACHE_H
|
||||
#define UCENTRALFMS_DEVICECACHE_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -43,6 +42,3 @@ namespace OpenWifi {
|
||||
inline auto DeviceCache() { return DeviceCache::instance(); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_DEVICECACHE_H
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
int FirmwareCache::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FirmwareCache::Stop() {
|
||||
|
||||
poco_information(Logger(),"Stopping...");
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
std::shared_ptr<FMSObjects::Firmware> GetFirmware([[maybe_unused]] const std::string & DeviceType, [[maybe_unused]] const std::string & Revision) {
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
// Created by stephane bourque on 2021-07-26.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_FIRMWARECACHE_H
|
||||
#define UCENTRALFMS_FIRMWARECACHE_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -40,6 +39,3 @@ namespace OpenWifi {
|
||||
inline auto FirmwareCache() { return FirmwareCache::instance(); }
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_FIRMWARECACHE_H
|
||||
|
||||
@@ -8,11 +8,14 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
int LatestFirmwareCache::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
StorageService()->FirmwaresDB().PopulateLatestFirmwareCache();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LatestFirmwareCache::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
bool LatestFirmwareCache::AddToCache(const std::string & DeviceType, const std::string &Revision, const std::string &Id, uint64_t TimeStamp) {
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
// Created by stephane bourque on 2021-07-13.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_LATESTFIRMWARECACHE_H
|
||||
#define UCENTRALFMS_LATESTFIRMWARECACHE_H
|
||||
#pragma once
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/JWT/Signer.h"
|
||||
#include "Poco/SHA2Engine.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -42,7 +43,7 @@ namespace OpenWifi {
|
||||
auto Tokens = Poco::StringTokenizer(Revision,"/", Poco::StringTokenizer::TOK_TRIM);
|
||||
if(Tokens.count()!=2)
|
||||
return false;
|
||||
return (Tokens[1].substr(0,5) == "IP-v");
|
||||
return (Tokens[1].substr(0,5) == "TIP-v");
|
||||
}
|
||||
|
||||
void DumpCache();
|
||||
@@ -57,13 +58,10 @@ namespace OpenWifi {
|
||||
Types::StringSet RevisionSet_;
|
||||
Types::StringSet DeviceSet_;
|
||||
explicit LatestFirmwareCache() noexcept:
|
||||
SubSystemServer("FirmwareCache", "FIRMWARE-CACHE", "FirmwareCache")
|
||||
SubSystemServer("LatestFirmwareCache", "LATEST-FIRMWARE-CACHE", "LatestFirmwareCache")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline auto LatestFirmwareCache() { return LatestFirmwareCache::instance(); }
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALFMS_LATESTFIRMWARECACHE_H
|
||||
|
||||
@@ -14,22 +14,25 @@
|
||||
#include "StorageService.h"
|
||||
#include "LatestFirmwareCache.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void ManifestCreator::onTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||
Utils::SetThreadName("manifest");
|
||||
Logger().information("Performing DB refresh");
|
||||
poco_information(Logger(),"Performing DB refresh");
|
||||
S3BucketContent BucketList;
|
||||
StorageService()->FirmwaresDB().RemoveOldFirmware();
|
||||
ReadBucket(BucketList);
|
||||
Logger().information(fmt::format("Found {} firmware entries in S3 repository.", BucketList.size()));
|
||||
poco_information(Logger(),fmt::format("Found {} firmware entries in S3 repository.", BucketList.size()));
|
||||
ComputeManifest(BucketList);
|
||||
AddManifestToDB(BucketList);
|
||||
}
|
||||
|
||||
bool ManifestCreator::ComputeManifest(S3BucketContent &BucketContent) {
|
||||
|
||||
uint64_t Limit = OpenWifi::Now() - MaxAge_, Rejected=0, Accepted=0, BadFormat=0, MissingJson=0;
|
||||
uint64_t Limit = Utils::Now() - MaxAge_, Rejected=0, Accepted=0, BadFormat=0, MissingJson=0;
|
||||
for(auto &[Name,Entry]:BucketContent) {
|
||||
std::string C = Entry.S3ContentManifest;
|
||||
|
||||
@@ -49,7 +52,7 @@ namespace OpenWifi {
|
||||
Entry.Image = ParsedContent->get("image").toString();
|
||||
auto FullNme = Name + "-upgrade.bin";
|
||||
if(FullNme!=Entry.Image) {
|
||||
Logger().error(fmt::format("MANIFEST({}): Image name does not match manifest name ({}).",Name,Entry.Image));
|
||||
poco_error(Logger(),fmt::format("MANIFEST({}): Image name does not match manifest name ({}).",Name,Entry.Image));
|
||||
Entry.Valid = false;
|
||||
BadFormat++;
|
||||
continue;
|
||||
@@ -61,7 +64,7 @@ namespace OpenWifi {
|
||||
Entry.Valid = false;
|
||||
}
|
||||
} else {
|
||||
Logger().error(fmt::format("MANIFEST({}): Entry does not have a valid JSON manifest.",Name));
|
||||
poco_error(Logger(),fmt::format("MANIFEST({}): Entry does not have a valid JSON manifest.",Name));
|
||||
MissingJson++;
|
||||
Entry.Valid = false;
|
||||
}
|
||||
@@ -70,10 +73,10 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
Logger().information(fmt::format("Accepted {} firmwares.", Accepted));
|
||||
Logger().information(fmt::format("Rejected {} too old firmwares.", Rejected));
|
||||
Logger().information(fmt::format("Rejected {} bad JSON.", BadFormat));
|
||||
Logger().information(fmt::format("Rejected {} missing JSON.", MissingJson));
|
||||
poco_information(Logger(),fmt::format("Accepted {} firmwares.", Accepted));
|
||||
poco_information(Logger(),fmt::format("Rejected {} too old firmwares.", Rejected));
|
||||
poco_information(Logger(),fmt::format("Rejected {} bad JSON.", BadFormat));
|
||||
poco_information(Logger(),fmt::format("Rejected {} missing JSON.", MissingJson));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -89,17 +92,17 @@ namespace OpenWifi {
|
||||
continue;
|
||||
|
||||
if(BucketEntry.Valid && !StorageService()->FirmwaresDB().GetFirmwareByName(R,BucketEntry.Compatible,F)) {
|
||||
F.id = MicroService::instance().CreateUUID();
|
||||
F.id = MicroServiceCreateUUID();
|
||||
F.release = Release;
|
||||
F.size = BucketEntry.S3Size;
|
||||
F.created = OpenWifi::Now();
|
||||
F.created = Utils::Now();
|
||||
F.imageDate = BucketEntry.S3TimeStamp;
|
||||
F.image = BucketEntry.Image;
|
||||
F.uri = BucketEntry.URI;
|
||||
F.revision = BucketEntry.Revision;
|
||||
F.deviceType = BucketEntry.Compatible;
|
||||
if(StorageService()->FirmwaresDB().AddFirmware(F)) {
|
||||
Logger().information(fmt::format("Adding firmware '{}', size={}",Release,F.size));
|
||||
poco_information(Logger(),fmt::format("Adding firmware '{}', size={}",Release,F.size));
|
||||
} else {
|
||||
}
|
||||
}
|
||||
@@ -109,14 +112,14 @@ namespace OpenWifi {
|
||||
|
||||
int ManifestCreator::Start() {
|
||||
Running_ = true;
|
||||
S3BucketName_ = MicroService::instance().ConfigGetString("s3.bucketname");
|
||||
S3Region_ = MicroService::instance().ConfigGetString("s3.region");
|
||||
S3Secret_ = MicroService::instance().ConfigGetString("s3.secret");
|
||||
S3Key_ = MicroService::instance().ConfigGetString("s3.key");
|
||||
S3Retry_ = MicroService::instance().ConfigGetInt("s3.retry",60);
|
||||
S3BucketName_ = MicroServiceConfigGetString("s3.bucketname","");
|
||||
S3Region_ = MicroServiceConfigGetString("s3.region","");
|
||||
S3Secret_ = MicroServiceConfigGetString("s3.secret","");
|
||||
S3Key_ = MicroServiceConfigGetString("s3.key","");
|
||||
S3Retry_ = MicroServiceConfigGetInt("s3.retry",60);
|
||||
|
||||
DBRefresh_ = MicroService::instance().ConfigGetInt("firmwaredb.refresh",30*60);
|
||||
MaxAge_ = MicroService::instance().ConfigGetInt("firmwaredb.maxage",90) * 24 * 60 * 60;
|
||||
DBRefresh_ = MicroServiceConfigGetInt("firmwaredb.refresh",30*60);
|
||||
MaxAge_ = MicroServiceConfigGetInt("firmwaredb.maxage",90) * 24 * 60 * 60;
|
||||
|
||||
AwsConfig_.enableTcpKeepAlive = true;
|
||||
AwsConfig_.enableEndpointDiscovery = true;
|
||||
@@ -169,7 +172,7 @@ namespace OpenWifi {
|
||||
static const std::string UPGRADE("-upgrade.bin");
|
||||
|
||||
std::string URIBase = "https://";
|
||||
URIBase += MicroService::instance().ConfigGetString("s3.bucket.uri");
|
||||
URIBase += MicroServiceConfigGetString("s3.bucket.uri","");
|
||||
|
||||
Bucket.clear();
|
||||
|
||||
@@ -185,7 +188,7 @@ namespace OpenWifi {
|
||||
while(!isDone) {
|
||||
Outcome = S3Client.ListObjectsV2(Request);
|
||||
if(!Outcome.IsSuccess()) {
|
||||
Logger().error(fmt::format("Error while doing ListObjectsV2: {}, {}",
|
||||
poco_error(Logger(),fmt::format("Error while doing ListObjectsV2: {}, {}",
|
||||
std::string{Outcome.GetError().GetExceptionName()},
|
||||
std::string{Outcome.GetError().GetMessage()}));
|
||||
return false;
|
||||
@@ -281,7 +284,7 @@ namespace OpenWifi {
|
||||
|
||||
// std::cout << "Count:" << Count << " Runs:" << Runs << std::endl;
|
||||
if(!Outcome.IsSuccess()) {
|
||||
Logger().error(fmt::format("Error while doing ListObjectsV2: {}, {}",
|
||||
poco_error(Logger(),fmt::format("Error while doing ListObjectsV2: {}, {}",
|
||||
std::string{Outcome.GetError().GetExceptionName()},
|
||||
std::string{Outcome.GetError().GetMessage()}));
|
||||
return false;
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
// Created by stephane bourque on 2021-06-02.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFWS_MANIFESTCREATOR_H
|
||||
#define UCENTRALFWS_MANIFESTCREATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <aws/core/Aws.h>
|
||||
#include <aws/s3/S3Client.h>
|
||||
#include <aws/core/auth/AWSCredentials.h>
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "Poco/Timer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -71,5 +70,3 @@ namespace OpenWifi {
|
||||
inline auto ManifestCreator() { return ManifestCreator::instance(); };
|
||||
|
||||
}
|
||||
|
||||
#endif //UCENTRALFWS_MANIFESTCREATOR_H
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
#include "NewCommandHandler.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "fmt/format.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void NewCommandHandler::run() {
|
||||
@@ -46,9 +50,9 @@ namespace OpenWifi {
|
||||
if(Command=="delete_device") {
|
||||
auto pSerialNumber = PayloadSection["payload"]["serialNumber"];
|
||||
if(pSerialNumber==SerialNumber) {
|
||||
Logger().debug(fmt::format("Removing device '{}' from upgrade history.",SerialNumber));
|
||||
poco_debug(Logger(),fmt::format("Removing device '{}' from upgrade history.",SerialNumber));
|
||||
StorageService()->HistoryDB().DeleteHistory(SerialNumber);
|
||||
Logger().debug(fmt::format("Removing device '{}' from device table.",SerialNumber));
|
||||
poco_debug(Logger(),fmt::format("Removing device '{}' from device table.",SerialNumber));
|
||||
StorageService()->DevicesDB().DeleteDevice(SerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// Created by stephane bourque on 2021-11-21.
|
||||
//
|
||||
|
||||
#ifndef OWFMS_NEWCOMMANDHANDLER_H
|
||||
#define OWFMS_NEWCOMMANDHANDLER_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -37,5 +36,3 @@ namespace OpenWifi {
|
||||
inline auto NewCommandHandler() { return NewCommandHandler::instance(); };
|
||||
|
||||
}
|
||||
|
||||
#endif //OWFMS_NEWCOMMANDHANDLER_H
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "DeviceCache.h"
|
||||
#include "AutoUpdater.h"
|
||||
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
/*
|
||||
{ "system" : { "id" : 6715803232063 , "host" : "https://localhost:17002" } ,
|
||||
"payload" : "{"capabilities":{"compatible":"linksys_ea8300","model":"Linksys EA8300 (Dallas)","network":{"lan":["eth0"],"wan":["eth1"]},"platform":"ap","switch":{"switch0":{"enable":true,"ports":[{"device":"eth0","need_tag":false,"num":0,"want_untag":true},{"num":1,"role":"lan"},{"num":2,"role":"lan"},{"num":3,"role":"lan"},{"num":4,"role":"lan"}],"reset":true,"roles":[{"device":"eth0","ports":"1 2 3 4 0","role":"lan"}]}},"wifi":{"platform/soc/a000000.wifi":{"band":["2G"],"channels":[1,2,3,4,5,6,7,8,9,10,11],"frequencies":[2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865687986},"platform/soc/a800000.wifi":{"band":["5G"],"channels":[36,40,44,48,52,56,60,64],"frequencies":[5180,5200,5220,5240,5260,5280,5300,5320],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865687986},"soc/40000000.pci/pci0000:00/0000:00:00.0/0000:01:00.0":{"band":["5G"],"channels":[100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165],"frequencies":[5500,5520,5540,5560,5580,5600,5620,5640,5660,5680,5700,5720,5745,5765,5785,5805,5825],"ht_capa":6639,"htmode":["HT20","HT40","VHT20","VHT40","VHT80"],"rx_ant":3,"tx_ant":3,"vht_capa":865696178}}},"firmware":"OpenWrt 21.02-SNAPSHOT r16011+53-6fd65c6573 / TIP-devel-0825cb93","serial":"24f5a207a130","uuid":1623866223}}
|
||||
@@ -68,12 +71,12 @@ namespace OpenWifi {
|
||||
if(StorageService()->FirmwaresDB().ComputeFirmwareAge(DeviceType, Revision, FA)) {
|
||||
StorageService()->DevicesDB().SetDeviceRevision(SerialNumber, Revision, DeviceType, EndPoint);
|
||||
if(FA.age)
|
||||
Logger().information(fmt::format("Device {} connection. Firmware is {} older than latest.",SerialNumber, Utils::SecondsToNiceText(FA.age)));
|
||||
poco_information(Logger(),fmt::format("Device {} connection. Firmware is {} older than latest.",SerialNumber, Utils::SecondsToNiceText(FA.age)));
|
||||
else
|
||||
Logger().information(fmt::format("Device {} connection. Device firmware is up to date.",SerialNumber));
|
||||
poco_information(Logger(),fmt::format("Device {} connection. Device firmware is up to date.",SerialNumber));
|
||||
}
|
||||
else {
|
||||
Logger().information(fmt::format("Device {} connection. Firmware age cannot be determined.",SerialNumber));
|
||||
poco_information(Logger(),fmt::format("Device {} connection. Firmware age cannot be determined.",SerialNumber));
|
||||
}
|
||||
|
||||
if(!LatestFirmwareCache()->IsLatest(DeviceType, Revision)) {
|
||||
@@ -116,6 +119,7 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
int NewConnectionHandler::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
Types::TopicNotifyFunction F = [this](std::string s1,std::string s2) { this->ConnectionReceived(s1,s2); };
|
||||
ConnectionWatcherId_ = KafkaManager()->RegisterTopicWatcher(KafkaTopics::CONNECTION, F);
|
||||
Worker_.start(*this);
|
||||
@@ -123,10 +127,12 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
void NewConnectionHandler::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
KafkaManager()->UnregisterTopicWatcher(KafkaTopics::CONNECTION, ConnectionWatcherId_);
|
||||
Running_ = false;
|
||||
Worker_.wakeUp();
|
||||
Worker_.join();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
};
|
||||
|
||||
bool NewConnectionHandler::Update() {
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
// Created by stephane bourque on 2021-07-13.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALFMS_NEWCONNECTIONHANDLER_H
|
||||
#define UCENTRALFMS_NEWCONNECTIONHANDLER_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -40,4 +38,3 @@ namespace OpenWifi {
|
||||
inline auto NewConnectionHandler() { return NewConnectionHandler::instance(); };
|
||||
}
|
||||
|
||||
#endif //UCENTRALFMS_NEWCONNECTIONHANDLER_H
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by stephane bourque on 2021-10-23.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
#include "RESTAPI/RESTAPI_firmwareHandler.h"
|
||||
#include "RESTAPI/RESTAPI_firmwaresHandler.h"
|
||||
#include "RESTAPI/RESTAPI_firmwareAgeHandler.h"
|
||||
@@ -12,11 +11,13 @@
|
||||
#include "RESTAPI/RESTAPI_historyHandler.h"
|
||||
#include "RESTAPI/RESTAPI_deviceReportHandler.h"
|
||||
#include "RESTAPI/RESTAPI_deviceInformation_handler.h"
|
||||
#include "framework/RESTAPI_SystemCommand.h"
|
||||
#include "framework/RESTAPI_WebSocketServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
||||
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t TransactionId) {
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_firmwaresHandler,
|
||||
RESTAPI_firmwareHandler,
|
||||
@@ -26,12 +27,13 @@ namespace OpenWifi {
|
||||
RESTAPI_connectedDeviceHandler,
|
||||
RESTAPI_historyHandler,
|
||||
RESTAPI_deviceReportHandler,
|
||||
RESTAPI_deviceInformation_handler
|
||||
RESTAPI_deviceInformation_handler,
|
||||
RESTAPI_webSocketServer
|
||||
>(Path,Bindings,L, S, TransactionId);
|
||||
}
|
||||
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S, uint64_t TransactionId) {
|
||||
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t TransactionId) {
|
||||
return RESTAPI_Router_I<
|
||||
RESTAPI_firmwaresHandler,
|
||||
RESTAPI_firmwareHandler,
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#ifndef UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
|
||||
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_connectedDeviceHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_connectedDeviceHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_connectedDeviceHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICESHANDLER_H
|
||||
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_connectedDevicesHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_connectedDevicesHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_connectedDevicesHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_deviceInformation_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_deviceInformation_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_deviceInformation_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_deviceReportHandler::DoGet() {
|
||||
Daemon()->CreateDashboard();
|
||||
Poco::JSON::Object O;
|
||||
Daemon()->GetDashboard().to_json(O);
|
||||
ReturnObject(O);
|
||||
poco_information(Logger(),fmt::format("GET-DASHBOARD: {}", Requester()));
|
||||
FMSObjects::DeviceReport Data;
|
||||
if(Daemon()->GetDashboard().Get(Data, Logger())) {
|
||||
Poco::JSON::Object Answer;
|
||||
Data.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
return BadRequest(RESTAPI::Errors::InternalError);
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_deviceReportHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_deviceReportHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_deviceReportHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#ifndef UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
|
||||
#define UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_firmwareAgeHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_firmwareAgeHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_firmwareAgeHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "RESTAPI_firmwareHandler.h"
|
||||
#include "RESTAPI/RESTAPI_firmwareHandler.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void
|
||||
@@ -16,7 +18,7 @@ namespace OpenWifi {
|
||||
if (!F.from_json(Obj)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
F.id = MicroService::instance().CreateUUID();
|
||||
F.id = MicroServiceCreateUUID();
|
||||
if(StorageService()->FirmwaresDB().AddFirmware(F)) {
|
||||
Poco::JSON::Object Answer;
|
||||
F.to_json(Answer);
|
||||
@@ -78,7 +80,7 @@ namespace OpenWifi {
|
||||
SecurityObjects::NoteInfoVec NIV;
|
||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get(RESTAPI::Protocol::NOTES).toString());
|
||||
for(auto const &i:NIV) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UserInfo_.userinfo.email, .note=i.note};
|
||||
F.notes.push_back(ii);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#ifndef UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
|
||||
#define UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_firmwareHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_firmwareHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_firmwareHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
#ifndef UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
|
||||
#define UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_firmwaresHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_firmwaresHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_firmwaresHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_historyHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_historyHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
RESTAPI_historyHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "RESTAPI_AnalyticsObjects.h"
|
||||
#include "RESTAPI_ProvObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "RESTAPI_ProvObjects.h"
|
||||
#include "framework/utils.h"
|
||||
#include <vector>
|
||||
|
||||
namespace OpenWifi {
|
||||
@@ -375,7 +376,7 @@ namespace OpenWifi {
|
||||
};
|
||||
|
||||
struct WifiClientHistory {
|
||||
uint64_t timestamp=OpenWifi::Now();
|
||||
uint64_t timestamp=Utils::Now();
|
||||
std::string station_id;
|
||||
std::string bssid;
|
||||
std::string ssid;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_CertObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
@@ -154,6 +154,7 @@ namespace OpenWifi::CertObjects {
|
||||
field_to_json(Obj,"submitted", submitted);
|
||||
field_to_json(Obj,"started", started);
|
||||
field_to_json(Obj,"completed", completed);
|
||||
field_to_json(Obj,"requesterUsername", requesterUsername);
|
||||
}
|
||||
|
||||
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -171,6 +172,7 @@ namespace OpenWifi::CertObjects {
|
||||
field_from_json(Obj,"submitted", submitted);
|
||||
field_from_json(Obj,"started", started);
|
||||
field_from_json(Obj,"completed", completed);
|
||||
field_from_json(Obj,"requesterUsername", requesterUsername);
|
||||
return true;
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ namespace OpenWifi::CertObjects {
|
||||
uint64_t submitted=0;
|
||||
uint64_t started=0;
|
||||
uint64_t completed=0;
|
||||
std::string requesterUsername;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_FMSObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
@@ -233,7 +234,7 @@ namespace OpenWifi::FMSObjects {
|
||||
UnknownFirmwares_.clear();
|
||||
totalSecondsOld_.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = OpenWifi::Now();
|
||||
snapshot = Utils::Now();
|
||||
}
|
||||
|
||||
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
|
||||
#include "Daemon.h"
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
#include "DeviceRegistry.h"
|
||||
#include "AP_WS_Server.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#endif
|
||||
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
@@ -49,6 +50,10 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"entity", entity);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"locale", locale);
|
||||
field_to_json(Obj,"restrictedDevice", restrictedDevice);
|
||||
field_to_json(Obj,"pendingConfiguration", pendingConfiguration);
|
||||
field_to_json(Obj,"pendingConfigurationCmd", pendingConfigurationCmd);
|
||||
field_to_json(Obj,"restrictionDetails", restrictionDetails);
|
||||
}
|
||||
|
||||
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||
@@ -57,7 +62,7 @@ namespace OpenWifi::GWObjects {
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
ConnectionState ConState;
|
||||
|
||||
if (DeviceRegistry()->GetState(SerialNumber, ConState)) {
|
||||
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
|
||||
ConState.to_json(Obj);
|
||||
} else {
|
||||
field_to_json(Obj,"ipAddress", "");
|
||||
@@ -69,6 +74,7 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
|
||||
field_to_json(Obj,"associations_2G", (uint64_t) 0);
|
||||
field_to_json(Obj,"associations_5G", (uint64_t) 0);
|
||||
field_to_json(Obj,"associations_6G", (uint64_t) 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -88,6 +94,10 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"subscriber", subscriber);
|
||||
field_from_json(Obj,"entity", entity);
|
||||
field_from_json(Obj,"locale", locale);
|
||||
field_from_json(Obj,"restrictedDevice", restrictedDevice);
|
||||
field_from_json(Obj,"pendingConfiguration", pendingConfiguration);
|
||||
field_from_json(Obj,"pendingConfigurationCmd", pendingConfigurationCmd);
|
||||
field_from_json(Obj,"restrictionDetails", restrictionDetails);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -198,11 +208,17 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"lastContact", LastContact);
|
||||
field_to_json(Obj,"associations_2G", Associations_2G);
|
||||
field_to_json(Obj,"associations_5G", Associations_5G);
|
||||
field_to_json(Obj,"associations_6G", Associations_6G);
|
||||
field_to_json(Obj,"webSocketClients", webSocketClients);
|
||||
field_to_json(Obj,"websocketPackets", websocketPackets);
|
||||
field_to_json(Obj,"kafkaClients", kafkaClients);
|
||||
field_to_json(Obj,"kafkaPackets", kafkaPackets);
|
||||
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", Utils::Now() - started);
|
||||
field_to_json(Obj,"certificateExpiryDate", certificateExpiryDate);
|
||||
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
@@ -218,6 +234,23 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_to_json(Obj,"connectedDevices", connectedDevices );
|
||||
field_to_json(Obj,"connectingDevices", connectingDevices );
|
||||
}
|
||||
|
||||
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||
field_from_json(Obj,"connectedDevices", connectedDevices );
|
||||
field_from_json(Obj,"connectingDevices", connectingDevices );
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
field_to_json(Obj,"server", Server);
|
||||
@@ -264,7 +297,7 @@ namespace OpenWifi::GWObjects {
|
||||
lastContact.clear();
|
||||
associations.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = OpenWifi::Now();
|
||||
snapshot = Utils::Now();
|
||||
}
|
||||
|
||||
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
|
||||
@@ -276,9 +309,12 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"serialNumber",serialNumber);
|
||||
field_to_json(Obj,"timeout",timeout);
|
||||
field_to_json(Obj,"type",type);
|
||||
field_to_json(Obj,"script",script);
|
||||
field_to_json(Obj,"scriptId",scriptId);
|
||||
field_to_json(Obj,"script",script);
|
||||
field_to_json(Obj,"when",when);
|
||||
field_to_json(Obj,"signature", signature);
|
||||
field_to_json(Obj,"deferred", deferred);
|
||||
field_to_json(Obj,"uri", uri);
|
||||
}
|
||||
|
||||
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -289,11 +325,13 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"script",script);
|
||||
field_from_json(Obj,"scriptId",scriptId);
|
||||
field_from_json(Obj,"when",when);
|
||||
field_from_json(Obj,"signature", signature);
|
||||
field_from_json(Obj,"deferred", deferred);
|
||||
field_from_json(Obj,"uri", uri);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
|
||||
@@ -314,6 +352,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"description",description);
|
||||
field_to_json(Obj,"authConfig",authConfig);
|
||||
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) {
|
||||
@@ -322,6 +362,8 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"description",description);
|
||||
field_from_json(Obj,"authConfig",authConfig);
|
||||
field_from_json(Obj,"acctConfig",acctConfig);
|
||||
field_from_json(Obj,"coaConfig",coaConfig);
|
||||
field_from_json(Obj,"useByDefault",useByDefault);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
@@ -329,7 +371,7 @@ namespace OpenWifi::GWObjects {
|
||||
}
|
||||
|
||||
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,"monitorMethod",monitorMethod);
|
||||
field_to_json(Obj,"methodParameters",methodParameters);
|
||||
@@ -338,7 +380,7 @@ namespace OpenWifi::GWObjects {
|
||||
|
||||
bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"policy",strategy);
|
||||
field_from_json(Obj,"strategy",strategy);
|
||||
field_from_json(Obj,"monitor",monitor);
|
||||
field_from_json(Obj,"monitorMethod",monitorMethod);
|
||||
field_from_json(Obj,"methodParameters",methodParameters);
|
||||
@@ -354,6 +396,17 @@ namespace OpenWifi::GWObjects {
|
||||
field_to_json(Obj,"ip",ip);
|
||||
field_to_json(Obj,"port",port);
|
||||
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,"allowSelfSigned",allowSelfSigned);
|
||||
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) {
|
||||
@@ -362,10 +415,133 @@ namespace OpenWifi::GWObjects {
|
||||
field_from_json(Obj,"ip",ip);
|
||||
field_from_json(Obj,"port",port);
|
||||
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,"allowSelfSigned",allowSelfSigned);
|
||||
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;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"id", id);
|
||||
field_to_json(Obj,"name", name);
|
||||
field_to_json(Obj,"description", description);
|
||||
field_to_json(Obj,"uri", uri);
|
||||
field_to_json(Obj,"content", content);
|
||||
field_to_json(Obj,"version", version);
|
||||
field_to_json(Obj,"type", type);
|
||||
field_to_json(Obj,"created", created);
|
||||
field_to_json(Obj,"modified", modified);
|
||||
field_to_json(Obj,"author", author);
|
||||
field_to_json(Obj,"restricted", restricted);
|
||||
field_to_json(Obj,"deferred", deferred);
|
||||
field_to_json(Obj,"timeout", timeout);
|
||||
field_to_json(Obj,"defaultUploadURI", defaultUploadURI);
|
||||
}
|
||||
|
||||
bool ScriptEntry::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,"description", description);
|
||||
field_from_json(Obj,"uri", uri);
|
||||
field_from_json(Obj,"content", content);
|
||||
field_from_json(Obj,"version", version);
|
||||
field_from_json(Obj,"type", type);
|
||||
field_from_json(Obj,"created", created);
|
||||
field_from_json(Obj,"modified", modified);
|
||||
field_from_json(Obj,"author", author);
|
||||
field_from_json(Obj,"restricted", restricted);
|
||||
field_from_json(Obj,"deferred", deferred);
|
||||
field_from_json(Obj,"timeout", timeout);
|
||||
field_from_json(Obj,"defaultUploadURI", defaultUploadURI);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptEntryList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"scripts",scripts);
|
||||
}
|
||||
|
||||
bool ScriptEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"scripts",scripts);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRestrictionsKeyInfo::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"vendor", vendor);
|
||||
field_to_json(Obj,"algo", algo);
|
||||
}
|
||||
|
||||
bool DeviceRestrictionsKeyInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"vendor", vendor);
|
||||
field_from_json(Obj,"algo", algo);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void DeviceRestrictions::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"dfs", dfs);
|
||||
field_to_json(Obj,"ssh", ssh);
|
||||
field_to_json(Obj,"rtty", rtty);
|
||||
field_to_json(Obj,"tty", tty);
|
||||
field_to_json(Obj,"developer", developer);
|
||||
field_to_json(Obj,"upgrade", upgrade);
|
||||
field_to_json(Obj,"commands", commands);
|
||||
field_to_json(Obj,"country", country);
|
||||
field_to_json(Obj,"key_info", key_info);
|
||||
}
|
||||
|
||||
bool DeviceRestrictions::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"dfs", dfs);
|
||||
field_from_json(Obj,"ssh", ssh);
|
||||
field_from_json(Obj,"rtty", rtty);
|
||||
field_from_json(Obj,"tty", tty);
|
||||
field_from_json(Obj,"developer", developer);
|
||||
field_from_json(Obj,"upgrade", upgrade);
|
||||
field_from_json(Obj,"commands", commands);
|
||||
field_from_json(Obj,"country", country);
|
||||
field_from_json(Obj,"key_info", key_info);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceRestrictionsKeyInfo::operator!=(const OpenWifi::GWObjects::DeviceRestrictionsKeyInfo &T) const {
|
||||
return (T.algo!=algo) || (T.vendor!=vendor);
|
||||
}
|
||||
|
||||
bool DeviceRestrictions::operator!=(const OpenWifi::GWObjects::DeviceRestrictions &T) const {
|
||||
return ( (T.dfs!=dfs) ||
|
||||
(T.rtty!=rtty) ||
|
||||
(T.upgrade!=upgrade) ||
|
||||
(T.commands != commands) ||
|
||||
(T.developer != developer) ||
|
||||
(T.ssh !=ssh) ||
|
||||
(T.key_info != key_info) ||
|
||||
(T.country != country) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,19 +28,52 @@ namespace OpenWifi::GWObjects {
|
||||
uint64_t TX = 0, RX = 0;
|
||||
uint64_t Associations_2G=0;
|
||||
uint64_t Associations_5G=0;
|
||||
uint64_t Associations_6G=0;
|
||||
bool Connected = false;
|
||||
uint64_t LastContact=0;
|
||||
std::string Firmware;
|
||||
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
|
||||
std::string Compatible;
|
||||
uint64_t kafkaClients=0;
|
||||
uint64_t webSocketClients=0;
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
std::string Compatible;
|
||||
uint64_t kafkaClients=0;
|
||||
uint64_t webSocketClients=0;
|
||||
uint64_t kafkaPackets=0;
|
||||
uint64_t websocketPackets=0;
|
||||
std::string locale;
|
||||
uint64_t started=0;
|
||||
uint64_t sessionId=0;
|
||||
double connectionCompletionTime=0.0;
|
||||
std::uint64_t certificateExpiryDate=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct DeviceRestrictionsKeyInfo {
|
||||
std::string vendor;
|
||||
std::string algo;
|
||||
|
||||
bool operator !=(const DeviceRestrictionsKeyInfo &b) const;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceRestrictions {
|
||||
bool dfs = false;
|
||||
bool ssh = false;
|
||||
bool rtty = false;
|
||||
bool tty = false;
|
||||
bool developer = false;
|
||||
bool upgrade = false;
|
||||
bool commands = false;
|
||||
std::vector<std::string> country;
|
||||
DeviceRestrictionsKeyInfo key_info;
|
||||
|
||||
bool operator !=(const DeviceRestrictions &D) const;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Device {
|
||||
std::string SerialNumber;
|
||||
std::string DeviceType;
|
||||
@@ -64,6 +97,10 @@ namespace OpenWifi::GWObjects {
|
||||
std::string entity;
|
||||
uint64_t modified=0;
|
||||
std::string locale;
|
||||
bool restrictedDevice=false;
|
||||
std::string pendingConfiguration;
|
||||
std::string pendingConfigurationCmd;
|
||||
DeviceRestrictions restrictionDetails;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||
@@ -71,6 +108,15 @@ namespace OpenWifi::GWObjects {
|
||||
void Print() const;
|
||||
};
|
||||
|
||||
struct DeviceConnectionStatistics {
|
||||
std::uint64_t connectedDevices = 0;
|
||||
std::uint64_t averageConnectionTime = 0;
|
||||
std::uint64_t connectingDevices = 0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID = 0 ;
|
||||
@@ -200,13 +246,44 @@ namespace OpenWifi::GWObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct ScriptEntry {
|
||||
std::string id;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string uri;
|
||||
std::string content;
|
||||
std::string version;
|
||||
std::string type;
|
||||
std::uint64_t created;
|
||||
std::uint64_t modified;
|
||||
std::string author;
|
||||
Types::StringVec restricted;
|
||||
bool deferred=false;
|
||||
std::uint64_t timeout=30;
|
||||
std::string defaultUploadURI;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ScriptEntryList {
|
||||
std::vector<ScriptEntry> scripts;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ScriptRequest {
|
||||
uint64_t timeout=30;
|
||||
std::string serialNumber;
|
||||
uint64_t timeout=30;
|
||||
std::string type;
|
||||
std::string script;
|
||||
std::string scriptId;
|
||||
uint64_t when=0;
|
||||
std::uint64_t when;
|
||||
std::string signature;
|
||||
bool deferred;
|
||||
std::string uri;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -216,6 +293,17 @@ namespace OpenWifi::GWObjects {
|
||||
std::string ip;
|
||||
uint16_t port=0;
|
||||
uint64_t weight=0;
|
||||
std::string secret;
|
||||
std::string certificate;
|
||||
bool radsec=false;
|
||||
bool allowSelfSigned=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;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -237,6 +325,8 @@ namespace OpenWifi::GWObjects {
|
||||
std::string description;
|
||||
RadiusProxyServerConfig authConfig;
|
||||
RadiusProxyServerConfig acctConfig;
|
||||
RadiusProxyServerConfig coaConfig;
|
||||
bool useByDefault=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -248,4 +338,5 @@ namespace OpenWifi::GWObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
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/RESTAPI_utils.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
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
|
||||
#include "RESTAPI_ProvObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
@@ -600,6 +602,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_to_json( Obj, "devClass",devClass);
|
||||
field_to_json( Obj, "locale",locale);
|
||||
field_to_json( Obj, "realMacAddress",realMacAddress);
|
||||
field_to_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
|
||||
}
|
||||
|
||||
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -621,6 +624,7 @@ namespace OpenWifi::ProvObjects {
|
||||
field_from_json( Obj,"devClass",devClass);
|
||||
field_from_json( Obj,"locale",locale);
|
||||
field_from_json( Obj,"realMacAddress",realMacAddress);
|
||||
field_from_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
@@ -1091,7 +1095,7 @@ namespace OpenWifi::ProvObjects {
|
||||
}
|
||||
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
uint64_t Now = Utils::Now();
|
||||
if(O->has("name"))
|
||||
I.name = O->get("name").toString();
|
||||
|
||||
@@ -1112,7 +1116,7 @@ namespace OpenWifi::ProvObjects {
|
||||
}
|
||||
|
||||
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
||||
uint64_t Now = OpenWifi::Now();
|
||||
uint64_t Now = Utils::Now();
|
||||
if(O->has("name"))
|
||||
I.name = O->get("name").toString();
|
||||
|
||||
@@ -1130,14 +1134,14 @@ namespace OpenWifi::ProvObjects {
|
||||
}
|
||||
I.notes = N;
|
||||
I.modified = I.created = Now;
|
||||
I.id = MicroService::CreateUUID();
|
||||
I.id = MicroServiceCreateUUID();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
||||
I.modified = I.created = OpenWifi::Now();
|
||||
I.id = MicroService::CreateUUID();
|
||||
I.modified = I.created = Utils::Now();
|
||||
I.id = MicroServiceCreateUUID();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1159,5 +1163,82 @@ namespace OpenWifi::ProvObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
void RRMAlgorithmDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"name",name);
|
||||
field_to_json(Obj,"parameters",parameters);
|
||||
}
|
||||
|
||||
bool RRMAlgorithmDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"name",name);
|
||||
field_from_json(Obj,"parameters",parameters);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RRMDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"vendor",vendor);
|
||||
field_to_json(Obj,"schedule",schedule);
|
||||
field_to_json(Obj,"algorithms",algorithms);
|
||||
}
|
||||
|
||||
bool RRMDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"vendor",vendor);
|
||||
field_from_json(Obj,"schedule",schedule);
|
||||
field_from_json(Obj,"algorithms",algorithms);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfigurationOverride::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"source",source);
|
||||
field_to_json(Obj,"reason",reason);
|
||||
field_to_json(Obj,"parameterName",parameterName);
|
||||
field_to_json(Obj,"parameterType",parameterType);
|
||||
field_to_json(Obj,"parameterValue",parameterValue);
|
||||
field_to_json(Obj,"modified",modified);
|
||||
}
|
||||
|
||||
bool ConfigurationOverride::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"source",source);
|
||||
field_from_json(Obj,"reason",reason);
|
||||
field_from_json(Obj,"parameterName",parameterName);
|
||||
field_from_json(Obj,"parameterType",parameterType);
|
||||
field_from_json(Obj,"parameterValue",parameterValue);
|
||||
field_from_json(Obj,"modified",modified);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConfigurationOverrideList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber",serialNumber);
|
||||
field_to_json(Obj,"managementPolicy",managementPolicy);
|
||||
field_to_json(Obj,"overrides",overrides);
|
||||
}
|
||||
|
||||
bool ConfigurationOverrideList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj,"serialNumber",serialNumber);
|
||||
field_from_json(Obj,"managementPolicy",managementPolicy);
|
||||
field_from_json(Obj,"overrides",overrides);
|
||||
return true;
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi::ProvObjects {
|
||||
|
||||
@@ -62,6 +61,21 @@ namespace OpenWifi::ProvObjects {
|
||||
};
|
||||
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
||||
|
||||
struct RRMAlgorithmDetails {
|
||||
std::string name;
|
||||
std::string parameters;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct RRMDetails {
|
||||
std::string vendor;
|
||||
std::string schedule;
|
||||
std::vector<RRMAlgorithmDetails> algorithms;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct DeviceRules {
|
||||
std::string rcOnly{"inherit"};
|
||||
std::string rrm{"inherit"};
|
||||
@@ -414,6 +428,7 @@ namespace OpenWifi::ProvObjects {
|
||||
std::string devClass;
|
||||
std::string locale;
|
||||
std::string realMacAddress;
|
||||
bool doNotAllowOverrides=false;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -679,6 +694,27 @@ namespace OpenWifi::ProvObjects {
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ConfigurationOverride {
|
||||
std::string source;
|
||||
std::string reason;
|
||||
std::string parameterName;
|
||||
std::string parameterType;
|
||||
std::string parameterValue;
|
||||
std::uint64_t modified;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ConfigurationOverrideList {
|
||||
std::string serialNumber;
|
||||
Types::UUID_t managementPolicy;
|
||||
std::vector<ConfigurationOverride> overrides;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
@@ -433,7 +433,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
SecurityObjects::NoteInfoVec NIV;
|
||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
|
||||
for(auto const &i:NIV) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
Notes.push_back(ii);
|
||||
}
|
||||
}
|
||||
@@ -446,7 +446,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
|
||||
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
|
||||
for(auto const &i:NewNotes) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UInfo.email, .note=i.note};
|
||||
ExistingNotes.push_back(ii);
|
||||
}
|
||||
return true;
|
||||
@@ -619,5 +619,80 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"login",login);
|
||||
field_to_json(Obj,"logout",logout);
|
||||
}
|
||||
|
||||
void ApiKeyAccessRight::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "service", service);
|
||||
field_to_json(Obj, "access", access);
|
||||
}
|
||||
|
||||
bool ApiKeyAccessRight::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "service", service);
|
||||
field_from_json(Obj, "access", access);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApiKeyAccessRightList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "acls", acls);
|
||||
}
|
||||
|
||||
bool ApiKeyAccessRightList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "acls", acls);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApiKeyEntry::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "id", id);
|
||||
field_to_json(Obj, "userUuid", userUuid);
|
||||
field_to_json(Obj, "name", name);
|
||||
field_to_json(Obj, "apiKey", apiKey);
|
||||
field_to_json(Obj, "salt", salt);
|
||||
field_to_json(Obj, "description", description);
|
||||
field_to_json(Obj, "expiresOn", expiresOn);
|
||||
field_to_json(Obj, "rights", rights);
|
||||
field_to_json(Obj, "lastUse", lastUse);
|
||||
}
|
||||
|
||||
bool ApiKeyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "id", id);
|
||||
field_from_json(Obj, "userUuid", userUuid);
|
||||
field_from_json(Obj, "name", name);
|
||||
field_from_json(Obj, "apiKey", apiKey);
|
||||
field_from_json(Obj, "salt", salt);
|
||||
field_from_json(Obj, "description", description);
|
||||
field_from_json(Obj, "expiresOn", expiresOn);
|
||||
field_from_json(Obj, "rights", rights);
|
||||
field_from_json(Obj, "lastUse", lastUse);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApiKeyEntryList::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj, "apiKeys", apiKeys);
|
||||
}
|
||||
|
||||
bool ApiKeyEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
try {
|
||||
field_from_json(Obj, "apiKeys", apiKeys);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Data/LOB.h"
|
||||
#include "Poco/Data/LOBStream.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
uint64_t Now();
|
||||
@@ -62,7 +63,7 @@ namespace OpenWifi {
|
||||
std::string UserTypeToString(USER_ROLE U);
|
||||
|
||||
struct NoteInfo {
|
||||
uint64_t created=0; // = OpenWifi::Now();
|
||||
uint64_t created=0; // = Utils::Now();
|
||||
std::string createdBy;
|
||||
std::string note;
|
||||
|
||||
@@ -101,7 +102,7 @@ namespace OpenWifi {
|
||||
std::string uuid;
|
||||
std::string question;
|
||||
std::string method;
|
||||
uint64_t created = OpenWifi::Now();
|
||||
uint64_t created = Utils::Now();
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -251,7 +252,8 @@ namespace OpenWifi {
|
||||
VERIFY_EMAIL,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_VERIFY_EMAIL,
|
||||
SUB_SIGNUP
|
||||
SUB_SIGNUP,
|
||||
EMAIL_INVITATION
|
||||
};
|
||||
|
||||
struct ActionLink {
|
||||
@@ -263,7 +265,7 @@ namespace OpenWifi {
|
||||
std::string locale;
|
||||
std::string message;
|
||||
uint64_t sent=0;
|
||||
uint64_t created=OpenWifi::Now();
|
||||
uint64_t created=Utils::Now();
|
||||
uint64_t expires=0;
|
||||
uint64_t completed=0;
|
||||
uint64_t canceled=0;
|
||||
@@ -323,5 +325,44 @@ namespace OpenWifi {
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
|
||||
struct ApiKeyAccessRight {
|
||||
std::string service;
|
||||
std::string access;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ApiKeyAccessRightList {
|
||||
std::vector<ApiKeyAccessRight> acls;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ApiKeyEntry {
|
||||
Types::UUID_t id;
|
||||
Types::UUID_t userUuid;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string apiKey;
|
||||
std::string salt;
|
||||
std::uint64_t created;
|
||||
std::uint64_t expiresOn=0;
|
||||
ApiKeyAccessRightList rights;
|
||||
std::uint64_t lastUse=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
struct ApiKeyEntryList {
|
||||
std::vector<ApiKeyEntry> apiKeys;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
//
|
||||
|
||||
#include "RESTAPI_SubObjects.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
|
||||
|
||||
namespace OpenWifi::SubObjects {
|
||||
|
||||
void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const {
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
//
|
||||
|
||||
#include "GW_SDK.h"
|
||||
#include "Daemon.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
|
||||
#include "framework/MicroServiceNames.h"
|
||||
#include "framework/OpenAPIRequests.h"
|
||||
|
||||
namespace OpenWifi::SDK::GW {
|
||||
|
||||
bool SendFirmwareUpgradeCommand( const std::string & serialNumber, const std::string & URI, [[maybe_unused]] uint64_t When ) {
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
// Created by stephane bourque on 2021-10-05.
|
||||
//
|
||||
|
||||
#ifndef OWFMS_GW_SDK_H
|
||||
#define OWFMS_GW_SDK_H
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <string>
|
||||
|
||||
namespace OpenWifi::SDK::GW {
|
||||
|
||||
@@ -14,4 +12,3 @@ namespace OpenWifi::SDK::GW {
|
||||
|
||||
};
|
||||
|
||||
#endif //OWFMS_GW_SDK_H
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// Created by stephane bourque on 2021-10-04.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/OpenAPIRequests.h"
|
||||
#include "framework/MicroServiceNames.h"
|
||||
|
||||
namespace OpenWifi::SDK::Prov {
|
||||
bool GetFirmwareOptions( const std::string & serialNumber, std::string &firmwareUpgrade,
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// Created by stephane bourque on 2021-10-04.
|
||||
//
|
||||
|
||||
#ifndef OWFMS_PROV_SDK_H
|
||||
#define OWFMS_PROV_SDK_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include <string>
|
||||
|
||||
namespace OpenWifi::SDK::Prov {
|
||||
|
||||
@@ -14,5 +13,3 @@ namespace OpenWifi::SDK::Prov {
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //OWFMS_PROV_SDK_H
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace OpenWifi {
|
||||
|
||||
int Storage::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
StorageClass::Start();
|
||||
@@ -27,9 +28,10 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
void Storage::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger().notice("Stopping.");
|
||||
StorageClass::Stop();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
std::string Storage::TrimRevision(const std::string &R) {
|
||||
|
||||
@@ -6,10 +6,8 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRAL_USTORAGESERVICE_H
|
||||
#define UCENTRAL_USTORAGESERVICE_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/StorageClass.h"
|
||||
|
||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||
@@ -53,4 +51,3 @@ namespace OpenWifi {
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif //UCENTRAL_USTORAGESERVICE_H
|
||||
|
||||
77
src/framework/ALBserver.cpp
Normal file
77
src/framework/ALBserver.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "ALBserver.h"
|
||||
|
||||
#include "framework/utils.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void ALBRequestHandler::handleRequest([[maybe_unused]] Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) {
|
||||
Utils::SetThreadName("alb-request");
|
||||
try {
|
||||
if((id_ % 100) == 0) {
|
||||
Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", Request.clientAddress().toString(), id_));
|
||||
}
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("text/html");
|
||||
Response.setDate(Poco::Timestamp());
|
||||
Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
|
||||
Response.setKeepAlive(true);
|
||||
Response.set("Connection", "keep-alive");
|
||||
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
std::ostream &Answer = Response.send();
|
||||
Answer << "process Alive and kicking!";
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ALBRequestHandlerFactory::ALBRequestHandlerFactory(Poco::Logger & L):
|
||||
Logger_(L) {
|
||||
}
|
||||
|
||||
ALBRequestHandler* ALBRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) {
|
||||
if (request.getURI() == "/")
|
||||
return new ALBRequestHandler(Logger_, req_id_++);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ALBHealthCheckServer::ALBHealthCheckServer() :
|
||||
SubSystemServer("ALBHealthCheckServer", "ALB-SVR", "alb")
|
||||
{
|
||||
}
|
||||
|
||||
int ALBHealthCheckServer::Start() {
|
||||
if(MicroServiceConfigGetBool("alb.enable",false)) {
|
||||
poco_information(Logger(),"Starting...");
|
||||
Running_=true;
|
||||
Port_ = (int)MicroServiceConfigGetInt("alb.port",15015);
|
||||
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
|
||||
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
|
||||
: Poco::Net::AddressFamily::IPv4));
|
||||
Poco::Net::SocketAddress SockAddr(Addr, Port_);
|
||||
Poco::Net::ServerSocket ClientSocket(SockAddr, 64);
|
||||
|
||||
Socket_ = std::make_unique<Poco::Net::ServerSocket>(SockAddr, Port_);
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setName("ws:alb");
|
||||
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
|
||||
Server_->start();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ALBHealthCheckServer::Stop() {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
if(Running_)
|
||||
Server_->stopAll(true);
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
63
src/framework/ALBserver.h
Normal file
63
src/framework/ALBserver.h
Normal file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class ALBRequestHandler: public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit ALBRequestHandler(Poco::Logger & L, uint64_t id)
|
||||
: Logger_(L), id_(id) {
|
||||
}
|
||||
|
||||
void handleRequest([[maybe_unused]] Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override;
|
||||
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
uint64_t id_;
|
||||
};
|
||||
|
||||
class ALBRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory
|
||||
{
|
||||
public:
|
||||
explicit ALBRequestHandlerFactory(Poco::Logger & L);
|
||||
ALBRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request) override;
|
||||
|
||||
private:
|
||||
Poco::Logger &Logger_;
|
||||
inline static std::atomic_uint64_t req_id_=1;
|
||||
};
|
||||
|
||||
class ALBHealthCheckServer : public SubSystemServer {
|
||||
public:
|
||||
ALBHealthCheckServer();
|
||||
|
||||
static auto instance() {
|
||||
static auto instance = new ALBHealthCheckServer;
|
||||
return instance;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Poco::Net::HTTPServer> Server_;
|
||||
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
|
||||
int Port_ = 0;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
};
|
||||
|
||||
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/Net/HTTPSClientSession.h"
|
||||
#include "Poco/URI.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
inline void API_Proxy( Poco::Logger &Logger,
|
||||
@@ -15,7 +21,7 @@ namespace OpenWifi {
|
||||
const char * PathRewrite,
|
||||
uint64_t msTimeout_ = 10000 ) {
|
||||
try {
|
||||
auto Services = MicroService::instance().GetServices(ServiceType);
|
||||
auto Services = MicroServiceGetServices(ServiceType);
|
||||
for(auto const &Svc:Services) {
|
||||
Poco::URI SourceURI(Request->getURI());
|
||||
Poco::URI DestinationURI(Svc.PrivateEndPoint);
|
||||
@@ -35,7 +41,7 @@ namespace OpenWifi {
|
||||
ProxyRequest.add("Authorization", Request->get("Authorization"));
|
||||
} else {
|
||||
ProxyRequest.add("X-API-KEY", Svc.AccessKey);
|
||||
ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint());
|
||||
ProxyRequest.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
|
||||
}
|
||||
|
||||
if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
|
||||
|
||||
102
src/framework/AppServiceRegistry.h
Normal file
102
src/framework/AppServiceRegistry.h
Normal file
@@ -0,0 +1,102 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "Poco/StreamCopier.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
|
||||
class AppServiceRegistry {
|
||||
public:
|
||||
AppServiceRegistry() {
|
||||
FileName = MicroServiceDataDirectory() + "/registry.json";
|
||||
Poco::File F(FileName);
|
||||
|
||||
try {
|
||||
if(F.exists()) {
|
||||
std::ostringstream OS;
|
||||
std::ifstream IF(FileName);
|
||||
Poco::StreamCopier::copyStream(IF, OS);
|
||||
Registry_ = nlohmann::json::parse(OS.str());
|
||||
}
|
||||
} catch (...) {
|
||||
Registry_ = nlohmann::json::parse("{}");
|
||||
}
|
||||
}
|
||||
|
||||
static AppServiceRegistry & instance() {
|
||||
static auto instance_= new AppServiceRegistry;
|
||||
return *instance_;
|
||||
}
|
||||
|
||||
inline ~AppServiceRegistry() {
|
||||
Save();
|
||||
}
|
||||
|
||||
inline void Save() {
|
||||
std::istringstream IS( to_string(Registry_));
|
||||
std::ofstream OF;
|
||||
OF.open(FileName,std::ios::binary | std::ios::trunc);
|
||||
Poco::StreamCopier::copyStream(IS, OF);
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, uint64_t Value ) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, const std::string &Value ) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline void Set(const char *Key, bool Value ) {
|
||||
Registry_[Key] = Value;
|
||||
Save();
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, bool & Value ) {
|
||||
if(Registry_[Key].is_boolean()) {
|
||||
Value = Registry_[Key].get<bool>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, uint64_t & Value ) {
|
||||
if(Registry_[Key].is_number_unsigned()) {
|
||||
Value = Registry_[Key].get<uint64_t>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Get(const char *Key, std::string & Value ) {
|
||||
if(Registry_[Key].is_string()) {
|
||||
Value = Registry_[Key].get<std::string>();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string FileName;
|
||||
nlohmann::json Registry_;
|
||||
};
|
||||
|
||||
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }
|
||||
|
||||
}
|
||||
129
src/framework/AuthClient.cpp
Normal file
129
src/framework/AuthClient.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
|
||||
#include "framework/AuthClient.h"
|
||||
#include "framework/MicroServiceNames.h"
|
||||
#include "framework/OpenAPIRequests.h"
|
||||
#include "framework/utils.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool AuthClient::RetrieveTokenInformation(const std::string & SessionToken,
|
||||
SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted, bool Sub) {
|
||||
try {
|
||||
Types::StringPairVec QueryData;
|
||||
QueryData.push_back(std::make_pair("token",SessionToken));
|
||||
std::string AlternateURIForLogging = fmt::format("{}?token={}", Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken", Utils::SanitizeToken(SessionToken));
|
||||
OpenAPIRequestGet Req( uSERVICE_SECURITY,
|
||||
Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken",
|
||||
QueryData,
|
||||
10000,
|
||||
AlternateURIForLogging
|
||||
);
|
||||
Poco::JSON::Object::Ptr Response;
|
||||
|
||||
auto StatusCode = Req.Do(Response);
|
||||
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
|
||||
Contacted = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Contacted = true;
|
||||
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
|
||||
if(Response->has("tokenInfo") && Response->has("userInfo")) {
|
||||
UInfo.from_json(Response);
|
||||
if(IsTokenExpired(UInfo.webtoken)) {
|
||||
Expired = true;
|
||||
return false;
|
||||
}
|
||||
Expired = false;
|
||||
Cache_.update(SessionToken, UInfo);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
poco_error(Logger(),fmt::format("Failed to retrieve token={} for TID={}", Utils::SanitizeToken(SessionToken), TID));
|
||||
}
|
||||
Expired = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthClient::IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted, bool Sub) {
|
||||
auto User = Cache_.get(SessionToken);
|
||||
if(!User.isNull()) {
|
||||
if(IsTokenExpired(User->webtoken)) {
|
||||
Expired = true;
|
||||
Cache_.remove(SessionToken);
|
||||
return false;
|
||||
}
|
||||
Expired = false;
|
||||
UInfo = *User;
|
||||
return true;
|
||||
}
|
||||
return RetrieveTokenInformation(SessionToken, UInfo, TID, Expired, Contacted, Sub);
|
||||
}
|
||||
|
||||
bool AuthClient::RetrieveApiKeyInformation(const std::string & SessionToken,
|
||||
SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted) {
|
||||
try {
|
||||
Types::StringPairVec QueryData;
|
||||
QueryData.push_back(std::make_pair("apikey",SessionToken));
|
||||
std::string AlternateURIForLogging = fmt::format("/api/v1/validateApiKey?apiKey={}", Utils::SanitizeToken(SessionToken));
|
||||
OpenAPIRequestGet Req( uSERVICE_SECURITY,
|
||||
"/api/v1/validateApiKey" ,
|
||||
QueryData,
|
||||
10000,
|
||||
AlternateURIForLogging);
|
||||
Poco::JSON::Object::Ptr Response;
|
||||
|
||||
auto StatusCode = Req.Do(Response);
|
||||
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
|
||||
Contacted = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Contacted = true;
|
||||
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
|
||||
if(Response->has("tokenInfo") && Response->has("userInfo") && Response->has("expiresOn")) {
|
||||
UInfo.from_json(Response);
|
||||
Expired = false;
|
||||
ApiKeyCache_.update(SessionToken, ApiKeyCacheEntry{ .UserInfo = UInfo, .ExpiresOn = Response->get("expiresOn")});
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
poco_error(Logger(),fmt::format("Failed to retrieve api key={} for TID={}", Utils::SanitizeToken(SessionToken), TID));
|
||||
}
|
||||
Expired = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthClient::IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy &UInfo,
|
||||
std::uint64_t TID, bool &Expired, bool &Contacted) {
|
||||
auto User = ApiKeyCache_.get(SessionToken);
|
||||
if (!User.isNull()) {
|
||||
if(User->ExpiresOn < Utils::Now()) {
|
||||
Expired = false;
|
||||
UInfo = User->UserInfo;
|
||||
return true;
|
||||
}
|
||||
ApiKeyCache_.remove(SessionToken);
|
||||
}
|
||||
return RetrieveApiKeyInformation(SessionToken, UInfo, TID, Expired, Contacted);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
79
src/framework/AuthClient.h
Normal file
79
src/framework/AuthClient.h
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
#include "Poco/ExpireLRUCache.h"
|
||||
#include "framework/utils.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class AuthClient : public SubSystemServer {
|
||||
|
||||
public:
|
||||
explicit AuthClient() noexcept:
|
||||
SubSystemServer("Authentication", "AUTH-CLNT", "authentication")
|
||||
{
|
||||
}
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new AuthClient;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
struct ApiKeyCacheEntry {
|
||||
OpenWifi::SecurityObjects::UserInfoAndPolicy UserInfo;
|
||||
std::uint64_t ExpiresOn;
|
||||
};
|
||||
|
||||
inline int Start() override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() override {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
std::lock_guard G(Mutex_);
|
||||
Cache_.clear();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
inline void RemovedCachedToken(const std::string &Token) {
|
||||
Cache_.remove(Token);
|
||||
ApiKeyCache_.remove(Token);
|
||||
}
|
||||
|
||||
inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) {
|
||||
return ((T.expires_in_+T.created_) < Utils::Now());
|
||||
}
|
||||
|
||||
bool RetrieveTokenInformation(const std::string & SessionToken,
|
||||
SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted, bool Sub=false);
|
||||
|
||||
bool RetrieveApiKeyInformation(const std::string & SessionToken,
|
||||
SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted);
|
||||
|
||||
bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted, bool Sub = false);
|
||||
|
||||
bool IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
|
||||
std::uint64_t TID,
|
||||
bool & Expired, bool & Contacted);
|
||||
|
||||
private:
|
||||
|
||||
Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{512,1200000 };
|
||||
Poco::ExpireLRUCache<std::string,ApiKeyCacheEntry> ApiKeyCache_{512,1200000 };
|
||||
};
|
||||
|
||||
inline auto AuthClient() { return AuthClient::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
155
src/framework/CIDR.h
Normal file
155
src/framework/CIDR.h
Normal file
@@ -0,0 +1,155 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
namespace OpenWifi::CIDR {
|
||||
|
||||
static bool cidr_match(const in_addr &addr, const in_addr &net, uint8_t bits) {
|
||||
if (bits == 0) {
|
||||
return true;
|
||||
}
|
||||
return !((addr.s_addr ^ net.s_addr) & htonl(0xFFFFFFFFu << (32 - bits)));
|
||||
}
|
||||
|
||||
static bool cidr6_match(const in6_addr &address, const in6_addr &network, uint8_t bits) {
|
||||
#ifdef __linux__
|
||||
const uint32_t *a = address.s6_addr32;
|
||||
const uint32_t *n = network.s6_addr32;
|
||||
#else
|
||||
const uint32_t *a = address.__u6_addr.__u6_addr32;
|
||||
const uint32_t *n = network.__u6_addr.__u6_addr32;
|
||||
#endif
|
||||
int bits_whole, bits_incomplete;
|
||||
bits_whole = bits >> 5; // number of whole u32
|
||||
bits_incomplete = bits & 0x1F; // number of bits in incomplete u32
|
||||
if (bits_whole) {
|
||||
if (memcmp(a, n, bits_whole << 2) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (bits_incomplete) {
|
||||
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
|
||||
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ConvertStringToLong(const char *S, unsigned long &L) {
|
||||
char *end;
|
||||
L = std::strtol(S, &end, 10);
|
||||
return end != S;
|
||||
}
|
||||
|
||||
static bool CidrIPinRange(const Poco::Net::IPAddress &IP, const std::string &Range) {
|
||||
Poco::StringTokenizer TimeTokens(Range, "/", Poco::StringTokenizer::TOK_TRIM);
|
||||
|
||||
Poco::Net::IPAddress RangeIP;
|
||||
if (Poco::Net::IPAddress::tryParse(TimeTokens[0], RangeIP)) {
|
||||
if (TimeTokens.count() == 2) {
|
||||
if (RangeIP.family() == Poco::Net::IPAddress::IPv4) {
|
||||
unsigned long MaskLength;
|
||||
if (ConvertStringToLong(TimeTokens[1].c_str(), MaskLength)) {
|
||||
return cidr_match(*static_cast<const in_addr *>(RangeIP.addr()),
|
||||
*static_cast<const in_addr *>(IP.addr()), MaskLength);
|
||||
}
|
||||
} else if (RangeIP.family() == Poco::Net::IPAddress::IPv6) {
|
||||
unsigned long MaskLength;
|
||||
if (ConvertStringToLong(TimeTokens[1].c_str(), MaskLength)) {
|
||||
return cidr6_match(*static_cast<const in6_addr *>(RangeIP.addr()),
|
||||
*static_cast<const in6_addr *>(IP.addr()), MaskLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Ranges can be a single IP, of IP1-IP2, of A set of IPs: IP1,IP2,IP3, or a cidr IP/24
|
||||
// These can work for IPv6 too...
|
||||
//
|
||||
static bool ValidateRange(const std::string &R) {
|
||||
|
||||
auto Tokens = Poco::StringTokenizer(R, "-");
|
||||
if (Tokens.count() == 2) {
|
||||
Poco::Net::IPAddress a, b;
|
||||
if (!Poco::Net::IPAddress::tryParse(Tokens[0], a) &&
|
||||
Poco::Net::IPAddress::tryParse(Tokens[1], b))
|
||||
return false;
|
||||
return a.family() == b.family();
|
||||
}
|
||||
|
||||
Tokens = Poco::StringTokenizer(R, ",");
|
||||
if (Tokens.count() > 1) {
|
||||
return std::all_of(Tokens.begin(), Tokens.end(), [](const std::string &A) {
|
||||
Poco::Net::IPAddress a;
|
||||
return Poco::Net::IPAddress::tryParse(A, a);
|
||||
});
|
||||
}
|
||||
|
||||
Tokens = Poco::StringTokenizer(R, "/");
|
||||
if (Tokens.count() == 2) {
|
||||
Poco::Net::IPAddress a;
|
||||
if (!Poco::Net::IPAddress::tryParse(Tokens[0], a))
|
||||
return false;
|
||||
if (std::atoi(Tokens[1].c_str()) == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Poco::Net::IPAddress a;
|
||||
return Poco::Net::IPAddress::tryParse(R, a);
|
||||
}
|
||||
|
||||
static bool IpInRange(const Poco::Net::IPAddress &target, const std::string &R) {
|
||||
|
||||
auto Tokens = Poco::StringTokenizer(R, "-");
|
||||
if (Tokens.count() == 2) {
|
||||
auto a = Poco::Net::IPAddress::parse(Tokens[0]);
|
||||
auto b = Poco::Net::IPAddress::parse(Tokens[1]);
|
||||
if (target.family() != a.family())
|
||||
return false;
|
||||
return (a <= target && b >= target);
|
||||
}
|
||||
|
||||
Tokens = Poco::StringTokenizer(R, ",");
|
||||
if (Tokens.count() > 1) {
|
||||
return std::any_of(Tokens.begin(), Tokens.end(), [target](const std::string &Element) {
|
||||
return Poco::Net::IPAddress::parse(Element) == target;
|
||||
});
|
||||
}
|
||||
|
||||
Tokens = Poco::StringTokenizer(R, "/");
|
||||
if (Tokens.count() == 2) {
|
||||
return CidrIPinRange(target, R);
|
||||
}
|
||||
|
||||
return Poco::Net::IPAddress::parse(R) == target;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IpInRanges(const std::string &IP, const Types::StringVec &R) {
|
||||
Poco::Net::IPAddress Target;
|
||||
|
||||
if (!Poco::Net::IPAddress::tryParse(IP, Target))
|
||||
return false;
|
||||
|
||||
return std::any_of(cbegin(R), cend(R),
|
||||
[Target](const std::string &i) { return IpInRange(Target, i); });
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool ValidateIpRanges(const Types::StringVec &Ranges) {
|
||||
return std::all_of(cbegin(Ranges), cend(Ranges), ValidateRange);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json-schema.hpp>
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/SubSystemServer.h"
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_schema::json_validator;
|
||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
|
||||
nlohmann::json RootSchema_;
|
||||
|
||||
ConfigurationValidator():
|
||||
SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") {
|
||||
SubSystemServer("ConfigValidator", "CFG-VALIDATOR", "config.validator") {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
49
src/framework/EventBusManager.cpp
Normal file
49
src/framework/EventBusManager.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-26.
|
||||
//
|
||||
|
||||
#include "framework/EventBusManager.h"
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/utils.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
EventBusManager::EventBusManager(Poco::Logger &L) :
|
||||
Logger_(L) {
|
||||
}
|
||||
|
||||
void EventBusManager::run() {
|
||||
Running_ = true;
|
||||
Utils::SetThreadName("fmwk:EventMgr");
|
||||
auto Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
|
||||
while(Running_) {
|
||||
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
|
||||
if(!Running_)
|
||||
break;
|
||||
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
|
||||
}
|
||||
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
|
||||
};
|
||||
|
||||
void EventBusManager::Start() {
|
||||
poco_information(Logger(),"Starting...");
|
||||
if(KafkaManager()->Enabled()) {
|
||||
Thread_.start(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void EventBusManager::Stop() {
|
||||
if(KafkaManager()->Enabled()) {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Running_ = false;
|
||||
Thread_.wakeUp();
|
||||
Thread_.join();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
28
src/framework/EventBusManager.h
Normal file
28
src/framework/EventBusManager.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-26.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/Runnable.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/Thread.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class EventBusManager : public Poco::Runnable {
|
||||
public:
|
||||
explicit EventBusManager(Poco::Logger &L);
|
||||
void run() final;
|
||||
void Start();
|
||||
void Stop();
|
||||
inline Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
private:
|
||||
mutable std::atomic_bool Running_ = false;
|
||||
Poco::Thread Thread_;
|
||||
Poco::Logger &Logger_;
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
365
src/framework/KafkaManager.cpp
Normal file
365
src/framework/KafkaManager.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "KafkaManager.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
#include "fmt/format.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void KafkaLoggerFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int level, const std::string & facility, const std::string &message) {
|
||||
switch ((cppkafka::LogLevel) level) {
|
||||
case cppkafka::LogLevel::LogNotice: {
|
||||
poco_notice(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
|
||||
}
|
||||
break;
|
||||
case cppkafka::LogLevel::LogDebug: {
|
||||
poco_debug(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
|
||||
}
|
||||
break;
|
||||
case cppkafka::LogLevel::LogInfo: {
|
||||
poco_information(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
|
||||
}
|
||||
break;
|
||||
case cppkafka::LogLevel::LogWarning: {
|
||||
poco_warning(KafkaManager()->Logger(), fmt::format("kafka-log: facility: {} message: {}",facility, message));
|
||||
}
|
||||
break;
|
||||
case cppkafka::LogLevel::LogAlert:
|
||||
case cppkafka::LogLevel::LogCrit: {
|
||||
poco_critical(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
|
||||
}
|
||||
break;
|
||||
case cppkafka::LogLevel::LogErr:
|
||||
case cppkafka::LogLevel::LogEmerg:
|
||||
default: {
|
||||
poco_error(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inline void KafkaErrorFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int error, const std::string &reason) {
|
||||
poco_error(KafkaManager()->Logger(),fmt::format("kafka-error: {}, reason: {}", error, reason));
|
||||
}
|
||||
|
||||
inline void AddKafkaSecurity(cppkafka::Configuration & Config) {
|
||||
auto CA = MicroServiceConfigGetString("openwifi.kafka.ssl.ca.location","");
|
||||
auto Certificate = MicroServiceConfigGetString("openwifi.kafka.ssl.certificate.location","");
|
||||
auto Key = MicroServiceConfigGetString("openwifi.kafka.ssl.key.location","");
|
||||
auto Password = MicroServiceConfigGetString("openwifi.kafka.ssl.key.password","");
|
||||
|
||||
if(CA.empty() || Certificate.empty() || Key.empty())
|
||||
return;
|
||||
|
||||
Config.set("ssl.ca.location", CA);
|
||||
Config.set("ssl.certificate.location", Certificate);
|
||||
Config.set("ssl.key.location", Key);
|
||||
if(!Password.empty())
|
||||
Config.set("ssl.key.password", Password);
|
||||
}
|
||||
|
||||
|
||||
void KafkaManager::initialize(Poco::Util::Application & self) {
|
||||
SubSystemServer::initialize(self);
|
||||
KafkaEnabled_ = MicroServiceConfigGetBool("openwifi.kafka.enable",false);
|
||||
}
|
||||
|
||||
inline void KafkaProducer::run() {
|
||||
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-PRODUCER", KafkaManager()->Logger().getChannel());
|
||||
poco_information(Logger_,"Starting...");
|
||||
|
||||
Utils::SetThreadName("Kafka:Prod");
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", MicroServiceConfigGetString("openwifi.kafka.client.id", "") },
|
||||
{ "metadata.broker.list", MicroServiceConfigGetString("openwifi.kafka.brokerlist", "") }
|
||||
});
|
||||
|
||||
AddKafkaSecurity(Config);
|
||||
|
||||
Config.set_log_callback(KafkaLoggerFun);
|
||||
Config.set_error_callback(KafkaErrorFun);
|
||||
|
||||
KafkaManager()->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
|
||||
std::to_string(MicroServiceID()) +
|
||||
R"lit( , "host" : ")lit" + MicroServicePrivateEndPoint() +
|
||||
R"lit(" } , "payload" : )lit" ;
|
||||
|
||||
cppkafka::Producer Producer(Config);
|
||||
Running_ = true;
|
||||
|
||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||
while(Note && Running_) {
|
||||
try {
|
||||
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
|
||||
if (Msg != nullptr) {
|
||||
Producer.produce(
|
||||
cppkafka::MessageBuilder(Msg->Topic()).key(Msg->Key()).payload(Msg->Payload()));
|
||||
}
|
||||
} catch (const cppkafka::HandleException &E) {
|
||||
poco_warning(Logger_,fmt::format("Caught a Kafka exception (producer): {}", E.what()));
|
||||
} catch( const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,"std::exception");
|
||||
}
|
||||
Note = Queue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger_,"Stopped...");
|
||||
}
|
||||
|
||||
inline void KafkaConsumer::run() {
|
||||
Utils::SetThreadName("Kafka:Cons");
|
||||
|
||||
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-CONSUMER", KafkaManager()->Logger().getChannel());
|
||||
|
||||
poco_information(Logger_,"Starting...");
|
||||
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", MicroServiceConfigGetString("openwifi.kafka.client.id","") },
|
||||
{ "metadata.broker.list", MicroServiceConfigGetString("openwifi.kafka.brokerlist","") },
|
||||
{ "group.id", MicroServiceConfigGetString("openwifi.kafka.group.id","") },
|
||||
{ "enable.auto.commit", MicroServiceConfigGetBool("openwifi.kafka.auto.commit",false) },
|
||||
{ "auto.offset.reset", "latest" } ,
|
||||
{ "enable.partition.eof", false }
|
||||
});
|
||||
|
||||
AddKafkaSecurity(Config);
|
||||
|
||||
Config.set_log_callback(KafkaLoggerFun);
|
||||
Config.set_error_callback(KafkaErrorFun);
|
||||
|
||||
cppkafka::TopicConfiguration topic_config = {
|
||||
{ "auto.offset.reset", "smallest" }
|
||||
};
|
||||
|
||||
// Now configure it to be the default topic config
|
||||
Config.set_default_topic_configuration(topic_config);
|
||||
|
||||
cppkafka::Consumer Consumer(Config);
|
||||
Consumer.set_assignment_callback([&](cppkafka::TopicPartitionList& partitions) {
|
||||
if(!partitions.empty()) {
|
||||
poco_information(Logger_,fmt::format("Partition assigned: {}...",
|
||||
partitions.front().get_partition()));
|
||||
}
|
||||
});
|
||||
Consumer.set_revocation_callback([&](const cppkafka::TopicPartitionList& partitions) {
|
||||
if(!partitions.empty()) {
|
||||
poco_information(Logger_,fmt::format("Partition revocation: {}...",
|
||||
partitions.front().get_partition()));
|
||||
}
|
||||
});
|
||||
|
||||
bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit",false);
|
||||
auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize",20);
|
||||
|
||||
Types::StringVec Topics;
|
||||
KafkaManager()->Topics(Topics);
|
||||
Consumer.subscribe(Topics);
|
||||
|
||||
Running_ = true;
|
||||
while(Running_) {
|
||||
try {
|
||||
std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100));
|
||||
for(auto const &Msg:MsgVec) {
|
||||
if (!Msg)
|
||||
continue;
|
||||
if (Msg.get_error()) {
|
||||
if (!Msg.is_eof()) {
|
||||
poco_error(Logger_,fmt::format("Error: {}", Msg.get_error().to_string()));
|
||||
}
|
||||
if(!AutoCommit)
|
||||
Consumer.async_commit(Msg);
|
||||
continue;
|
||||
}
|
||||
KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(),Msg.get_payload() );
|
||||
if (!AutoCommit)
|
||||
Consumer.async_commit(Msg);
|
||||
}
|
||||
} catch (const cppkafka::HandleException &E) {
|
||||
poco_warning(Logger_,fmt::format("Caught a Kafka exception (consumer): {}", E.what()));
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} catch (...) {
|
||||
poco_error(Logger_,"std::exception");
|
||||
}
|
||||
}
|
||||
Consumer.unsubscribe();
|
||||
poco_information(Logger_,"Stopped...");
|
||||
}
|
||||
|
||||
void KafkaProducer::Start() {
|
||||
if(!Running_) {
|
||||
Running_=true;
|
||||
Worker_.start(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaProducer::Stop() {
|
||||
if(Running_) {
|
||||
Running_=false;
|
||||
Queue_.wakeUpAll();
|
||||
Worker_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaProducer::Produce(const std::string &Topic, const std::string &Key, const std::string &Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Queue_.enqueueNotification( new KafkaMessage(Topic,Key,Payload));
|
||||
}
|
||||
|
||||
void KafkaConsumer::Start() {
|
||||
if(!Running_) {
|
||||
Running_=true;
|
||||
Worker_.start(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaConsumer::Stop() {
|
||||
if(Running_) {
|
||||
Running_=false;
|
||||
Worker_.wakeUp();
|
||||
Worker_.join();
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Start() {
|
||||
if(!Running_) {
|
||||
Running_=true;
|
||||
Worker_.start(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Stop() {
|
||||
if(Running_) {
|
||||
Running_=false;
|
||||
Queue_.wakeUpAll();
|
||||
Worker_.join();
|
||||
}
|
||||
}
|
||||
|
||||
auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if(It == Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList L;
|
||||
L.emplace(L.end(),std::make_pair(F,FunctionId_));
|
||||
Notifiers_[Topic] = std::move(L);
|
||||
} else {
|
||||
It->second.emplace(It->second.end(),std::make_pair(F,FunctionId_));
|
||||
}
|
||||
return FunctionId_++;
|
||||
}
|
||||
|
||||
void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if(It != Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList & L = It->second;
|
||||
for(auto it=L.begin(); it!=L.end(); it++)
|
||||
if(it->second == Id) {
|
||||
L.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload) {
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if(It!=Notifiers_.end()) {
|
||||
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaDispatcher::run() {
|
||||
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel());
|
||||
poco_information(Logger_,"Starting...");
|
||||
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
|
||||
Utils::SetThreadName("kafka:dispatch");
|
||||
while(Note && Running_) {
|
||||
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
|
||||
if(Msg!= nullptr) {
|
||||
auto It = Notifiers_.find(Msg->Topic());
|
||||
if (It != Notifiers_.end()) {
|
||||
const auto & FL = It->second;
|
||||
for(const auto &[CallbackFunc,_]:FL) {
|
||||
CallbackFunc(Msg->Key(), Msg->Payload());
|
||||
}
|
||||
}
|
||||
}
|
||||
Note = Queue_.waitDequeueNotification();
|
||||
}
|
||||
poco_information(Logger_,"Stopped...");
|
||||
}
|
||||
|
||||
void KafkaDispatcher::Topics(std::vector<std::string> &T) {
|
||||
T.clear();
|
||||
for(const auto &[TopicName,_]:Notifiers_)
|
||||
T.push_back(TopicName);
|
||||
}
|
||||
|
||||
|
||||
int KafkaManager::Start() {
|
||||
if(!KafkaEnabled_)
|
||||
return 0;
|
||||
ConsumerThr_.Start();
|
||||
ProducerThr_.Start();
|
||||
Dispatcher_.Start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void KafkaManager::Stop() {
|
||||
if(KafkaEnabled_) {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
Dispatcher_.Stop();
|
||||
ProducerThr_.Stop();
|
||||
ConsumerThr_.Stop();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage ) {
|
||||
if(KafkaEnabled_) {
|
||||
ProducerThr_.Produce(topic,key,WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload) {
|
||||
Dispatcher_.Dispatch(Topic, Key, Payload);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
|
||||
return SystemInfoWrapper_ + PayLoad + "}";
|
||||
}
|
||||
|
||||
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
|
||||
if(KafkaEnabled_) {
|
||||
return Dispatcher_.RegisterTopicWatcher(Topic,F);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
|
||||
if(KafkaEnabled_) {
|
||||
Dispatcher_.UnregisterTopicWatcher(Topic, Id);
|
||||
}
|
||||
}
|
||||
|
||||
void KafkaManager::Topics(std::vector<std::string> &T) {
|
||||
Dispatcher_.Topics(T);
|
||||
}
|
||||
|
||||
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList& partitions) {
|
||||
poco_information(Logger(),fmt::format("Partition assigned: {}...", partitions.front().get_partition()));
|
||||
}
|
||||
|
||||
void KafkaManager::PartitionRevocation(const cppkafka::TopicPartitionList& partitions) {
|
||||
poco_information(Logger(),fmt::format("Partition revocation: {}...",partitions.front().get_partition()));
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
122
src/framework/KafkaManager.h
Normal file
122
src/framework/KafkaManager.h
Normal file
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/Notification.h"
|
||||
#include "Poco/NotificationQueue.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
#include "framework/utils.h"
|
||||
#include "framework/KafkaTopics.h"
|
||||
|
||||
#include "cppkafka/cppkafka.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class KafkaMessage: public Poco::Notification {
|
||||
public:
|
||||
KafkaMessage( const std::string &Topic, const std::string &Key, const std::string & Payload) :
|
||||
Topic_(Topic), Key_(Key), Payload_(Payload) {
|
||||
}
|
||||
|
||||
inline const std::string & Topic() { return Topic_; }
|
||||
inline const std::string & Key() { return Key_; }
|
||||
inline const std::string & Payload() { return Payload_; }
|
||||
|
||||
private:
|
||||
std::string Topic_;
|
||||
std::string Key_;
|
||||
std::string Payload_;
|
||||
};
|
||||
|
||||
class KafkaProducer : public Poco::Runnable {
|
||||
public:
|
||||
void run () override;
|
||||
void Start();
|
||||
void Stop();
|
||||
void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload);
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
Poco::NotificationQueue Queue_;
|
||||
};
|
||||
|
||||
class KafkaConsumer : public Poco::Runnable {
|
||||
public:
|
||||
void run() override;
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
};
|
||||
|
||||
class KafkaDispatcher : public Poco::Runnable {
|
||||
public:
|
||||
void Start();
|
||||
void Stop();
|
||||
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void UnregisterTopicWatcher(const std::string &Topic, int Id);
|
||||
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
|
||||
void run() override;
|
||||
void Topics(std::vector<std::string> &T);
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Types::NotifyTable Notifiers_;
|
||||
Poco::Thread Worker_;
|
||||
mutable std::atomic_bool Running_=false;
|
||||
uint64_t FunctionId_=1;
|
||||
Poco::NotificationQueue Queue_;
|
||||
};
|
||||
|
||||
class KafkaManager : public SubSystemServer {
|
||||
public:
|
||||
|
||||
friend class KafkaConsumer;
|
||||
friend class KafkaProducer;
|
||||
|
||||
inline void initialize(Poco::Util::Application & self) override;
|
||||
|
||||
static auto instance() {
|
||||
static auto instance_ = new KafkaManager;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true );
|
||||
void Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload);
|
||||
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
|
||||
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
|
||||
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
|
||||
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
|
||||
void Topics(std::vector<std::string> &T);
|
||||
|
||||
private:
|
||||
bool KafkaEnabled_ = false;
|
||||
std::string SystemInfoWrapper_;
|
||||
KafkaProducer ProducerThr_;
|
||||
KafkaConsumer ConsumerThr_;
|
||||
KafkaDispatcher Dispatcher_;
|
||||
|
||||
void PartitionAssignment(const cppkafka::TopicPartitionList& partitions);
|
||||
void PartitionRevocation(const cppkafka::TopicPartitionList& partitions);
|
||||
|
||||
KafkaManager() noexcept:
|
||||
SubSystemServer("KafkaManager", "KAFKA-SVR", "openwifi.kafka") {
|
||||
}
|
||||
};
|
||||
|
||||
inline auto KafkaManager() { return KafkaManager::instance(); }
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
namespace OpenWifi::KafkaTopics {
|
||||
static const std::string HEALTHCHECK{"healthcheck"};
|
||||
static const std::string STATE{"state"};
|
||||
|
||||
712
src/framework/MicroService.cpp
Normal file
712
src/framework/MicroService.cpp
Normal file
@@ -0,0 +1,712 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-26.
|
||||
//
|
||||
|
||||
#include "Poco/FileChannel.h"
|
||||
#include "Poco/ConsoleChannel.h"
|
||||
#include "Poco/PatternFormatter.h"
|
||||
#include "Poco/FormattingChannel.h"
|
||||
#include "Poco/AsyncChannel.h"
|
||||
#include "Poco/NullChannel.h"
|
||||
#include "Poco/SplitterChannel.h"
|
||||
#include "Poco/Net/HTTPStreamFactory.h"
|
||||
#include "Poco/Net/HTTPSStreamFactory.h"
|
||||
#include "Poco/Net/FTPSStreamFactory.h"
|
||||
#include "Poco/Net/FTPStreamFactory.h"
|
||||
#include "Poco/Net/SSLManager.h"
|
||||
#include "Poco/JSON/JSONException.h"
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/MicroServiceErrorHandler.h"
|
||||
#include "framework/UI_WebSocketClientServer.h"
|
||||
#include "framework/MicroServiceNames.h"
|
||||
#include "framework/AuthClient.h"
|
||||
#include "framework/ALBserver.h"
|
||||
#include "framework/KafkaManager.h"
|
||||
#include "framework/RESTAPI_GenericServerAccounting.h"
|
||||
#include "framework/RESTAPI_ExtServer.h"
|
||||
#include "framework/RESTAPI_IntServer.h"
|
||||
#include "framework/utils.h"
|
||||
#include "framework/WebSocketLogger.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void MicroService::Exit(int Reason) {
|
||||
std::exit(Reason);
|
||||
}
|
||||
|
||||
void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key, const std::string & Payload) {
|
||||
std::lock_guard G(InfraMutex_);
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Object = P.parse(Payload).extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if (Object->has(KafkaTopics::ServiceEvents::Fields::ID) &&
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::EVENT)) {
|
||||
uint64_t ID = Object->get(KafkaTopics::ServiceEvents::Fields::ID);
|
||||
auto Event = Object->get(KafkaTopics::ServiceEvents::Fields::EVENT).toString();
|
||||
if (ID != ID_) {
|
||||
if( Event==KafkaTopics::ServiceEvents::EVENT_JOIN ||
|
||||
Event==KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE ||
|
||||
Event==KafkaTopics::ServiceEvents::EVENT_LEAVE ) {
|
||||
if( Object->has(KafkaTopics::ServiceEvents::Fields::TYPE) &&
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::PUBLIC) &&
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::PRIVATE) &&
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::VRSN) &&
|
||||
Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) {
|
||||
auto PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString();
|
||||
if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && Services_.find(PrivateEndPoint) != Services_.end()) {
|
||||
Services_[PrivateEndPoint].LastUpdate = Utils::Now();
|
||||
} else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
|
||||
Services_.erase(PrivateEndPoint);
|
||||
poco_debug(logger(),fmt::format("Service {} ID={} leaving system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
|
||||
} else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN || Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) {
|
||||
poco_debug(logger(),fmt::format("Service {} ID={} joining system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
|
||||
Services_[PrivateEndPoint] = Types::MicroServiceMeta{
|
||||
.Id = ID,
|
||||
.Type = Poco::toLower(Object->get(KafkaTopics::ServiceEvents::Fields::TYPE).toString()),
|
||||
.PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),
|
||||
.PublicEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PUBLIC).toString(),
|
||||
.AccessKey = Object->get(KafkaTopics::ServiceEvents::Fields::KEY).toString(),
|
||||
.Version = Object->get(KafkaTopics::ServiceEvents::Fields::VRSN).toString(),
|
||||
.LastUpdate = Utils::Now() };
|
||||
|
||||
std::string SvcList;
|
||||
for (const auto &Svc: Services_) {
|
||||
if(SvcList.empty())
|
||||
SvcList = Svc.second.Type;
|
||||
else
|
||||
SvcList += ", " + Svc.second.Type;
|
||||
}
|
||||
poco_information(logger(),fmt::format("Current list of microservices: {}", SvcList));
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",Event));
|
||||
}
|
||||
} else if (Event==KafkaTopics::ServiceEvents::EVENT_REMOVE_TOKEN) {
|
||||
if(Object->has(KafkaTopics::ServiceEvents::Fields::TOKEN)) {
|
||||
#ifndef TIP_SECURITY_SERVICE
|
||||
AuthClient()->RemovedCachedToken(Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString());
|
||||
#endif
|
||||
} else {
|
||||
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing token",Event));
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(),fmt::format("Unknown Event: {} Source: {}", Event, ID));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
poco_error(logger(),"Bad bus message.");
|
||||
}
|
||||
|
||||
auto i=Services_.begin();
|
||||
auto now = Utils::Now();
|
||||
for(;i!=Services_.end();) {
|
||||
if((now - i->second.LastUpdate)>60) {
|
||||
i = Services_.erase(i);
|
||||
} else
|
||||
++i;
|
||||
}
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
}
|
||||
}
|
||||
|
||||
Types::MicroServiceMetaVec MicroService::GetServices(const std::string & Type) {
|
||||
std::lock_guard G(InfraMutex_);
|
||||
|
||||
auto T = Poco::toLower(Type);
|
||||
Types::MicroServiceMetaVec Res;
|
||||
for(const auto &[_,ServiceRec]:Services_) {
|
||||
if(ServiceRec.Type==T)
|
||||
Res.push_back(ServiceRec);
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
Types::MicroServiceMetaVec MicroService::GetServices() {
|
||||
std::lock_guard G(InfraMutex_);
|
||||
|
||||
Types::MicroServiceMetaVec Res;
|
||||
for(const auto &[_,ServiceRec]:Services_) {
|
||||
Res.push_back(ServiceRec);
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
void MicroService::LoadConfigurationFile() {
|
||||
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,".");
|
||||
ConfigFileName_ = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
|
||||
Poco::Path ConfigFile(ConfigFileName_);
|
||||
|
||||
if(!ConfigFile.isFile())
|
||||
{
|
||||
std::cerr << DAEMON_APP_NAME << ": Configuration "
|
||||
<< ConfigFile.toString() << " does not seem to exist. Please set " + DAEMON_CONFIG_ENV_VAR
|
||||
+ " env variable the path of the " + DAEMON_PROPERTIES_FILENAME + " file." << std::endl;
|
||||
std::exit(Poco::Util::Application::EXIT_CONFIG);
|
||||
}
|
||||
|
||||
// loadConfiguration(ConfigFile.toString());
|
||||
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString());
|
||||
configPtr()->addWriteable(PropConfigurationFile_, PRIO_DEFAULT);
|
||||
}
|
||||
|
||||
void MicroService::Reload() {
|
||||
LoadConfigurationFile();
|
||||
LoadMyConfig();
|
||||
}
|
||||
|
||||
void MicroService::LoadMyConfig() {
|
||||
NoAPISecurity_ = ConfigGetBool("openwifi.security.restapi.disable",false);
|
||||
std::string KeyFile = ConfigPath("openwifi.service.key","");
|
||||
if(!KeyFile.empty()) {
|
||||
std::string KeyFilePassword = ConfigPath("openwifi.service.key.password", "");
|
||||
AppKey_ = Poco::SharedPtr<Poco::Crypto::RSAKey>(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword));
|
||||
Cipher_ = CipherFactory_.createCipher(*AppKey_);
|
||||
Signer_.setRSAKey(AppKey_);
|
||||
Signer_.addAllAlgorithms();
|
||||
NoBuiltInCrypto_ = false;
|
||||
} else {
|
||||
NoBuiltInCrypto_ = true;
|
||||
}
|
||||
|
||||
ID_ = Utils::GetSystemId();
|
||||
if(!DebugMode_)
|
||||
DebugMode_ = ConfigGetBool("openwifi.system.debug",false);
|
||||
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
|
||||
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
|
||||
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
|
||||
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
|
||||
}
|
||||
|
||||
void MicroService::InitializeLoggingSystem() {
|
||||
static auto initialized = false;
|
||||
|
||||
if(!initialized) {
|
||||
initialized = true;
|
||||
LoadConfigurationFile();
|
||||
|
||||
auto LoggingDestination = MicroService::instance().ConfigGetString("logging.type", "file");
|
||||
auto LoggingFormat = MicroService::instance().ConfigGetString("logging.format",
|
||||
"%Y-%m-%d %H:%M:%S.%i %s: [%p][thr:%I] %t");
|
||||
auto UseAsyncLogs_ = MicroService::instance().ConfigGetBool("logging.asynch", true);
|
||||
auto DisableWebSocketLogging = MicroService::instance().ConfigGetBool("logging.websocket",false);
|
||||
|
||||
if (LoggingDestination == "null") {
|
||||
Poco::AutoPtr<Poco::NullChannel> DevNull(new Poco::NullChannel);
|
||||
Poco::Logger::root().setChannel(DevNull);
|
||||
} else if (LoggingDestination == "console") {
|
||||
SetConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
||||
} else if (LoggingDestination == "colorconsole") {
|
||||
SetColorConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
||||
} else if (LoggingDestination == "sql") {
|
||||
SetSQLLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
||||
} else if (LoggingDestination == "syslog") {
|
||||
SetSyslogLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
|
||||
} else {
|
||||
SetFileLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat, DAEMON_ROOT_ENV_VAR);
|
||||
}
|
||||
|
||||
auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug"));
|
||||
Poco::Logger::root().setLevel(Level);
|
||||
if(!DisableWebSocketLogging) {
|
||||
static const UI_WebSocketClientServer::NotificationTypeIdVec Notifications = {
|
||||
{1, "log"}};
|
||||
UI_WebSocketClientServer()->RegisterNotifications(Notifications);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MicroService::SetConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
|
||||
|
||||
Poco::AutoPtr<Poco::ConsoleChannel> Console(new Poco::ConsoleChannel);
|
||||
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
||||
Formatter->setProperty("pattern", FormatterPattern);
|
||||
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
|
||||
|
||||
if(DisableWebSocketLogging) {
|
||||
if(UseAsync) {
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
|
||||
Poco::Logger::root().setChannel(Async);
|
||||
} else {
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
}
|
||||
} else {
|
||||
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
||||
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
||||
Splitter->addChannel(WSLogger);
|
||||
Splitter->addChannel(FormattingChannel);
|
||||
if(UseAsync) {
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
|
||||
Poco::Logger::root().setChannel(Async);
|
||||
} else {
|
||||
Poco::Logger::root().setChannel(Splitter);
|
||||
}
|
||||
}
|
||||
Poco::Logger::root().information(fmt::format("Enabled console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
|
||||
}
|
||||
|
||||
void MicroService::SetColorConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
|
||||
|
||||
Poco::AutoPtr<Poco::ColorConsoleChannel> Console(new Poco::ColorConsoleChannel);
|
||||
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
||||
Formatter->setProperty("pattern", FormatterPattern);
|
||||
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
|
||||
|
||||
if(DisableWebSocketLogging) {
|
||||
if(UseAsync) {
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
|
||||
Poco::Logger::root().setChannel(Async);
|
||||
} else {
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
}
|
||||
} else {
|
||||
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
||||
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
||||
Splitter->addChannel(WSLogger);
|
||||
Splitter->addChannel(FormattingChannel);
|
||||
if(UseAsync) {
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
|
||||
Poco::Logger::root().setChannel(Async);
|
||||
} else {
|
||||
Poco::Logger::root().setChannel(Splitter);
|
||||
}
|
||||
}
|
||||
Poco::Logger::root().information(fmt::format("Enabled color console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
|
||||
}
|
||||
|
||||
void MicroService::SetSQLLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
|
||||
//"CREATE TABLE T_POCO_LOG (Source VARCHAR, Name VARCHAR, ProcessId INTEGER, Thread VARCHAR, ThreadId INTEGER, Priority INTEGER, Text VARCHAR, DateTime DATE)"
|
||||
}
|
||||
|
||||
void MicroService::SetSyslogLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
|
||||
|
||||
}
|
||||
|
||||
void MicroService::SetFileLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern, const std::string & root_env_var) {
|
||||
std::string DefaultLogPath = fmt::format("${}/logs",root_env_var);
|
||||
auto LoggingLocationDir = MicroService::instance().ConfigPath("logging.path", DefaultLogPath);
|
||||
Poco::File LD(LoggingLocationDir);
|
||||
try {
|
||||
if(!LD.exists()) {
|
||||
LD.createDirectory();
|
||||
}
|
||||
} catch(const Poco::Exception &E) {
|
||||
std::cout << "Cannot create " << LD.path() << " Error: " << E.message() << std::endl;
|
||||
}
|
||||
auto LoggingLocationDirFilePattern = LoggingLocationDir + "/log";
|
||||
|
||||
Poco::AutoPtr<Poco::FileChannel> FileChannel(new Poco::FileChannel);
|
||||
FileChannel->setProperty("rotation", "10 M");
|
||||
FileChannel->setProperty("archive", "timestamp");
|
||||
FileChannel->setProperty("purgeCount", "10");
|
||||
FileChannel->setProperty("path", LoggingLocationDirFilePattern);
|
||||
|
||||
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
|
||||
Formatter->setProperty("pattern", FormatterPattern);
|
||||
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, FileChannel));
|
||||
|
||||
if(DisableWebSocketLogging) {
|
||||
if(UseAsync) {
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
|
||||
Poco::Logger::root().setChannel(Async);
|
||||
} else {
|
||||
Poco::Logger::root().setChannel(FormattingChannel);
|
||||
}
|
||||
} else {
|
||||
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
|
||||
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
|
||||
Splitter->addChannel(WSLogger);
|
||||
Splitter->addChannel(FormattingChannel);
|
||||
if(UseAsync) {
|
||||
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
|
||||
Poco::Logger::root().setChannel(Async);
|
||||
} else {
|
||||
Poco::Logger::root().setChannel(Splitter);
|
||||
}
|
||||
}
|
||||
Poco::Logger::root().information(fmt::format("Enabled file logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
|
||||
}
|
||||
|
||||
void DaemonPostInitialization(Poco::Util::Application &self);
|
||||
|
||||
void MicroService::initialize(Poco::Util::Application &self) {
|
||||
// add the default services
|
||||
LoadConfigurationFile();
|
||||
InitializeLoggingSystem();
|
||||
|
||||
SubSystems_.push_back(KafkaManager());
|
||||
SubSystems_.push_back(ALBHealthCheckServer());
|
||||
SubSystems_.push_back(RESTAPI_ExtServer());
|
||||
SubSystems_.push_back(RESTAPI_IntServer());
|
||||
#ifndef TIP_SECURITY_SERVICE
|
||||
SubSystems_.push_back(AuthClient());
|
||||
#endif
|
||||
Poco::Net::initializeSSL();
|
||||
Poco::Net::HTTPStreamFactory::registerFactory();
|
||||
Poco::Net::HTTPSStreamFactory::registerFactory();
|
||||
Poco::Net::FTPStreamFactory::registerFactory();
|
||||
Poco::Net::FTPSStreamFactory::registerFactory();
|
||||
|
||||
Poco::File DataDir(ConfigPath("openwifi.system.data"));
|
||||
DataDir_ = DataDir.path();
|
||||
if(!DataDir.exists()) {
|
||||
try {
|
||||
DataDir.createDirectory();
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
}
|
||||
}
|
||||
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets","");
|
||||
if(WWWAssetsDir_.empty())
|
||||
WWWAssetsDir_ = DataDir_;
|
||||
|
||||
LoadMyConfig();
|
||||
|
||||
InitializeSubSystemServers();
|
||||
ServerApplication::initialize(self);
|
||||
DaemonPostInitialization(self);
|
||||
|
||||
Types::TopicNotifyFunction F = [this](const std::string &Key,const std::string &Payload) { this->BusMessageReceived(Key, Payload); };
|
||||
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
|
||||
}
|
||||
|
||||
void MicroService::uninitialize() {
|
||||
// add your own uninitialization code here
|
||||
ServerApplication::uninitialize();
|
||||
}
|
||||
|
||||
void MicroService::reinitialize(Poco::Util::Application &self) {
|
||||
ServerApplication::reinitialize(self);
|
||||
// add your own reinitialization code here
|
||||
}
|
||||
|
||||
void MicroService::defineOptions(Poco::Util::OptionSet &options) {
|
||||
ServerApplication::defineOptions(options);
|
||||
|
||||
options.addOption(
|
||||
Poco::Util::Option("help", "", "display help information on command line arguments")
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleHelp)));
|
||||
|
||||
options.addOption(
|
||||
Poco::Util::Option("file", "", "specify the configuration file")
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.argument("file")
|
||||
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleConfig)));
|
||||
|
||||
options.addOption(
|
||||
Poco::Util::Option("debug", "", "to run in debug, set to true")
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleDebug)));
|
||||
|
||||
options.addOption(
|
||||
Poco::Util::Option("logs", "", "specify the log directory and file (i.e. dir/file.log)")
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.argument("dir")
|
||||
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleLogs)));
|
||||
|
||||
options.addOption(
|
||||
Poco::Util::Option("version", "", "get the version and quit.")
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleVersion)));
|
||||
|
||||
}
|
||||
|
||||
void MicroService::handleHelp([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
|
||||
HelpRequested_ = true;
|
||||
displayHelp();
|
||||
stopOptionsProcessing();
|
||||
}
|
||||
|
||||
void MicroService::handleVersion([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
|
||||
HelpRequested_ = true;
|
||||
std::cout << Version() << std::endl;
|
||||
stopOptionsProcessing();
|
||||
}
|
||||
|
||||
void MicroService::handleDebug([[maybe_unused]] const std::string &name, const std::string &value) {
|
||||
if(value == "true")
|
||||
DebugMode_ = true ;
|
||||
}
|
||||
|
||||
void MicroService::handleLogs([[maybe_unused]] const std::string &name, const std::string &value) {
|
||||
LogDir_ = value;
|
||||
}
|
||||
|
||||
void MicroService::handleConfig([[maybe_unused]] const std::string &name, const std::string &value) {
|
||||
ConfigFileName_ = value;
|
||||
}
|
||||
|
||||
void MicroService::displayHelp() {
|
||||
Poco::Util::HelpFormatter helpFormatter(options());
|
||||
helpFormatter.setCommand(commandName());
|
||||
helpFormatter.setUsage("OPTIONS");
|
||||
helpFormatter.setHeader("A " + DAEMON_APP_NAME + " implementation for TIP.");
|
||||
helpFormatter.format(std::cout);
|
||||
}
|
||||
|
||||
void MicroService::InitializeSubSystemServers() {
|
||||
for(auto i:SubSystems_) {
|
||||
addSubsystem(i);
|
||||
}
|
||||
}
|
||||
|
||||
void MicroService::StartSubSystemServers() {
|
||||
AddActivity("Starting");
|
||||
for(auto i:SubSystems_) {
|
||||
i->Start();
|
||||
}
|
||||
EventBusManager_ = std::make_unique<EventBusManager>(Poco::Logger::create("EventBusManager",Poco::Logger::root().getChannel(),Poco::Logger::root().getLevel()));
|
||||
EventBusManager_->Start();
|
||||
}
|
||||
|
||||
void MicroService::StopSubSystemServers() {
|
||||
AddActivity("Stopping");
|
||||
EventBusManager_->Stop();
|
||||
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) {
|
||||
(*i)->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string MicroService::CreateUUID() {
|
||||
static std::random_device rd;
|
||||
static std::mt19937_64 gen(rd());
|
||||
static std::uniform_int_distribution<> dis(0, 15);
|
||||
static std::uniform_int_distribution<> dis2(8, 11);
|
||||
|
||||
std::stringstream ss;
|
||||
int i;
|
||||
ss << std::hex;
|
||||
for (i = 0; i < 8; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 4; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-4";
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
ss << dis2(gen);
|
||||
for (i = 0; i < 3; i++) {
|
||||
ss << dis(gen);
|
||||
}
|
||||
ss << "-";
|
||||
for (i = 0; i < 12; i++) {
|
||||
ss << dis(gen);
|
||||
};
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
|
||||
try {
|
||||
auto P = Poco::Logger::parseLevel(Level);
|
||||
auto Sub = Poco::toLower(SubSystem);
|
||||
|
||||
if (Sub == "all") {
|
||||
for (auto i : SubSystems_) {
|
||||
i->Logger().setLevel(P);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
for (auto i : SubSystems_) {
|
||||
if (Sub == Poco::toLower(i->Name())) {
|
||||
i->Logger().setLevel(P);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const Poco::Exception & E) {
|
||||
std::cerr << "Exception" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MicroService::Reload(const std::string &Sub) {
|
||||
for (auto i : SubSystems_) {
|
||||
if (Poco::toLower(Sub) == Poco::toLower(i->Name())) {
|
||||
i->reinitialize(Poco::Util::Application::instance());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Types::StringVec MicroService::GetSubSystems() const {
|
||||
Types::StringVec Result;
|
||||
for(auto i:SubSystems_)
|
||||
Result.push_back(Poco::toLower(i->Name()));
|
||||
return Result;
|
||||
}
|
||||
|
||||
Types::StringPairVec MicroService::GetLogLevels() {
|
||||
Types::StringPairVec Result;
|
||||
|
||||
for(auto &i:SubSystems_) {
|
||||
auto P = std::make_pair( i->Name(), Utils::LogLevelToString(i->GetLoggingLevel()));
|
||||
Result.push_back(P);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
const Types::StringVec & MicroService::GetLogLevelNames() {
|
||||
static Types::StringVec LevelNames{"none", "fatal", "critical", "error", "warning", "notice", "information", "debug", "trace" };
|
||||
return LevelNames;
|
||||
}
|
||||
|
||||
uint64_t MicroService::ConfigGetInt(const std::string &Key,uint64_t Default) {
|
||||
return (uint64_t) config().getInt64(Key,Default);
|
||||
}
|
||||
|
||||
uint64_t MicroService::ConfigGetInt(const std::string &Key) {
|
||||
return config().getInt(Key);
|
||||
}
|
||||
|
||||
uint64_t MicroService::ConfigGetBool(const std::string &Key,bool Default) {
|
||||
return config().getBool(Key,Default);
|
||||
}
|
||||
|
||||
uint64_t MicroService::ConfigGetBool(const std::string &Key) {
|
||||
return config().getBool(Key);
|
||||
}
|
||||
|
||||
std::string MicroService::ConfigGetString(const std::string &Key,const std::string & Default) {
|
||||
return config().getString(Key, Default);
|
||||
}
|
||||
|
||||
std::string MicroService::ConfigGetString(const std::string &Key) {
|
||||
return config().getString(Key);
|
||||
}
|
||||
|
||||
std::string MicroService::ConfigPath(const std::string &Key,const std::string & Default) {
|
||||
std::string R = config().getString(Key, Default);
|
||||
return Poco::Path::expand(R);
|
||||
}
|
||||
|
||||
std::string MicroService::ConfigPath(const std::string &Key) {
|
||||
std::string R = config().getString(Key);
|
||||
return Poco::Path::expand(R);
|
||||
}
|
||||
|
||||
std::string MicroService::Encrypt(const std::string &S) {
|
||||
if(NoBuiltInCrypto_) {
|
||||
return S;
|
||||
}
|
||||
return Cipher_->encryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
||||
}
|
||||
|
||||
std::string MicroService::Decrypt(const std::string &S) {
|
||||
if(NoBuiltInCrypto_) {
|
||||
return S;
|
||||
}
|
||||
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
|
||||
}
|
||||
|
||||
std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
|
||||
Poco::JSON::Object Obj;
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::ID,ID_);
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::TYPE,Poco::toLower(DAEMON_APP_NAME));
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::PUBLIC,MyPublicEndPoint_);
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::PRIVATE,MyPrivateEndPoint_);
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::KEY,MyHash_);
|
||||
Obj.set(KafkaTopics::ServiceEvents::Fields::VRSN,Version_);
|
||||
std::stringstream ResultText;
|
||||
Poco::JSON::Stringifier::stringify(Obj, ResultText);
|
||||
return ResultText.str();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool MicroService::IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
|
||||
try {
|
||||
auto APIKEY = Request.get("X-API-KEY");
|
||||
return APIKEY == MyHash_;
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MicroService::SavePID() {
|
||||
try {
|
||||
std::ofstream O;
|
||||
O.open(MicroService::instance().DataDir() + "/pidfile",std::ios::binary | std::ios::trunc);
|
||||
O << Poco::Process::id();
|
||||
O.close();
|
||||
} catch (...)
|
||||
{
|
||||
std::cout << "Could not save system ID" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
int MicroService::main([[maybe_unused]] const ArgVec &args) {
|
||||
MicroServiceErrorHandler ErrorHandler(*this);
|
||||
Poco::ErrorHandler::set(&ErrorHandler);
|
||||
|
||||
if (!HelpRequested_) {
|
||||
SavePID();
|
||||
|
||||
Poco::Logger &logger = Poco::Logger::get(DAEMON_APP_NAME);
|
||||
logger.notice(fmt::format("Starting {} version {}.",DAEMON_APP_NAME, Version()));
|
||||
|
||||
if(Poco::Net::Socket::supportsIPv6())
|
||||
poco_information(logger,"System supports IPv6.");
|
||||
else
|
||||
poco_information(logger,"System does NOT support IPv6.");
|
||||
|
||||
if (config().getBool("application.runAsDaemon", false)) {
|
||||
poco_information(logger,"Starting as a daemon.");
|
||||
}
|
||||
|
||||
poco_information(logger,fmt::format("System ID set to {}",ID_));
|
||||
StartSubSystemServers();
|
||||
waitForTerminationRequest();
|
||||
StopSubSystemServers();
|
||||
logger.notice(fmt::format("Stopped {}...",DAEMON_APP_NAME));
|
||||
}
|
||||
|
||||
return Application::EXIT_OK;
|
||||
}
|
||||
|
||||
void MicroService::AddActivity(const std::string &Activity) {
|
||||
if(!DataDir_.empty()) {
|
||||
std::string ActivityFile{ DataDir_ + "/activity.log"};
|
||||
try {
|
||||
std::ofstream of(ActivityFile,std::ios_base::app | std::ios_base::out );
|
||||
auto t = std::chrono::system_clock::now();
|
||||
std::time_t now = std::chrono::system_clock::to_time_t(t);
|
||||
of << Activity << " at " << std::ctime(&now) ;
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string MicroService::Sign(Poco::JWT::Token &T, const std::string &Algo) {
|
||||
if(NoBuiltInCrypto_) {
|
||||
return T.toString();
|
||||
} else {
|
||||
return Signer_.sign(T,Algo);
|
||||
}
|
||||
}
|
||||
|
||||
void MicroService::DeleteOverrideConfiguration() {
|
||||
Poco::File F(DataDir_ + ExtraConfigurationFilename);
|
||||
|
||||
try {
|
||||
if(F.exists())
|
||||
F.remove();
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
212
src/framework/MicroServiceErrorHandler.h
Normal file
212
src/framework/MicroServiceErrorHandler.h
Normal file
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// 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/JSON/JSONException.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::TimeoutException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::TimeoutException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::NoThreadAvailableException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::NoThreadAvailableException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::OutOfMemoryException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::OutOfMemoryException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::BadCastException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::BadCastException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::DataException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::DataException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::PoolOverflowException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::PoolOverflowException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||
t_name, t_id, E.code(),
|
||||
E.displayText(),
|
||||
E.message(),
|
||||
E.what()));
|
||||
} catch (const Poco::SystemException &E) {
|
||||
poco_error(App_.logger(), fmt::format("Poco::SystemException 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;
|
||||
};
|
||||
|
||||
}
|
||||
132
src/framework/MicroServiceExtra.h
Normal file
132
src/framework/MicroServiceExtra.h
Normal file
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-26.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "Poco/BasicEvent.h"
|
||||
#include "Poco/ExpireLRUCache.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ConfigurationEntry {
|
||||
public:
|
||||
template <typename T> explicit ConfigurationEntry(T def) :
|
||||
Default_(def),
|
||||
Current_(def){
|
||||
}
|
||||
|
||||
template <typename T> explicit ConfigurationEntry(T def, T cur, const std::string &Hint="") :
|
||||
Default_(def),
|
||||
Current_(cur),
|
||||
Hint_(Hint){
|
||||
}
|
||||
|
||||
inline ConfigurationEntry()=default;
|
||||
inline ~ConfigurationEntry()=default;
|
||||
|
||||
template <typename T> explicit operator T () const { return std::get<T>(Current_); }
|
||||
inline ConfigurationEntry & operator=(const char *v) { Current_ = std::string(v); return *this;}
|
||||
template <typename T> ConfigurationEntry & operator=(T v) { Current_ = (T) v; return *this;}
|
||||
|
||||
void reset() {
|
||||
Current_ = Default_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::variant<bool,uint64_t,std::string> Default_, Current_;
|
||||
std::string Hint_;
|
||||
};
|
||||
inline std::string to_string(const ConfigurationEntry &v) { return (std::string) v; }
|
||||
|
||||
typedef std::map<std::string,ConfigurationEntry> ConfigurationMap_t;
|
||||
|
||||
template <typename T> class FIFO {
|
||||
public:
|
||||
explicit FIFO(uint32_t Size) :
|
||||
Size_(Size) {
|
||||
Buffer_ = new T [Size_];
|
||||
}
|
||||
|
||||
~FIFO() {
|
||||
delete [] Buffer_;
|
||||
}
|
||||
|
||||
mutable Poco::BasicEvent<bool> Writable_;
|
||||
mutable Poco::BasicEvent<bool> Readable_;
|
||||
|
||||
inline bool Read(T &t) {
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
if (Write_ == Read_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
t = Buffer_[Read_++];
|
||||
if (Read_ == Size_) {
|
||||
Read_ = 0;
|
||||
}
|
||||
Used_--;
|
||||
}
|
||||
bool flag = true;
|
||||
Writable_.notify(this, flag);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Write(const T &t) {
|
||||
{
|
||||
std::lock_guard M(Mutex_);
|
||||
|
||||
Buffer_[Write_++] = t;
|
||||
if (Write_ == Size_) {
|
||||
Write_ = 0;
|
||||
}
|
||||
Used_++;
|
||||
MaxEverUsed_ = std::max(Used_,MaxEverUsed_);
|
||||
}
|
||||
bool flag = true;
|
||||
Readable_.notify(this, flag);
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool isFull() {
|
||||
std::lock_guard M(Mutex_);
|
||||
return Used_==Buffer_->capacity();
|
||||
}
|
||||
|
||||
inline auto MaxEverUser() const { return MaxEverUsed_; }
|
||||
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
uint32_t Size_=0;
|
||||
uint32_t Read_=0;
|
||||
uint32_t Write_=0;
|
||||
uint32_t Used_=0;
|
||||
uint32_t MaxEverUsed_=0;
|
||||
T * Buffer_ = nullptr;
|
||||
};
|
||||
|
||||
template <class Record, typename KeyType = std::string, int Size=256, int Expiry=60000> class RecordCache {
|
||||
public:
|
||||
explicit RecordCache( KeyType Record::* Q) :
|
||||
MemberOffset(Q){
|
||||
};
|
||||
inline auto update(const Record &R) {
|
||||
return Cache_.update(R.*MemberOffset, R);
|
||||
}
|
||||
inline auto get(const KeyType &K) {
|
||||
return Cache_.get(K);
|
||||
}
|
||||
inline auto remove(const KeyType &K) {
|
||||
return Cache_.remove(K);
|
||||
}
|
||||
inline auto remove(const Record &R) {
|
||||
return Cache_.remove(R.*MemberOffset);
|
||||
}
|
||||
private:
|
||||
KeyType Record::* MemberOffset;
|
||||
Poco::ExpireLRUCache<KeyType,Record> Cache_{Size,Expiry};
|
||||
};
|
||||
}
|
||||
121
src/framework/MicroServiceFuncs.cpp
Normal file
121
src/framework/MicroServiceFuncs.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
const std::string &MicroServiceDataDirectory() { return MicroService::instance().DataDir(); }
|
||||
|
||||
Types::MicroServiceMetaVec MicroServiceGetServices(const std::string &Type) {
|
||||
return MicroService::instance().GetServices(Type);
|
||||
}
|
||||
|
||||
Types::MicroServiceMetaVec MicroServiceGetServices() {
|
||||
return MicroService::instance().GetServices();
|
||||
}
|
||||
|
||||
std::string MicroServicePublicEndPoint() { return MicroService::instance().PublicEndPoint(); }
|
||||
|
||||
std::string MicroServiceConfigGetString(const std::string &Key, const std::string &DefaultValue) {
|
||||
return MicroService::instance().ConfigGetString(Key, DefaultValue);
|
||||
}
|
||||
|
||||
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue) {
|
||||
return MicroService::instance().ConfigGetBool(Key, DefaultValue);
|
||||
}
|
||||
|
||||
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue) {
|
||||
return MicroService::instance().ConfigGetInt(Key, DefaultValue);
|
||||
}
|
||||
|
||||
std::string MicroServicePrivateEndPoint() { return MicroService::instance().PrivateEndPoint(); }
|
||||
|
||||
std::uint64_t MicroServiceID() { return MicroService::instance().ID(); }
|
||||
|
||||
bool MicroServiceIsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
|
||||
return MicroService::instance().IsValidAPIKEY(Request);
|
||||
}
|
||||
|
||||
bool MicroServiceNoAPISecurity() { return MicroService::instance().NoAPISecurity(); }
|
||||
|
||||
void MicroServiceLoadConfigurationFile() { MicroService::instance().LoadConfigurationFile(); }
|
||||
|
||||
void MicroServiceReload() { MicroService::instance().Reload(); }
|
||||
|
||||
void MicroServiceReload(const std::string &Type) { MicroService::instance().Reload(Type); }
|
||||
|
||||
const Types::StringVec MicroServiceGetLogLevelNames() {
|
||||
return MicroService::instance().GetLogLevelNames();
|
||||
}
|
||||
|
||||
const Types::StringVec MicroServiceGetSubSystems() {
|
||||
return MicroService::instance().GetSubSystems();
|
||||
}
|
||||
|
||||
Types::StringPairVec MicroServiceGetLogLevels() { return MicroService::instance().GetLogLevels(); }
|
||||
|
||||
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
|
||||
return MicroService::instance().SetSubsystemLogLevel(SubSystem, Level);
|
||||
}
|
||||
|
||||
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer) {
|
||||
MicroService::instance().GetExtraConfiguration(Answer);
|
||||
}
|
||||
|
||||
std::string MicroServiceVersion() { return MicroService::instance().Version(); }
|
||||
|
||||
std::uint64_t MicroServiceUptimeTotalSeconds() {
|
||||
return MicroService::instance().uptime().totalSeconds();
|
||||
}
|
||||
|
||||
std::uint64_t MicroServiceStartTimeEpochTime() {
|
||||
return MicroService::instance().startTime().epochTime();
|
||||
}
|
||||
|
||||
std::string MicroServiceGetUIURI() { return MicroService::instance().GetUIURI(); }
|
||||
|
||||
const SubSystemVec MicroServiceGetFullSubSystems() {
|
||||
return MicroService::instance().GetFullSubSystems();
|
||||
}
|
||||
|
||||
std::string MicroServiceCreateUUID() { return MicroService::CreateUUID(); }
|
||||
|
||||
std::uint64_t MicroServiceDaemonBusTimer() { return MicroService::instance().DaemonBusTimer(); }
|
||||
|
||||
std::string MicroServiceMakeSystemEventMessage(const std::string &Type) {
|
||||
return MicroService::instance().MakeSystemEventMessage(Type);
|
||||
}
|
||||
|
||||
Poco::ThreadPool &MicroServiceTimerPool() { return MicroService::instance().TimerPool(); }
|
||||
|
||||
std::string MicroServiceConfigPath(const std::string &Key,
|
||||
const std::string &DefaultValue) {
|
||||
return MicroService::instance().ConfigPath(Key, DefaultValue);
|
||||
}
|
||||
|
||||
std::string MicroServiceWWWAssetsDir() {
|
||||
return MicroService::instance().WWWAssetsDir();
|
||||
}
|
||||
|
||||
std::uint64_t MicroServiceRandom(std::uint64_t Start,std::uint64_t End) {
|
||||
return MicroService::instance().Random(Start, End);
|
||||
}
|
||||
|
||||
std::uint64_t MicroServiceRandom(std::uint64_t Range) {
|
||||
return MicroService::instance().Random(Range);
|
||||
}
|
||||
|
||||
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo) {
|
||||
return MicroService::instance().Sign(T, Algo);
|
||||
}
|
||||
|
||||
std::string MicroServiceGetPublicAPIEndPoint() {
|
||||
return MicroService::instance().GetPublicAPIEndPoint();
|
||||
}
|
||||
|
||||
void MicroServiceDeleteOverrideConfiguration() {
|
||||
return MicroService::instance().DeleteOverrideConfiguration();
|
||||
}
|
||||
}
|
||||
56
src/framework/MicroServiceFuncs.h
Normal file
56
src/framework/MicroServiceFuncs.h
Normal file
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/ThreadPool.h"
|
||||
#include "Poco/JWT/Token.h"
|
||||
|
||||
|
||||
namespace OpenWifi {
|
||||
class SubSystemServer;
|
||||
using SubSystemVec=std::vector<SubSystemServer *>;
|
||||
const std::string & MicroServiceDataDirectory();
|
||||
Types::MicroServiceMetaVec MicroServiceGetServices(const std::string & Type);
|
||||
Types::MicroServiceMetaVec MicroServiceGetServices();
|
||||
std::string MicroServicePublicEndPoint();
|
||||
std::string MicroServiceConfigGetString(const std::string &Key, const std::string &DefaultValue);
|
||||
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
|
||||
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
|
||||
std::string MicroServicePrivateEndPoint();
|
||||
std::uint64_t MicroServiceID();
|
||||
bool MicroServiceIsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
|
||||
bool MicroServiceNoAPISecurity();
|
||||
void MicroServiceLoadConfigurationFile();
|
||||
void MicroServiceReload();
|
||||
void MicroServiceReload(const std::string &Type);
|
||||
const Types::StringVec MicroServiceGetLogLevelNames();
|
||||
const Types::StringVec MicroServiceGetSubSystems();
|
||||
Types::StringPairVec MicroServiceGetLogLevels();
|
||||
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
|
||||
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer);
|
||||
std::string MicroServiceVersion();
|
||||
std::uint64_t MicroServiceUptimeTotalSeconds();
|
||||
std::uint64_t MicroServiceStartTimeEpochTime();
|
||||
std::string MicroServiceGetUIURI();
|
||||
const SubSystemVec MicroServiceGetFullSubSystems();
|
||||
std::string MicroServiceCreateUUID();
|
||||
std::uint64_t MicroServiceDaemonBusTimer();
|
||||
std::string MicroServiceMakeSystemEventMessage( const std::string & Type );
|
||||
Poco::ThreadPool & MicroServiceTimerPool();
|
||||
std::string MicroServiceConfigPath(const std::string &Key,
|
||||
const std::string &DefaultValue);
|
||||
std::string MicroServiceWWWAssetsDir();
|
||||
std::uint64_t MicroServiceRandom(std::uint64_t Start,std::uint64_t End);
|
||||
std::uint64_t MicroServiceRandom(std::uint64_t Range);
|
||||
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo);
|
||||
std::string MicroServiceGetPublicAPIEndPoint();
|
||||
void MicroServiceDeleteOverrideConfiguration();
|
||||
}
|
||||
22
src/framework/MicroServiceNames.h
Normal file
22
src/framework/MicroServiceNames.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string uSERVICE_SECURITY{"owsec"};
|
||||
static const std::string uSERVICE_GATEWAY{"owgw"};
|
||||
static const std::string uSERVICE_FIRMWARE{ "owfms"};
|
||||
static const std::string uSERVICE_TOPOLOGY{ "owtopo"};
|
||||
static const std::string uSERVICE_PROVISIONING{ "owprov"};
|
||||
static const std::string uSERVICE_OWLS{ "owls"};
|
||||
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
|
||||
static const std::string uSERVICE_INSTALLER{ "owinst"};
|
||||
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
|
||||
static const std::string uSERVICE_OWRRM{ "owrrm"};
|
||||
|
||||
}
|
||||
289
src/framework/OpenAPIRequests.cpp
Normal file
289
src/framework/OpenAPIRequests.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "OpenAPIRequests.h"
|
||||
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
#include "Poco/Net/HTTPSClientSession.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
#include "fmt/format.h"
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestGet::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
|
||||
try {
|
||||
|
||||
auto Services = MicroServiceGetServices(Type_);
|
||||
for(auto const &Svc:Services) {
|
||||
Poco::URI URI(Svc.PrivateEndPoint);
|
||||
|
||||
auto Secure = (URI.getScheme() == "https");
|
||||
|
||||
URI.setPath(EndPoint_);
|
||||
for (const auto &qp : QueryData_)
|
||||
URI.addQueryParameter(qp.first, qp.second);
|
||||
|
||||
std::string Path(URI.getPathAndQuery());
|
||||
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Path,
|
||||
Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
|
||||
poco_debug(Poco::Logger::get("REST-CALLER-GET"), fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
|
||||
|
||||
if(BearerToken.empty()) {
|
||||
Request.add("X-API-KEY", Svc.AccessKey);
|
||||
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
|
||||
} else {
|
||||
// Authorization: Bearer ${token}
|
||||
Request.add("Authorization", "Bearer " + BearerToken);
|
||||
}
|
||||
|
||||
if(Secure) {
|
||||
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
|
||||
Session.sendRequest(Request);
|
||||
|
||||
Poco::Net::HTTPResponse Response;
|
||||
std::istream &is = Session.receiveResponse(Response);
|
||||
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
return Response.getStatus();
|
||||
} else {
|
||||
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
|
||||
Session.sendRequest(Request);
|
||||
|
||||
Poco::Net::HTTPResponse Response;
|
||||
std::istream &is = Session.receiveResponse(Response);
|
||||
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
return Response.getStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E)
|
||||
{
|
||||
Poco::Logger::get("REST-CALLER-GET").log(E);
|
||||
}
|
||||
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
|
||||
}
|
||||
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPut::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
|
||||
try {
|
||||
auto Services = MicroServiceGetServices(Type_);
|
||||
for(auto const &Svc:Services) {
|
||||
Poco::URI URI(Svc.PrivateEndPoint);
|
||||
|
||||
auto Secure = (URI.getScheme() == "https");
|
||||
|
||||
URI.setPath(EndPoint_);
|
||||
for (const auto &qp : QueryData_)
|
||||
URI.addQueryParameter(qp.first, qp.second);
|
||||
|
||||
poco_debug(Poco::Logger::get("REST-CALLER-PUT"), fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
|
||||
|
||||
std::string Path(URI.getPathAndQuery());
|
||||
|
||||
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Path,
|
||||
Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
std::ostringstream obody;
|
||||
Poco::JSON::Stringifier::stringify(Body_,obody);
|
||||
|
||||
Request.setContentType("application/json");
|
||||
Request.setContentLength(obody.str().size());
|
||||
|
||||
if(BearerToken.empty()) {
|
||||
Request.add("X-API-KEY", Svc.AccessKey);
|
||||
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
|
||||
} else {
|
||||
// Authorization: Bearer ${token}
|
||||
Request.add("Authorization", "Bearer " + BearerToken);
|
||||
}
|
||||
|
||||
if(Secure) {
|
||||
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
|
||||
std::ostream &os = Session.sendRequest(Request);
|
||||
os << obody.str();
|
||||
|
||||
Poco::Net::HTTPResponse Response;
|
||||
std::istream &is = Session.receiveResponse(Response);
|
||||
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
return Response.getStatus();
|
||||
} else {
|
||||
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
|
||||
std::ostream &os = Session.sendRequest(Request);
|
||||
os << obody.str();
|
||||
|
||||
Poco::Net::HTTPResponse Response;
|
||||
std::istream &is = Session.receiveResponse(Response);
|
||||
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
return Response.getStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E)
|
||||
{
|
||||
Poco::Logger::get("REST-CALLER-PUT").log(E);
|
||||
}
|
||||
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
|
||||
}
|
||||
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPost::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
|
||||
try {
|
||||
auto Services = MicroServiceGetServices(Type_);
|
||||
|
||||
for(auto const &Svc:Services) {
|
||||
Poco::URI URI(Svc.PrivateEndPoint);
|
||||
|
||||
|
||||
auto Secure = (URI.getScheme() == "https");
|
||||
|
||||
URI.setPath(EndPoint_);
|
||||
for (const auto &qp : QueryData_)
|
||||
URI.addQueryParameter(qp.first, qp.second);
|
||||
|
||||
poco_debug(Poco::Logger::get("REST-CALLER-POST"),fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
|
||||
|
||||
std::string Path(URI.getPathAndQuery());
|
||||
|
||||
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Path,
|
||||
Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
std::ostringstream obody;
|
||||
Poco::JSON::Stringifier::stringify(Body_,obody);
|
||||
|
||||
Request.setContentType("application/json");
|
||||
Request.setContentLength(obody.str().size());
|
||||
|
||||
if(BearerToken.empty()) {
|
||||
Request.add("X-API-KEY", Svc.AccessKey);
|
||||
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
|
||||
} else {
|
||||
// Authorization: Bearer ${token}
|
||||
Request.add("Authorization", "Bearer " + BearerToken);
|
||||
}
|
||||
|
||||
if(Secure) {
|
||||
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
std::ostream &os = Session.sendRequest(Request);
|
||||
os << obody.str();
|
||||
|
||||
Poco::Net::HTTPResponse Response;
|
||||
std::istream &is = Session.receiveResponse(Response);
|
||||
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
return Response.getStatus();
|
||||
} else {
|
||||
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
std::ostream &os = Session.sendRequest(Request);
|
||||
os << obody.str();
|
||||
|
||||
Poco::Net::HTTPResponse Response;
|
||||
std::istream &is = Session.receiveResponse(Response);
|
||||
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
Poco::JSON::Parser P;
|
||||
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
return Response.getStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E)
|
||||
{
|
||||
Poco::Logger::get("REST-CALLER-POST").log(E);
|
||||
}
|
||||
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
|
||||
}
|
||||
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestDelete::Do(const std::string & BearerToken) {
|
||||
try {
|
||||
auto Services = MicroServiceGetServices(Type_);
|
||||
|
||||
for(auto const &Svc:Services) {
|
||||
Poco::URI URI(Svc.PrivateEndPoint);
|
||||
|
||||
auto Secure = (URI.getScheme() == "https");
|
||||
|
||||
URI.setPath(EndPoint_);
|
||||
for (const auto &qp : QueryData_)
|
||||
URI.addQueryParameter(qp.first, qp.second);
|
||||
|
||||
poco_debug(Poco::Logger::get("REST-CALLER-DELETE"),fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
|
||||
|
||||
std::string Path(URI.getPathAndQuery());
|
||||
|
||||
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Path,
|
||||
Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
if(BearerToken.empty()) {
|
||||
Request.add("X-API-KEY", Svc.AccessKey);
|
||||
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
|
||||
} else {
|
||||
// Authorization: Bearer ${token}
|
||||
Request.add("Authorization", "Bearer " + BearerToken);
|
||||
}
|
||||
|
||||
if(Secure) {
|
||||
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
Session.sendRequest(Request);
|
||||
Poco::Net::HTTPResponse Response;
|
||||
Session.receiveResponse(Response);
|
||||
return Response.getStatus();
|
||||
} else {
|
||||
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
|
||||
Session.sendRequest(Request);
|
||||
Poco::Net::HTTPResponse Response;
|
||||
Session.receiveResponse(Response);
|
||||
return Response.getStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception &E)
|
||||
{
|
||||
Poco::Logger::get("REST-CALLER-DELETE").log(E);
|
||||
}
|
||||
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
|
||||
}
|
||||
|
||||
|
||||
} // namespace OpenWifi
|
||||
110
src/framework/OpenAPIRequests.h
Normal file
110
src/framework/OpenAPIRequests.h
Normal file
@@ -0,0 +1,110 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
|
||||
#include "framework/OpenWifiTypes.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class OpenAPIRequestGet {
|
||||
public:
|
||||
explicit OpenAPIRequestGet( const std::string & Type,
|
||||
const std::string & EndPoint,
|
||||
const Types::StringPairVec & QueryData,
|
||||
uint64_t msTimeout,
|
||||
const std::string &LoggingStr=""):
|
||||
Type_(Type),
|
||||
EndPoint_(EndPoint),
|
||||
QueryData_(QueryData),
|
||||
msTimeout_(msTimeout),
|
||||
LoggingStr_(LoggingStr){};
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
|
||||
private:
|
||||
std::string Type_;
|
||||
std::string EndPoint_;
|
||||
Types::StringPairVec QueryData_;
|
||||
uint64_t msTimeout_;
|
||||
std::string LoggingStr_;
|
||||
};
|
||||
|
||||
class OpenAPIRequestPut {
|
||||
public:
|
||||
explicit OpenAPIRequestPut( const std::string & Type,
|
||||
const std::string & EndPoint,
|
||||
const Types::StringPairVec & QueryData,
|
||||
const Poco::JSON::Object & Body,
|
||||
uint64_t msTimeout,
|
||||
const std::string &LoggingStr=""):
|
||||
Type_(Type),
|
||||
EndPoint_(EndPoint),
|
||||
QueryData_(QueryData),
|
||||
msTimeout_(msTimeout),
|
||||
Body_(Body),
|
||||
LoggingStr_(LoggingStr){};
|
||||
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
|
||||
|
||||
private:
|
||||
std::string Type_;
|
||||
std::string EndPoint_;
|
||||
Types::StringPairVec QueryData_;
|
||||
uint64_t msTimeout_;
|
||||
Poco::JSON::Object Body_;
|
||||
std::string LoggingStr_;
|
||||
};
|
||||
|
||||
class OpenAPIRequestPost {
|
||||
public:
|
||||
explicit OpenAPIRequestPost( const std::string & Type,
|
||||
const std::string & EndPoint,
|
||||
const Types::StringPairVec & QueryData,
|
||||
const Poco::JSON::Object & Body,
|
||||
uint64_t msTimeout,
|
||||
const std::string &LoggingStr=""):
|
||||
Type_(Type),
|
||||
EndPoint_(EndPoint),
|
||||
QueryData_(QueryData),
|
||||
msTimeout_(msTimeout),
|
||||
Body_(Body),
|
||||
LoggingStr_(LoggingStr){};
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
|
||||
private:
|
||||
std::string Type_;
|
||||
std::string EndPoint_;
|
||||
Types::StringPairVec QueryData_;
|
||||
uint64_t msTimeout_;
|
||||
Poco::JSON::Object Body_;
|
||||
std::string LoggingStr_;
|
||||
};
|
||||
|
||||
class OpenAPIRequestDelete {
|
||||
public:
|
||||
explicit OpenAPIRequestDelete( const std::string & Type,
|
||||
const std::string & EndPoint,
|
||||
const Types::StringPairVec & QueryData,
|
||||
uint64_t msTimeout,
|
||||
const std::string &LoggingStr=""):
|
||||
Type_(Type),
|
||||
EndPoint_(EndPoint),
|
||||
QueryData_(QueryData),
|
||||
msTimeout_(msTimeout),
|
||||
LoggingStr_(LoggingStr){};
|
||||
Poco::Net::HTTPServerResponse::HTTPStatus Do(const std::string & BearerToken = "");
|
||||
|
||||
private:
|
||||
std::string Type_;
|
||||
std::string EndPoint_;
|
||||
Types::StringPairVec QueryData_;
|
||||
uint64_t msTimeout_;
|
||||
Poco::JSON::Object Body_;
|
||||
std::string LoggingStr_;
|
||||
};
|
||||
|
||||
} // namespace OpenWifi
|
||||
@@ -28,6 +28,19 @@ namespace OpenWifi::Types {
|
||||
typedef std::string UUID_t;
|
||||
typedef std::vector<UUID_t> UUIDvec_t;
|
||||
typedef std::map<std::string,std::map<uint32_t,uint64_t>> Counted3DMapSII;
|
||||
|
||||
struct MicroServiceMeta {
|
||||
uint64_t Id=0;
|
||||
std::string Type;
|
||||
std::string PrivateEndPoint;
|
||||
std::string PublicEndPoint;
|
||||
std::string AccessKey;
|
||||
std::string Version;
|
||||
uint64_t LastUpdate=0;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, MicroServiceMeta> MicroServiceMetaMap;
|
||||
typedef std::vector<MicroServiceMeta> MicroServiceMetaVec;
|
||||
}
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
27
src/framework/RESTAPI_ExtServer.cpp
Normal file
27
src/framework/RESTAPI_ExtServer.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "framework/RESTAPI_ExtServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler *ExtRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &Request) {
|
||||
try {
|
||||
Poco::URI uri(Request.getURI());
|
||||
auto TID = NextTransactionId_++;
|
||||
Utils::SetThreadName(fmt::format("x-rest:{}",TID).c_str());
|
||||
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TID);
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Poco::Net::HTTPRequestHandler *RESTAPI_ExtServer::CallServer(const std::string &Path, uint64_t Id) {
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
|
||||
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
|
||||
}
|
||||
|
||||
}
|
||||
99
src/framework/RESTAPI_ExtServer.h
Normal file
99
src/framework/RESTAPI_ExtServer.h
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t Id);
|
||||
|
||||
class ExtRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
ExtRequestHandlerFactory() = default;
|
||||
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override;
|
||||
private:
|
||||
static inline std::atomic_uint64_t NextTransactionId_ = 1;
|
||||
};
|
||||
|
||||
class RESTAPI_ExtServer : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new RESTAPI_ExtServer;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
inline int Start() override {
|
||||
poco_information(Logger(),"Starting.");
|
||||
Server_.InitLogging();
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
|
||||
if(MicroServiceNoAPISecurity()) {
|
||||
poco_information(Logger(),fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port()));
|
||||
} else {
|
||||
poco_information(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(),
|
||||
Svr.KeyFile(),Svr.CertFile()));
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
}
|
||||
|
||||
Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setKeepAlive(true);
|
||||
Params->setName("ws:xrest");
|
||||
|
||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||
if(MicroServiceNoAPISecurity()) {
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory, Pool_, Sock, Params);
|
||||
} else {
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory, Pool_, Sock, Params);
|
||||
};
|
||||
NewServer->start();
|
||||
RESTServers_.push_back(std::move(NewServer));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() override {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stopAll(true);
|
||||
Pool_.stopAll();
|
||||
Pool_.joinAll();
|
||||
RESTServers_.clear();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
|
||||
MicroServiceLoadConfigurationFile();
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id);
|
||||
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_{"x-rest",8,128};
|
||||
RESTAPI_GenericServerAccounting Server_;
|
||||
|
||||
RESTAPI_ExtServer() noexcept:
|
||||
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline auto RESTAPI_ExtServer() { return RESTAPI_ExtServer::instance(); };
|
||||
|
||||
}
|
||||
75
src/framework/RESTAPI_GenericServerAccounting.h
Normal file
75
src/framework/RESTAPI_GenericServerAccounting.h
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/String.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
|
||||
#include "framework/MicroServiceFuncs.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_GenericServerAccounting {
|
||||
public:
|
||||
|
||||
enum {
|
||||
LOG_GET=0,
|
||||
LOG_DELETE,
|
||||
LOG_PUT,
|
||||
LOG_POST
|
||||
};
|
||||
|
||||
void inline SetFlags(bool External, const std::string &Methods) {
|
||||
Poco::StringTokenizer Tokens(Methods,",");
|
||||
auto Offset = (External ? 0 : 4);
|
||||
for(const auto &i:Tokens) {
|
||||
if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_DELETE)==0)
|
||||
LogFlags_[Offset+LOG_DELETE]=true;
|
||||
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_PUT)==0)
|
||||
LogFlags_[Offset+LOG_PUT]=true;
|
||||
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_POST)==0)
|
||||
LogFlags_[Offset+LOG_POST]=true;
|
||||
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_GET)==0)
|
||||
LogFlags_[Offset+LOG_GET]=true;
|
||||
}
|
||||
}
|
||||
|
||||
inline void InitLogging() {
|
||||
std::string Public = MicroServiceConfigGetString("apilogging.public.methods","PUT,POST,DELETE");
|
||||
SetFlags(true, Public);
|
||||
std::string Private = MicroServiceConfigGetString("apilogging.private.methods","PUT,POST,DELETE");
|
||||
SetFlags(false, Private);
|
||||
|
||||
std::string PublicBadTokens = MicroServiceConfigGetString("apilogging.public.badtokens.methods","");
|
||||
LogBadTokens_[0] = (Poco::icompare(PublicBadTokens,"true")==0);
|
||||
std::string PrivateBadTokens = MicroServiceConfigGetString("apilogging.private.badtokens.methods","");
|
||||
LogBadTokens_[1] = (Poco::icompare(PrivateBadTokens,"true")==0);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool LogIt(const std::string &Method, bool External) const {
|
||||
auto Offset = (External ? 0 : 4);
|
||||
if(Method == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
return LogFlags_[Offset+LOG_GET];
|
||||
if(Method == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
return LogFlags_[Offset+LOG_POST];
|
||||
if(Method == Poco::Net::HTTPRequest::HTTP_PUT)
|
||||
return LogFlags_[Offset+LOG_PUT];
|
||||
if(Method == Poco::Net::HTTPRequest::HTTP_DELETE)
|
||||
return LogFlags_[Offset+LOG_DELETE];
|
||||
return false;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline bool LogBadTokens(bool External) const {
|
||||
return LogBadTokens_[ (External ? 0 : 1) ];
|
||||
};
|
||||
|
||||
private:
|
||||
std::array<bool,8> LogFlags_{false};
|
||||
std::array<bool,2> LogBadTokens_{false};
|
||||
};
|
||||
}
|
||||
8
src/framework/RESTAPI_Handler.cpp
Normal file
8
src/framework/RESTAPI_Handler.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
} // namespace OpenWifi
|
||||
826
src/framework/RESTAPI_Handler.h
Normal file
826
src/framework/RESTAPI_Handler.h
Normal file
@@ -0,0 +1,826 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Logger.h"
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/Net/HTTPResponse.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
#include "Poco/DeflatingStream.h"
|
||||
#include "Poco/TemporaryFile.h"
|
||||
#include "Poco/Net/OAuth20Credentials.h"
|
||||
|
||||
#include "framework/ow_constants.h"
|
||||
#include "framework/RESTAPI_GenericServerAccounting.h"
|
||||
#include "framework/RESTAPI_RateLimiter.h"
|
||||
#include "framework/utils.h"
|
||||
#include "framework/RESTAPI_utils.h"
|
||||
#include "framework/AuthClient.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
#if defined(TIP_SECURITY_SERVICE)
|
||||
#include "AuthService.h"
|
||||
#endif
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
struct QueryBlock {
|
||||
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
|
||||
std::string SerialNumber, Filter;
|
||||
std::vector<std::string> Select;
|
||||
bool Lifetime=false, LastOnly=false, Newest=false, CountOnly=false, AdditionalInfo=false;
|
||||
};
|
||||
typedef std::map<std::string, std::string> BindingMap;
|
||||
|
||||
struct RateLimit {
|
||||
int64_t Interval=1000;
|
||||
int64_t MaxCalls=10;
|
||||
};
|
||||
|
||||
RESTAPIHandler( BindingMap map,
|
||||
Poco::Logger &l,
|
||||
std::vector<std::string> Methods,
|
||||
RESTAPI_GenericServerAccounting & Server,
|
||||
uint64_t TransactionId,
|
||||
bool Internal,
|
||||
bool AlwaysAuthorize=true,
|
||||
bool RateLimited=false,
|
||||
const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100},
|
||||
bool SubscriberOnly=false)
|
||||
: Bindings_(std::move(map)),
|
||||
Logger_(l),
|
||||
Methods_(std::move(Methods)),
|
||||
Internal_(Internal),
|
||||
RateLimited_(RateLimited),
|
||||
SubOnlyService_(SubscriberOnly),
|
||||
AlwaysAuthorize_(AlwaysAuthorize),
|
||||
Server_(Server),
|
||||
MyRates_(Profile),
|
||||
TransactionId_(TransactionId)
|
||||
{
|
||||
}
|
||||
|
||||
inline bool RoleIsAuthorized([[maybe_unused]] const std::string & Path, [[maybe_unused]] const std::string & Method, [[maybe_unused]] std::string & Reason) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void handleRequest(Poco::Net::HTTPServerRequest &RequestIn,
|
||||
Poco::Net::HTTPServerResponse &ResponseIn) final {
|
||||
try {
|
||||
Request = &RequestIn;
|
||||
Response = &ResponseIn;
|
||||
|
||||
// std::string th_name = "restsvr_" + std::to_string(TransactionId_);
|
||||
// Utils::SetThreadName(th_name.c_str());
|
||||
|
||||
if(Request->getContentLength()>0) {
|
||||
if(Request->getContentType().find("application/json")!=std::string::npos) {
|
||||
ParsedBody_ = IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
}
|
||||
|
||||
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) {
|
||||
return UnAuthorized(RESTAPI::Errors::RATE_LIMIT_EXCEEDED);
|
||||
}
|
||||
|
||||
if (!ContinueProcessing())
|
||||
return;
|
||||
|
||||
bool Expired=false, Contacted=false;
|
||||
if (AlwaysAuthorize_ && !IsAuthorized(Expired, Contacted, SubOnlyService_)) {
|
||||
if(Expired)
|
||||
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
|
||||
if(Contacted)
|
||||
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
|
||||
else
|
||||
return UnAuthorized(RESTAPI::Errors::SECURITY_SERVICE_UNREACHABLE);
|
||||
}
|
||||
|
||||
std::string Reason;
|
||||
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
|
||||
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
ParseParameters();
|
||||
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
return DoGet();
|
||||
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
return DoPost();
|
||||
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE)
|
||||
return DoDelete();
|
||||
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_PUT)
|
||||
return DoPut();
|
||||
return BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
return BadRequest(RESTAPI::Errors::InternalError);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; }
|
||||
[[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; }
|
||||
|
||||
inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) {
|
||||
bindings.clear();
|
||||
auto PathItems = Poco::StringTokenizer(Request, "/");
|
||||
|
||||
for(const auto &EndPoint:EndPoints) {
|
||||
auto ParamItems = Poco::StringTokenizer(EndPoint, "/");
|
||||
if (PathItems.count() != ParamItems.count())
|
||||
continue;
|
||||
|
||||
bool Matched = true;
|
||||
for (size_t i = 0; i < PathItems.count(); i++) {
|
||||
if (PathItems[i] != ParamItems[i]) {
|
||||
if (ParamItems[i][0] == '{') {
|
||||
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
|
||||
bindings[Poco::toLower(ParamName)] = PathItems[i];
|
||||
} else {
|
||||
Matched = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(Matched)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void PrintBindings() {
|
||||
for (const auto &[key, value] : Bindings_)
|
||||
std::cout << "Key = " << key << " Value= " << value << std::endl;
|
||||
}
|
||||
|
||||
inline void ParseParameters() {
|
||||
Poco::URI uri(Request->getURI());
|
||||
Parameters_ = uri.getQueryParameters();
|
||||
InitQueryBlock();
|
||||
}
|
||||
|
||||
inline static bool is_number(const std::string &s) {
|
||||
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
|
||||
}
|
||||
|
||||
inline static bool is_bool(const std::string &s) {
|
||||
if (s == "true" || s == "false")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uint64_t GetParameter(const std::string &Name, const uint64_t Default) {
|
||||
auto Hint = std::find_if(Parameters_.begin(),Parameters_.end(),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==Parameters_.end() || !is_number(Hint->second))
|
||||
return Default;
|
||||
return std::stoull(Hint->second);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool GetBoolParameter(const std::string &Name, bool Default=false) {
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==end(Parameters_) || !is_bool(Hint->second))
|
||||
return Default;
|
||||
return Hint->second=="true";
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string GetParameter(const std::string &Name, const std::string &Default="") {
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==end(Parameters_))
|
||||
return Default;
|
||||
return Hint->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool HasParameter(const std::string &Name, std::string &Value) {
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==end(Parameters_))
|
||||
return false;
|
||||
Value = Hint->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool HasParameter(const std::string &Name, uint64_t & Value) {
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==end(Parameters_))
|
||||
return false;
|
||||
Value = std::stoull(Hint->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const std::string & GetBinding(const std::string &Name, const std::string &Default="") {
|
||||
auto E = Bindings_.find(Poco::toLower(Name));
|
||||
if (E == Bindings_.end())
|
||||
return Default;
|
||||
|
||||
return E->second;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline static std::string MakeList(const std::vector<std::string> &L) {
|
||||
std::string Return;
|
||||
for (const auto &i : L) {
|
||||
if (Return.empty())
|
||||
Return = i;
|
||||
else
|
||||
Return += ", " + i;
|
||||
}
|
||||
return Return;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Types::UUIDvec_t & Value) {
|
||||
if(O->has(Field) && O->isArray(Field)) {
|
||||
auto Arr = O->getArray(Field);
|
||||
for(const auto &i:*Arr)
|
||||
Value.emplace_back(i.toString());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, std::string &Value) {
|
||||
if(O->has(Field)) {
|
||||
Value = O->get(Field).toString();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, uint64_t &Value) {
|
||||
if(O->has(Field)) {
|
||||
Value = O->get(Field);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, bool &Value) {
|
||||
if(O->has(Field)) {
|
||||
Value = O->get(Field).toString()=="true";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, double &Value) {
|
||||
if(O->has(Field)) {
|
||||
Value = (double) O->get(Field);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) {
|
||||
if(O->has(Field)) {
|
||||
std::string Content = O->get(Field).toString();
|
||||
auto DecodedBlob = Utils::base64decode(Content);
|
||||
Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
|
||||
if(O->has(Field)) {
|
||||
assignee = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void SetCommonHeaders(bool CloseConnection=false) {
|
||||
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Response->setChunkedTransferEncoding(true);
|
||||
Response->setContentType("application/json");
|
||||
auto Origin = Request->find("Origin");
|
||||
if (Origin != Request->end()) {
|
||||
Response->set("Access-Control-Allow-Origin", Origin->second);
|
||||
} else {
|
||||
Response->set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
Response->set("Vary", "Origin, Accept-Encoding");
|
||||
if(CloseConnection) {
|
||||
Response->set("Connection", "close");
|
||||
Response->setKeepAlive(false);
|
||||
} else {
|
||||
Response->setKeepAlive(true);
|
||||
Response->set("Connection", "Keep-Alive");
|
||||
Response->set("Keep-Alive", "timeout=30, max=1000");
|
||||
}
|
||||
}
|
||||
|
||||
inline void ProcessOptions() {
|
||||
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Response->setChunkedTransferEncoding(true);
|
||||
auto Origin = Request->find("Origin");
|
||||
if (Origin != Request->end()) {
|
||||
Response->set("Access-Control-Allow-Origin", Origin->second);
|
||||
} else {
|
||||
Response->set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
Response->set("Access-Control-Allow-Methods", MakeList(Methods_));
|
||||
auto RequestHeaders = Request->find("Access-Control-Request-Headers");
|
||||
if(RequestHeaders!=Request->end())
|
||||
Response->set("Access-Control-Allow-Headers", RequestHeaders->second);
|
||||
Response->set("Vary", "Origin, Accept-Encoding");
|
||||
Response->set("Access-Control-Allow-Credentials", "true");
|
||||
Response->set("Access-Control-Max-Age", "86400");
|
||||
Response->set("Connection", "Keep-Alive");
|
||||
Response->set("Keep-Alive", "timeout=30, max=1000");
|
||||
|
||||
Response->setContentLength(0);
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
|
||||
Response->send();
|
||||
}
|
||||
|
||||
inline void PrepareResponse(Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK,
|
||||
bool CloseConnection = false) {
|
||||
Response->setStatus(Status);
|
||||
SetCommonHeaders(CloseConnection);
|
||||
}
|
||||
|
||||
inline void BadRequest(const OpenWifi::RESTAPI::Errors::msg &E, const std::string & Extra="") {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",400);
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
if(Extra.empty())
|
||||
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
|
||||
else
|
||||
ErrorObject.set("ErrorDescription",fmt::format("{}: {} ({})",E.err_num,E.err_txt, Extra)) ;
|
||||
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
|
||||
inline void InternalError(const OpenWifi::RESTAPI::Errors::msg &E) {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",500);
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
|
||||
inline void UnAuthorized(const OpenWifi::RESTAPI::Errors::msg &E) {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",E.err_num);
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
|
||||
inline void NotFound() {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",404);
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
const auto & E = OpenWifi::RESTAPI::Errors::Error404;
|
||||
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
poco_debug(Logger_,fmt::format("RES-NOTFOUND: User='{}@{}' Method='{}' Path='{}",
|
||||
Requester(),
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
|
||||
inline void OK() {
|
||||
PrepareResponse();
|
||||
if( Request->getMethod()==Poco::Net::HTTPRequest::HTTP_DELETE ||
|
||||
Request->getMethod()==Poco::Net::HTTPRequest::HTTP_OPTIONS) {
|
||||
Response->send();
|
||||
} else {
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("Code", 0);
|
||||
ErrorObject.set("Operation", Request->getMethod());
|
||||
ErrorObject.set("Details", "Command completed.");
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
}
|
||||
|
||||
inline void SendCompressedTarFile(const std::string & FileName, const std::string & Content) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
Response->set("Content-Type","application/gzip");
|
||||
Response->set("Content-Disposition", "attachment; filename=" + FileName );
|
||||
Response->set("Content-Transfer-Encoding","binary");
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
Response->set("Cache-Control", "no-store");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
|
||||
Response->setContentLength(Content.size());
|
||||
Response->setChunkedTransferEncoding(true);
|
||||
std::ostream& OutputStream = Response->send();
|
||||
OutputStream << Content;
|
||||
}
|
||||
|
||||
inline void SendFile(Poco::File & File, const std::string & UUID) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
Response->set("Content-Type","application/octet-stream");
|
||||
Response->set("Content-Disposition", "attachment; filename=" + UUID );
|
||||
Response->set("Content-Transfer-Encoding","binary");
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
Response->set("Cache-Control", "no-store");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->setContentLength(File.getSize());
|
||||
Response->sendFile(File.path(),"application/octet-stream");
|
||||
}
|
||||
|
||||
inline void SendFile(Poco::File & File) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
Poco::Path P(File.path());
|
||||
auto MT = Utils::FindMediaType(File);
|
||||
if(MT.Encoding==Utils::BINARY) {
|
||||
Response->set("Content-Transfer-Encoding","binary");
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
}
|
||||
Response->set("Cache-Control", "no-store");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->sendFile(File.path(),MT.ContentType);
|
||||
}
|
||||
|
||||
inline void SendFile(Poco::TemporaryFile &TempAvatar, [[maybe_unused]] const std::string &Type, const std::string & Name) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
auto MT = Utils::FindMediaType(Name);
|
||||
if(MT.Encoding==Utils::BINARY) {
|
||||
Response->set("Content-Transfer-Encoding","binary");
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
}
|
||||
Response->set("Content-Disposition", "attachment; filename=" + Name );
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
Response->set("Cache-Control", "no-store");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->setContentLength(TempAvatar.getSize());
|
||||
Response->sendFile(TempAvatar.path(),MT.ContentType);
|
||||
}
|
||||
|
||||
inline void SendFileContent(const std::string &Content, const std::string &Type, const std::string & Name) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
auto MT = Utils::FindMediaType(Name);
|
||||
if(MT.Encoding==Utils::BINARY) {
|
||||
Response->set("Content-Transfer-Encoding","binary");
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
}
|
||||
Response->set("Content-Disposition", "attachment; filename=" + Name );
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
Response->set("Cache-Control", "no-store");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->setContentLength(Content.size());
|
||||
Response->setContentType(Type );
|
||||
auto & OutputStream = Response->send();
|
||||
OutputStream << Content ;
|
||||
}
|
||||
|
||||
inline void SendHTMLFileBack(Poco::File & File,
|
||||
const Types::StringPairVec & FormVars) {
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
|
||||
SetCommonHeaders();
|
||||
Response->set("Pragma", "private");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
std::string FormContent = Utils::LoadFile(File.path());
|
||||
Utils::ReplaceVariables(FormContent, FormVars);
|
||||
Response->setContentLength(FormContent.size());
|
||||
Response->setChunkedTransferEncoding(true);
|
||||
Response->setContentType("text/html");
|
||||
std::ostream& ostr = Response->send();
|
||||
ostr << FormContent;
|
||||
}
|
||||
|
||||
inline void ReturnStatus(Poco::Net::HTTPResponse::HTTPStatus Status, bool CloseConnection=false) {
|
||||
PrepareResponse(Status, CloseConnection);
|
||||
if(Status == Poco::Net::HTTPResponse::HTTP_NO_CONTENT) {
|
||||
Response->setContentLength(0);
|
||||
Response->erase("Content-Type");
|
||||
Response->setChunkedTransferEncoding(false);
|
||||
}
|
||||
Response->send();
|
||||
}
|
||||
|
||||
inline bool ContinueProcessing() {
|
||||
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
|
||||
ProcessOptions();
|
||||
return false;
|
||||
} else if (std::find(Methods_.begin(), Methods_.end(), Request->getMethod()) == Methods_.end()) {
|
||||
BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsAuthorized(bool & Expired, bool & Contacted, bool SubOnly = false );
|
||||
|
||||
inline void ReturnObject(Poco::JSON::Object &Object) {
|
||||
PrepareResponse();
|
||||
if(Request!= nullptr) {
|
||||
// can we compress ???
|
||||
auto AcceptedEncoding = Request->find("Accept-Encoding");
|
||||
if(AcceptedEncoding!=Request->end()) {
|
||||
if( AcceptedEncoding->second.find("gzip")!=std::string::npos ||
|
||||
AcceptedEncoding->second.find("compress")!=std::string::npos) {
|
||||
Response->set("Content-Encoding", "gzip");
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP);
|
||||
Poco::JSON::Stringifier::stringify(Object, deflater);
|
||||
deflater.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(Object, Answer);
|
||||
}
|
||||
|
||||
inline void ReturnRawJSON(const std::string &json_doc) {
|
||||
PrepareResponse();
|
||||
if(Request!= nullptr) {
|
||||
// can we compress ???
|
||||
auto AcceptedEncoding = Request->find("Accept-Encoding");
|
||||
if(AcceptedEncoding!=Request->end()) {
|
||||
if( AcceptedEncoding->second.find("gzip")!=std::string::npos ||
|
||||
AcceptedEncoding->second.find("compress")!=std::string::npos) {
|
||||
Response->set("Content-Encoding", "gzip");
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP);
|
||||
deflater << json_doc;
|
||||
deflater.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::ostream &Answer = Response->send();
|
||||
Answer << json_doc;
|
||||
}
|
||||
|
||||
inline void ReturnCountOnly(uint64_t Count) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set("count", Count);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
inline bool InitQueryBlock() {
|
||||
if(QueryBlockInitialized_)
|
||||
return true;
|
||||
QueryBlockInitialized_=true;
|
||||
QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0);
|
||||
QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0);
|
||||
QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0);
|
||||
QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100);
|
||||
QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, "");
|
||||
QB_.Lifetime = GetBoolParameter(RESTAPI::Protocol::LIFETIME,false);
|
||||
QB_.LogType = GetParameter(RESTAPI::Protocol::LOGTYPE,0);
|
||||
QB_.LastOnly = GetBoolParameter(RESTAPI::Protocol::LASTONLY,false);
|
||||
QB_.Newest = GetBoolParameter(RESTAPI::Protocol::NEWEST,false);
|
||||
QB_.CountOnly = GetBoolParameter(RESTAPI::Protocol::COUNTONLY,false);
|
||||
QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false);
|
||||
|
||||
auto RawSelect = GetParameter(RESTAPI::Protocol::SELECT, "");
|
||||
|
||||
auto Entries = Poco::StringTokenizer(RawSelect,",");
|
||||
for(const auto &i:Entries) {
|
||||
QB_.Select.emplace_back(i);
|
||||
}
|
||||
if(QB_.Offset<1)
|
||||
QB_.Offset=0;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uint64_t Get(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, uint64_t Default=0){
|
||||
if(Obj->has(Parameter))
|
||||
return Obj->get(Parameter);
|
||||
return Default;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string GetS(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, const std::string & Default=""){
|
||||
if(Obj->has(Parameter))
|
||||
return Obj->get(Parameter).toString();
|
||||
return Default;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool GetB(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, bool Default=false){
|
||||
if(Obj->has(Parameter))
|
||||
return Obj->get(Parameter).toString()=="true";
|
||||
return Default;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uint64_t GetWhen(const Poco::JSON::Object::Ptr &Obj) {
|
||||
return RESTAPIHandler::Get(RESTAPI::Protocol::WHEN, Obj);
|
||||
}
|
||||
|
||||
template<typename T> void ReturnObject(const char *Name, const std::vector<T> & Objects) {
|
||||
Poco::JSON::Object Answer;
|
||||
RESTAPI_utils::field_to_json(Answer,Name,Objects);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
template<typename T> void Object(const char *Name, const std::vector<T> & Objects) {
|
||||
Poco::JSON::Object Answer;
|
||||
RESTAPI_utils::field_to_json(Answer,Name,Objects);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
template <typename T> void Object(const T &O) {
|
||||
Poco::JSON::Object Answer;
|
||||
O.to_json(Answer);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
virtual void DoGet() = 0 ;
|
||||
virtual void DoDelete() = 0 ;
|
||||
virtual void DoPost() = 0 ;
|
||||
virtual void DoPut() = 0 ;
|
||||
|
||||
Poco::Net::HTTPServerRequest *Request= nullptr;
|
||||
Poco::Net::HTTPServerResponse *Response= nullptr;
|
||||
SecurityObjects::UserInfoAndPolicy UserInfo_;
|
||||
QueryBlock QB_;
|
||||
const std::string & Requester() const { return REST_Requester_; }
|
||||
protected:
|
||||
BindingMap Bindings_;
|
||||
Poco::URI::QueryParameters Parameters_;
|
||||
Poco::Logger &Logger_;
|
||||
std::string SessionToken_;
|
||||
std::vector<std::string> Methods_;
|
||||
bool Internal_=false;
|
||||
bool RateLimited_=false;
|
||||
bool QueryBlockInitialized_=false;
|
||||
bool SubOnlyService_=false;
|
||||
bool AlwaysAuthorize_=true;
|
||||
Poco::JSON::Parser IncomingParser_;
|
||||
RESTAPI_GenericServerAccounting & Server_;
|
||||
RateLimit MyRates_;
|
||||
uint64_t TransactionId_;
|
||||
Poco::JSON::Object::Ptr ParsedBody_;
|
||||
std::string REST_Requester_;
|
||||
};
|
||||
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken,
|
||||
SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired , bool Sub );
|
||||
#endif
|
||||
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
|
||||
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
|
||||
auto Allowed = MicroServiceIsValidAPIKEY(*Request);
|
||||
Contacted = true;
|
||||
if(!Allowed) {
|
||||
if(Server_.LogBadTokens(false)) {
|
||||
poco_debug(Logger_,fmt::format("I-REQ-DENIED({}): TID={} Method={} Path={}",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
TransactionId_,
|
||||
Request->getMethod(), Request->getURI()));
|
||||
}
|
||||
} else {
|
||||
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
|
||||
REST_Requester_ = Id;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
poco_debug(Logger_,fmt::format("I-REQ-ALLOWED({}): TID={} User='{}' Method={} Path={}",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
TransactionId_,
|
||||
Id,
|
||||
Request->getMethod(), Request->getURI()));
|
||||
}
|
||||
}
|
||||
return Allowed;
|
||||
} else if(!Internal_ && Request->has("X-API-KEY")) {
|
||||
SessionToken_ = Request->get("X-API-KEY", "");
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
std::uint64_t expiresOn;
|
||||
if (AuthService()->IsValidApiKey(SessionToken_, UserInfo_.webtoken, UserInfo_.userinfo, Expired, expiresOn)) {
|
||||
#else
|
||||
if (AuthClient()->IsValidApiKey( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted)) {
|
||||
#endif
|
||||
REST_Requester_ = UserInfo_.userinfo.email;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): APIKEY-ACCESS TID={} User='{}@{}' Method={} Path={}",
|
||||
UserInfo_.userinfo.email,
|
||||
TransactionId_,
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
Request->clientAddress().toString(),
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if(Server_.LogBadTokens(true)) {
|
||||
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
TransactionId_,
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
if (SessionToken_.empty()) {
|
||||
try {
|
||||
Poco::Net::OAuth20Credentials Auth(*Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
SessionToken_ = Auth.getBearerToken();
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, TransactionId_, Expired, Sub)) {
|
||||
#else
|
||||
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted, Sub)) {
|
||||
#endif
|
||||
REST_Requester_ = UserInfo_.userinfo.email;
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): TID={} User='{}@{}' Method={} Path={}",
|
||||
UserInfo_.userinfo.email,
|
||||
TransactionId_,
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
Request->clientAddress().toString(),
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if(Server_.LogBadTokens(true)) {
|
||||
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
TransactionId_,
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L, std::vector<std::string>{}, Server, TransactionId, Internal) {}
|
||||
inline void DoGet() override {};
|
||||
inline void DoPost() override {};
|
||||
inline void DoPut() override {};
|
||||
inline void DoDelete() override {};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
constexpr auto test_has_PathName_method(T*)
|
||||
-> decltype( T::PathName() , std::true_type{} )
|
||||
{
|
||||
return std::true_type{};
|
||||
}
|
||||
constexpr auto test_has_PathName_method(...) -> std::false_type
|
||||
{
|
||||
return std::false_type{};
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & Logger, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId) {
|
||||
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
|
||||
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
|
||||
return new T(Bindings, Logger, Server, TransactionId, false);
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, false);
|
||||
} else {
|
||||
return RESTAPI_Router<Args...>(RequestedPath, Bindings, Logger, Server, TransactionId);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & Logger, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId) {
|
||||
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
|
||||
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
|
||||
return new T(Bindings, Logger, Server, TransactionId, true );
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, true);
|
||||
} else {
|
||||
return RESTAPI_Router_I<Args...>(RequestedPath, Bindings, Logger, Server, TransactionId);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
17
src/framework/RESTAPI_IntServer.cpp
Normal file
17
src/framework/RESTAPI_IntServer.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#include "RESTAPI_IntServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler *
|
||||
IntRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &Request) {
|
||||
auto TID = NextTransactionId_++;
|
||||
Utils::SetThreadName(fmt::format("i-rest:{}", TID).c_str());
|
||||
Poco::URI uri(Request.getURI());
|
||||
return RESTAPI_IntServer()->CallServer(uri.getPath(), TID);
|
||||
}
|
||||
|
||||
} // namespace OpenWifi
|
||||
104
src/framework/RESTAPI_IntServer.h
Normal file
104
src/framework/RESTAPI_IntServer.h
Normal file
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-10-25.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
|
||||
#include "framework/SubSystemServer.h"
|
||||
#include "framework/RESTAPI_Handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t Id);
|
||||
|
||||
class IntRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
inline IntRequestHandlerFactory() = default;
|
||||
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override;
|
||||
private:
|
||||
static inline std::atomic_uint64_t NextTransactionId_ = 1;
|
||||
};
|
||||
|
||||
class RESTAPI_IntServer : public SubSystemServer {
|
||||
public:
|
||||
static auto instance() {
|
||||
static auto instance_ = new RESTAPI_IntServer;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
inline int Start() override {
|
||||
poco_information(Logger(),"Starting.");
|
||||
Server_.InitLogging();
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
|
||||
if(MicroServiceNoAPISecurity()) {
|
||||
poco_information(Logger(),fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port()));
|
||||
} else {
|
||||
poco_information(Logger(),fmt::format("Starting: {}:{}. Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(),
|
||||
Svr.KeyFile(),Svr.CertFile()));
|
||||
Svr.LogCert(Logger());
|
||||
if (!Svr.RootCA().empty())
|
||||
Svr.LogCas(Logger());
|
||||
}
|
||||
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
Params->setKeepAlive(true);
|
||||
Params->setName("ws:irest");
|
||||
|
||||
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
|
||||
if(MicroServiceNoAPISecurity()) {
|
||||
auto Sock{Svr.CreateSocket(Logger())};
|
||||
NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory, Pool_, Sock, Params);
|
||||
} else {
|
||||
auto Sock{Svr.CreateSecureSocket(Logger())};
|
||||
NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory, Pool_, Sock, Params);
|
||||
};
|
||||
NewServer->start();
|
||||
RESTServers_.push_back(std::move(NewServer));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void Stop() override {
|
||||
poco_information(Logger(),"Stopping...");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stopAll(true);
|
||||
Pool_.stopAll();
|
||||
Pool_.joinAll();
|
||||
poco_information(Logger(),"Stopped...");
|
||||
}
|
||||
|
||||
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
|
||||
MicroServiceLoadConfigurationFile();
|
||||
poco_information(Logger(),"Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
|
||||
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
|
||||
}
|
||||
const Poco::ThreadPool & Pool() { return Pool_; }
|
||||
private:
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_{"i-rest",4,64};
|
||||
RESTAPI_GenericServerAccounting Server_;
|
||||
|
||||
RESTAPI_IntServer() noexcept:
|
||||
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline auto RESTAPI_IntServer() { return RESTAPI_IntServer::instance(); };
|
||||
|
||||
|
||||
} // namespace OpenWifi
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user