mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralfms.git
synced 2025-10-30 02:12:22 +00:00
Compare commits
79 Commits
v2.7.0-RC5
...
v2.8.0-RC2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
DOCKER_REGISTRY_USERNAME: ucentral
|
DOCKER_REGISTRY_USERNAME: ucentral
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: github
|
path: github
|
||||||
@@ -58,11 +58,11 @@ jobs:
|
|||||||
- name: Get base branch name and set as output
|
- name: Get base branch name and set as output
|
||||||
id: get_base_branch
|
id: get_base_branch
|
||||||
run: |
|
run: |
|
||||||
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
|
echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
|
||||||
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
|
echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: github
|
path: github
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
- docker
|
- docker
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout actions repo
|
- name: Checkout actions repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
repository: Telecominfraproject/.github
|
repository: Telecominfraproject/.github
|
||||||
path: 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)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(owfms VERSION 2.7.0)
|
project(owfms VERSION 2.8.0)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
@@ -27,12 +27,12 @@ endif()
|
|||||||
|
|
||||||
find_package(Git QUIET)
|
find_package(Git QUIET)
|
||||||
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
|
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}
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
RESULT_VARIABLE GIT_RESULT
|
RESULT_VARIABLE GIT_RESULT
|
||||||
OUTPUT_VARIABLE GIT_HASH)
|
OUTPUT_VARIABLE GIT_HASH)
|
||||||
if(NOT GIT_RESULT EQUAL "0")
|
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()
|
endif()
|
||||||
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
|
||||||
endif()
|
endif()
|
||||||
@@ -42,8 +42,10 @@ endif()
|
|||||||
|
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
find_package(fmt REQUIRED)
|
find_package(fmt REQUIRED)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||||
find_package(AWSSDK REQUIRED COMPONENTS s3)
|
find_package(AWSSDK REQUIRED COMPONENTS s3)
|
||||||
|
find_package(ZLIB REQUIRED)
|
||||||
|
|
||||||
if(SMALL_BUILD)
|
if(SMALL_BUILD)
|
||||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||||
@@ -75,14 +77,54 @@ add_executable( owfms
|
|||||||
src/framework/OpenWifiTypes.h
|
src/framework/OpenWifiTypes.h
|
||||||
src/framework/orm.h
|
src/framework/orm.h
|
||||||
src/framework/StorageClass.h
|
src/framework/StorageClass.h
|
||||||
src/framework/ow_constants.h
|
|
||||||
src/framework/MicroServiceErrorHandler.h
|
|
||||||
src/framework/WebSocketClientNotifications.h
|
|
||||||
src/framework/MicroServiceErrorHandler.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_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_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
|
||||||
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.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_firmwaresHandler.cpp src/RESTAPI/RESTAPI_firmwaresHandler.h
|
||||||
src/RESTAPI/RESTAPI_firmwareHandler.cpp src/RESTAPI/RESTAPI_firmwareHandler.h
|
src/RESTAPI/RESTAPI_firmwareHandler.cpp src/RESTAPI/RESTAPI_firmwareHandler.h
|
||||||
src/RESTAPI/RESTAPI_historyHandler.cpp src/RESTAPI/RESTAPI_historyHandler.h
|
src/RESTAPI/RESTAPI_historyHandler.cpp src/RESTAPI/RESTAPI_historyHandler.h
|
||||||
@@ -95,7 +137,6 @@ add_executable( owfms
|
|||||||
src/Daemon.cpp src/Daemon.h
|
src/Daemon.cpp src/Daemon.h
|
||||||
src/StorageService.cpp src/StorageService.h
|
src/StorageService.cpp src/StorageService.h
|
||||||
src/ManifestCreator.cpp src/ManifestCreator.h
|
src/ManifestCreator.cpp src/ManifestCreator.h
|
||||||
src/framework/MicroService.h
|
|
||||||
src/NewConnectionHandler.cpp src/NewConnectionHandler.h
|
src/NewConnectionHandler.cpp src/NewConnectionHandler.h
|
||||||
src/LatestFirmwareCache.cpp src/LatestFirmwareCache.h
|
src/LatestFirmwareCache.cpp src/LatestFirmwareCache.h
|
||||||
src/DeviceCache.cpp src/DeviceCache.h
|
src/DeviceCache.cpp src/DeviceCache.h
|
||||||
@@ -105,7 +146,9 @@ add_executable( owfms
|
|||||||
src/NewCommandHandler.cpp src/NewCommandHandler.h
|
src/NewCommandHandler.cpp src/NewCommandHandler.h
|
||||||
src/storage/orm_history.cpp src/storage/orm_history.h
|
src/storage/orm_history.cpp src/storage/orm_history.h
|
||||||
src/storage/orm_firmwares.cpp src/storage/orm_firmwares.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
|
target_link_libraries( owfms PUBLIC
|
||||||
${Poco_LIBRARIES}
|
${Poco_LIBRARIES}
|
||||||
|
|||||||
85
Dockerfile
85
Dockerfile
@@ -1,17 +1,14 @@
|
|||||||
ARG DEBIAN_VERSION=11.4-slim
|
ARG DEBIAN_VERSION=11.5-slim
|
||||||
ARG POCO_VERSION=poco-tip-v1
|
ARG POCO_VERSION=poco-tip-v2
|
||||||
ARG FMTLIB_VERSION=9.0.0
|
|
||||||
ARG CPPKAFKA_VERSION=tip-v1
|
ARG CPPKAFKA_VERSION=tip-v1
|
||||||
ARG JSON_VALIDATOR_VERSION=2.1.0
|
|
||||||
ARG AWS_SDK_VERSION=1.9.315
|
|
||||||
|
|
||||||
FROM debian:$DEBIAN_VERSION AS build-base
|
FROM debian:$DEBIAN_VERSION AS build-base
|
||||||
|
|
||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
make cmake g++ git \
|
make cmake g++ git curl zip unzip pkg-config \
|
||||||
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
|
||||||
librdkafka-dev libboost-all-dev libssl-dev \
|
librdkafka-dev libboost-all-dev libssl-dev \
|
||||||
zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev
|
zlib1g-dev ca-certificates libcurl4-openssl-dev libfmt-dev
|
||||||
|
|
||||||
FROM build-base AS poco-build
|
FROM build-base AS poco-build
|
||||||
|
|
||||||
@@ -27,20 +24,6 @@ RUN cmake ..
|
|||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
RUN cmake --build . --target install
|
RUN cmake --build . --target install
|
||||||
|
|
||||||
FROM build-base AS fmtlib-build
|
|
||||||
|
|
||||||
ARG FMTLIB_VERSION
|
|
||||||
|
|
||||||
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/tags/${FMTLIB_VERSION} version.json
|
|
||||||
RUN git clone https://github.com/fmtlib/fmt --branch ${FMTLIB_VERSION} /fmtlib
|
|
||||||
|
|
||||||
WORKDIR /fmtlib
|
|
||||||
RUN mkdir cmake-build
|
|
||||||
WORKDIR cmake-build
|
|
||||||
RUN cmake ..
|
|
||||||
RUN make
|
|
||||||
RUN make install
|
|
||||||
|
|
||||||
FROM build-base AS cppkafka-build
|
FROM build-base AS cppkafka-build
|
||||||
|
|
||||||
ARG CPPKAFKA_VERSION
|
ARG CPPKAFKA_VERSION
|
||||||
@@ -55,62 +38,30 @@ RUN cmake ..
|
|||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
RUN cmake --build . --target install
|
RUN cmake --build . --target install
|
||||||
|
|
||||||
FROM build-base AS json-schema-validator-build
|
|
||||||
|
|
||||||
ARG JSON_VALIDATOR_VERSION
|
|
||||||
|
|
||||||
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
|
|
||||||
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
ARG AWS_SDK_VERSION
|
|
||||||
|
|
||||||
ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/tags/${AWS_SDK_VERSION} version.json
|
|
||||||
RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp --branch ${AWS_SDK_VERSION} /aws-sdk-cpp
|
|
||||||
|
|
||||||
WORKDIR /aws-sdk-cpp
|
|
||||||
RUN mkdir cmake-build
|
|
||||||
WORKDIR cmake-build
|
|
||||||
RUN cmake .. -DBUILD_ONLY="sns;s3" \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DUSE_OPENSSL=ON \
|
|
||||||
-DCPP_STANDARD=17 \
|
|
||||||
-DBUILD_SHARED_LIBS=ON \
|
|
||||||
-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
|
FROM build-base AS owfms-build
|
||||||
|
|
||||||
ADD CMakeLists.txt build /owfms/
|
ADD CMakeLists.txt build /owfms/
|
||||||
|
ADD overlays /owfms/overlays
|
||||||
ADD cmake /owfms/cmake
|
ADD cmake /owfms/cmake
|
||||||
ADD src /owfms/src
|
ADD src /owfms/src
|
||||||
ADD .git /owfms/.git
|
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/include /usr/local/include
|
||||||
COPY --from=poco-build /usr/local/lib /usr/local/lib
|
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/include /usr/local/include
|
||||||
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
|
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
|
WORKDIR /owfms
|
||||||
RUN mkdir cmake-build
|
RUN mkdir cmake-build
|
||||||
WORKDIR /owfms/cmake-build
|
WORKDIR /owfms/cmake-build
|
||||||
RUN cmake ..
|
RUN cmake -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake ..
|
||||||
RUN cmake --build . --config Release -j8
|
RUN cmake --build . --config Release -j8
|
||||||
|
|
||||||
FROM debian:$DEBIAN_VERSION
|
FROM debian:$DEBIAN_VERSION
|
||||||
@@ -127,7 +78,7 @@ RUN mkdir -p "$OWFMS_ROOT" "$OWFMS_CONFIG" && \
|
|||||||
|
|
||||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||||
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
|
||||||
libmariadb-dev-compat libpq5 unixodbc postgresql-client
|
libmariadb-dev-compat libpq5 postgresql-client libfmt7 sqlite3
|
||||||
|
|
||||||
COPY readiness_check /readiness_check
|
COPY readiness_check /readiness_check
|
||||||
COPY test_scripts/curl/cli /cli
|
COPY test_scripts/curl/cli /cli
|
||||||
@@ -139,11 +90,9 @@ RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentr
|
|||||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
|
||||||
|
|
||||||
COPY --from=owfms-build /owfms/cmake-build/owfms /openwifi/owfms
|
COPY --from=owfms-build /owfms/cmake-build/owfms /openwifi/owfms
|
||||||
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
|
COPY --from=owfms-build /vcpkg/installed/x64-linux/lib/ /usr/local/lib/
|
||||||
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib
|
COPY --from=cppkafka-build /cppkafka/cmake-build/src/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=poco-build /poco/cmake-build/lib/ /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
|
|
||||||
|
|
||||||
RUN ldconfig
|
RUN ldconfig
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
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).
|
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
|
## Building
|
||||||
In order to build the uCentralFMS, you will need to install its dependencies, which includes the following:
|
In order to build the uCentralFMS, you will need to install its dependencies, which includes the following:
|
||||||
- cmake
|
- cmake
|
||||||
@@ -216,4 +221,4 @@ s3.key = *******************************************
|
|||||||
s3.retry = 60
|
s3.retry = 60
|
||||||
s3.bucket.uri = ucentral-ap-firmware.s3.amazonaws.com
|
s3.bucket.uri = ucentral-ap-firmware.s3.amazonaws.com
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
|
|||||||
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16004"} \
|
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16004"} \
|
||||||
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
||||||
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
|
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_BUCKETNAME=${S3_BUCKETNAME:-"ucentral-ap-firmware"} \
|
||||||
S3_REGION=${S3_REGION:-"us-east-1"} \
|
S3_REGION=${S3_REGION:-"us-east-1"} \
|
||||||
S3_SECRET=${S3_SECRET:-"*******************************************"} \
|
S3_SECRET=${S3_SECRET:-"*******************************************"} \
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ fullnameOverride: ""
|
|||||||
images:
|
images:
|
||||||
owfms:
|
owfms:
|
||||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owfms
|
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owfms
|
||||||
tag: main
|
tag: v2.8.0-RC2
|
||||||
pullPolicy: Always
|
pullPolicy: Always
|
||||||
# regcred:
|
# regcred:
|
||||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||||
@@ -147,7 +147,7 @@ configProperties:
|
|||||||
s3.region: us-east-1
|
s3.region: us-east-1
|
||||||
s3.retry: 60
|
s3.retry: 60
|
||||||
s3.bucket.uri: ucentral-ap-firmware.s3.amazonaws.com
|
s3.bucket.uri: ucentral-ap-firmware.s3.amazonaws.com
|
||||||
firmwaredb.refresh: 1800
|
firmwaredb.refresh: 86400
|
||||||
# ALB
|
# ALB
|
||||||
alb.enable: "true"
|
alb.enable: "true"
|
||||||
alb.port: 16104
|
alb.port: 16104
|
||||||
|
|||||||
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"
|
||||||
|
}
|
||||||
@@ -38,8 +38,8 @@ openwifi.system.commandchannel = /tmp/app.ucentralfms
|
|||||||
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
||||||
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
|
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
|
||||||
|
|
||||||
firmwaredb.refresh = 1800
|
firmwaredb.refresh = ${FIRMWAREDB_REFRESH}
|
||||||
firmwaredb.maxage = 90
|
firmwaredb.maxage = ${FIRMWAREDB_MAXAGE}
|
||||||
|
|
||||||
#
|
#
|
||||||
# Firmware Microservice Specific Section
|
# Firmware Microservice Specific Section
|
||||||
|
|||||||
@@ -8,14 +8,19 @@
|
|||||||
#include "LatestFirmwareCache.h"
|
#include "LatestFirmwareCache.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
|
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
int AutoUpdater::Start() {
|
int AutoUpdater::Start() {
|
||||||
poco_information(Logger(),"Starting...");
|
poco_information(Logger(),"Starting...");
|
||||||
AutoUpdaterEnabled_ = MicroService::instance().ConfigGetBool("autoupdater.enabled", false);
|
AutoUpdaterEnabled_ = MicroServiceConfigGetBool("autoupdater.enabled", false);
|
||||||
if(AutoUpdaterEnabled_) {
|
if(AutoUpdaterEnabled_) {
|
||||||
Running_ = false;
|
Running_ = false;
|
||||||
AutoUpdaterFrequency_ = MicroService::instance().ConfigGetInt("autoupdater.frequency",600);
|
AutoUpdaterFrequency_ = MicroServiceConfigGetInt("autoupdater.frequency",600);
|
||||||
AutoUpdaterCallBack_ = std::make_unique<Poco::TimerCallback<AutoUpdater>>(*this, &AutoUpdater::onTimer);
|
AutoUpdaterCallBack_ = std::make_unique<Poco::TimerCallback<AutoUpdater>>(*this, &AutoUpdater::onTimer);
|
||||||
Timer_.setStartInterval(5 * 60 * 1000); // first run in 5 minutes
|
Timer_.setStartInterval(5 * 60 * 1000); // first run in 5 minutes
|
||||||
Timer_.setPeriodicInterval(AutoUpdaterFrequency_ * 1000);
|
Timer_.setPeriodicInterval(AutoUpdaterFrequency_ * 1000);
|
||||||
@@ -50,7 +55,7 @@ namespace OpenWifi {
|
|||||||
try {
|
try {
|
||||||
poco_debug(Logger(),fmt::format("Preparing to upgrade {}",Entry.first));
|
poco_debug(Logger(),fmt::format("Preparing to upgrade {}",Entry.first));
|
||||||
auto CacheEntry = Cache_.find(Entry.first);
|
auto CacheEntry = Cache_.find(Entry.first);
|
||||||
uint64_t now = OpenWifi::Now();
|
uint64_t now = Utils::Now();
|
||||||
std::string firmwareUpgrade;
|
std::string firmwareUpgrade;
|
||||||
if(CacheEntry == Cache_.end() || (CacheEntry->second.LastCheck-now)>300) {
|
if(CacheEntry == Cache_.end() || (CacheEntry->second.LastCheck-now)>300) {
|
||||||
// get the firmware settings for that device.
|
// get the firmware settings for that device.
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
// Created by stephane bourque on 2021-10-04.
|
// Created by stephane bourque on 2021-10-04.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef OWFMS_AUTOUPDATER_H
|
#pragma once
|
||||||
#define OWFMS_AUTOUPDATER_H
|
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
|
#include "framework/SubSystemServer.h"
|
||||||
#include "Poco/Util/Application.h"
|
#include "Poco/Util/Application.h"
|
||||||
#include "Poco/Timer.h"
|
#include "Poco/Timer.h"
|
||||||
|
|
||||||
@@ -55,4 +55,3 @@ namespace OpenWifi {
|
|||||||
inline auto AutoUpdater() { return AutoUpdater::instance(); }
|
inline auto AutoUpdater() { return AutoUpdater::instance(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //OWFMS_AUTOUPDATER_H
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
#include "AutoUpdater.h"
|
#include "AutoUpdater.h"
|
||||||
#include "NewCommandHandler.h"
|
#include "NewCommandHandler.h"
|
||||||
|
|
||||||
|
#include "framework/UI_WebSocketClientServer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class Daemon *Daemon::instance_ = nullptr;
|
class Daemon *Daemon::instance_ = nullptr;
|
||||||
|
|
||||||
@@ -37,7 +39,8 @@ namespace OpenWifi {
|
|||||||
NewConnectionHandler(),
|
NewConnectionHandler(),
|
||||||
ManifestCreator(),
|
ManifestCreator(),
|
||||||
AutoUpdater(),
|
AutoUpdater(),
|
||||||
NewCommandHandler()
|
NewCommandHandler(),
|
||||||
|
UI_WebSocketClientServer()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return instance_;
|
return instance_;
|
||||||
@@ -45,6 +48,11 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DaemonPostInitialization(Poco::Util::Application &self) {
|
||||||
|
Daemon()->PostInitialization(self);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/MicroService.h"
|
||||||
#include "framework/OpenWifiTypes.h"
|
#include "framework/OpenWifiTypes.h"
|
||||||
|
#include "framework/MicroServiceNames.h"
|
||||||
|
|
||||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||||
#include "Dashboard.h"
|
#include "Dashboard.h"
|
||||||
|
|
||||||
@@ -30,9 +32,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
void PostInitialization(Poco::Util::Application &self);
|
void PostInitialization(Poco::Util::Application &self);
|
||||||
static Daemon *instance();
|
static Daemon *instance();
|
||||||
inline void ResetDashboard() { DB_.Reset(); }
|
inline DeviceDashboard & GetDashboard() { return DB_; }
|
||||||
inline void CreateDashboard() { DB_.Create(); }
|
|
||||||
inline const FMSObjects::DeviceReport & GetDashboard() { return DB_.Report(); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Daemon *instance_;
|
static Daemon *instance_;
|
||||||
@@ -40,9 +40,6 @@ namespace OpenWifi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
inline Daemon * Daemon() { return Daemon::instance(); }
|
inline Daemon * Daemon() { return Daemon::instance(); }
|
||||||
inline void DaemonPostInitialization(Poco::Util::Application &self) {
|
|
||||||
Daemon()->PostInitialization(self);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //UCENTRALFWS_DAEMON_H
|
#endif //UCENTRALFWS_DAEMON_H
|
||||||
|
|||||||
@@ -4,15 +4,48 @@
|
|||||||
|
|
||||||
#include "Dashboard.h"
|
#include "Dashboard.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
void DeviceDashboard::Create() {
|
|
||||||
uint64_t Now = OpenWifi::Now();
|
|
||||||
|
|
||||||
if(LastRun_==0 || (Now-LastRun_)>120) {
|
bool DeviceDashboard::Get(FMSObjects::DeviceReport &D, Poco::Logger & Logger) {
|
||||||
DB_.reset();
|
uint64_t Now = Utils::Now();
|
||||||
StorageService()->DevicesDB().GenerateDeviceReport(DB_);
|
if(!ValidDashboard_ || LastRun_==0 || (Now-LastRun_)>120) {
|
||||||
LastRun_ = Now;
|
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.
|
// Created by stephane bourque on 2021-07-21.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALGW_DASHBOARD_H
|
#pragma once
|
||||||
#define UCENTRALGW_DASHBOARD_H
|
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "framework/OpenWifiTypes.h"
|
#include "framework/OpenWifiTypes.h"
|
||||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||||
|
#include "Poco/Logger.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class DeviceDashboard {
|
class DeviceDashboard {
|
||||||
public:
|
public:
|
||||||
void Create();
|
bool Get(FMSObjects::DeviceReport &D, Poco::Logger &Logger);
|
||||||
const FMSObjects::DeviceReport & Report() const { return DB_;}
|
|
||||||
inline void Reset() { LastRun_=0; DB_.reset(); }
|
|
||||||
private:
|
|
||||||
FMSObjects::DeviceReport DB_;
|
|
||||||
uint64_t LastRun_=0;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#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);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,10 @@
|
|||||||
// Created by stephane bourque on 2021-07-13.
|
// Created by stephane bourque on 2021-07-13.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALFMS_DEVICECACHE_H
|
#pragma once
|
||||||
#define UCENTRALFMS_DEVICECACHE_H
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
@@ -43,6 +42,3 @@ namespace OpenWifi {
|
|||||||
inline auto DeviceCache() { return DeviceCache::instance(); }
|
inline auto DeviceCache() { return DeviceCache::instance(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif //UCENTRALFMS_DEVICECACHE_H
|
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
// Created by stephane bourque on 2021-07-26.
|
// Created by stephane bourque on 2021-07-26.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALFMS_FIRMWARECACHE_H
|
#pragma once
|
||||||
#define UCENTRALFMS_FIRMWARECACHE_H
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
@@ -40,6 +39,3 @@ namespace OpenWifi {
|
|||||||
inline auto FirmwareCache() { return FirmwareCache::instance(); }
|
inline auto FirmwareCache() { return FirmwareCache::instance(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //UCENTRALFMS_FIRMWARECACHE_H
|
|
||||||
|
|||||||
@@ -2,16 +2,17 @@
|
|||||||
// Created by stephane bourque on 2021-07-13.
|
// Created by stephane bourque on 2021-07-13.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALFMS_LATESTFIRMWARECACHE_H
|
#pragma once
|
||||||
#define UCENTRALFMS_LATESTFIRMWARECACHE_H
|
|
||||||
|
|
||||||
#include "Poco/JSON/Object.h"
|
#include "Poco/JSON/Object.h"
|
||||||
#include "Poco/Net/HTTPServerRequest.h"
|
#include "Poco/Net/HTTPServerRequest.h"
|
||||||
#include "Poco/Net/HTTPServerResponse.h"
|
#include "Poco/Net/HTTPServerResponse.h"
|
||||||
#include "Poco/JWT/Signer.h"
|
#include "Poco/JWT/Signer.h"
|
||||||
#include "Poco/SHA2Engine.h"
|
#include "Poco/SHA2Engine.h"
|
||||||
|
#include "Poco/StringTokenizer.h"
|
||||||
|
|
||||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ namespace OpenWifi {
|
|||||||
auto Tokens = Poco::StringTokenizer(Revision,"/", Poco::StringTokenizer::TOK_TRIM);
|
auto Tokens = Poco::StringTokenizer(Revision,"/", Poco::StringTokenizer::TOK_TRIM);
|
||||||
if(Tokens.count()!=2)
|
if(Tokens.count()!=2)
|
||||||
return false;
|
return false;
|
||||||
return (Tokens[1].substr(0,5) == "IP-v");
|
return (Tokens[1].substr(0,5) == "TIP-v");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DumpCache();
|
void DumpCache();
|
||||||
@@ -64,6 +65,3 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
inline auto LatestFirmwareCache() { return LatestFirmwareCache::instance(); }
|
inline auto LatestFirmwareCache() { return LatestFirmwareCache::instance(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif //UCENTRALFMS_LATESTFIRMWARECACHE_H
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@
|
|||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
#include "LatestFirmwareCache.h"
|
#include "LatestFirmwareCache.h"
|
||||||
|
|
||||||
|
#include "framework/utils.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void ManifestCreator::onTimer([[maybe_unused]] Poco::Timer &timer) {
|
void ManifestCreator::onTimer([[maybe_unused]] Poco::Timer &timer) {
|
||||||
@@ -29,7 +32,7 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
bool ManifestCreator::ComputeManifest(S3BucketContent &BucketContent) {
|
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) {
|
for(auto &[Name,Entry]:BucketContent) {
|
||||||
std::string C = Entry.S3ContentManifest;
|
std::string C = Entry.S3ContentManifest;
|
||||||
|
|
||||||
@@ -89,10 +92,10 @@ namespace OpenWifi {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(BucketEntry.Valid && !StorageService()->FirmwaresDB().GetFirmwareByName(R,BucketEntry.Compatible,F)) {
|
if(BucketEntry.Valid && !StorageService()->FirmwaresDB().GetFirmwareByName(R,BucketEntry.Compatible,F)) {
|
||||||
F.id = MicroService::instance().CreateUUID();
|
F.id = MicroServiceCreateUUID();
|
||||||
F.release = Release;
|
F.release = Release;
|
||||||
F.size = BucketEntry.S3Size;
|
F.size = BucketEntry.S3Size;
|
||||||
F.created = OpenWifi::Now();
|
F.created = Utils::Now();
|
||||||
F.imageDate = BucketEntry.S3TimeStamp;
|
F.imageDate = BucketEntry.S3TimeStamp;
|
||||||
F.image = BucketEntry.Image;
|
F.image = BucketEntry.Image;
|
||||||
F.uri = BucketEntry.URI;
|
F.uri = BucketEntry.URI;
|
||||||
@@ -109,14 +112,14 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
int ManifestCreator::Start() {
|
int ManifestCreator::Start() {
|
||||||
Running_ = true;
|
Running_ = true;
|
||||||
S3BucketName_ = MicroService::instance().ConfigGetString("s3.bucketname");
|
S3BucketName_ = MicroServiceConfigGetString("s3.bucketname","");
|
||||||
S3Region_ = MicroService::instance().ConfigGetString("s3.region");
|
S3Region_ = MicroServiceConfigGetString("s3.region","");
|
||||||
S3Secret_ = MicroService::instance().ConfigGetString("s3.secret");
|
S3Secret_ = MicroServiceConfigGetString("s3.secret","");
|
||||||
S3Key_ = MicroService::instance().ConfigGetString("s3.key");
|
S3Key_ = MicroServiceConfigGetString("s3.key","");
|
||||||
S3Retry_ = MicroService::instance().ConfigGetInt("s3.retry",60);
|
S3Retry_ = MicroServiceConfigGetInt("s3.retry",60);
|
||||||
|
|
||||||
DBRefresh_ = MicroService::instance().ConfigGetInt("firmwaredb.refresh",30*60);
|
DBRefresh_ = MicroServiceConfigGetInt("firmwaredb.refresh",30*60);
|
||||||
MaxAge_ = MicroService::instance().ConfigGetInt("firmwaredb.maxage",90) * 24 * 60 * 60;
|
MaxAge_ = MicroServiceConfigGetInt("firmwaredb.maxage",90) * 24 * 60 * 60;
|
||||||
|
|
||||||
AwsConfig_.enableTcpKeepAlive = true;
|
AwsConfig_.enableTcpKeepAlive = true;
|
||||||
AwsConfig_.enableEndpointDiscovery = true;
|
AwsConfig_.enableEndpointDiscovery = true;
|
||||||
@@ -169,7 +172,7 @@ namespace OpenWifi {
|
|||||||
static const std::string UPGRADE("-upgrade.bin");
|
static const std::string UPGRADE("-upgrade.bin");
|
||||||
|
|
||||||
std::string URIBase = "https://";
|
std::string URIBase = "https://";
|
||||||
URIBase += MicroService::instance().ConfigGetString("s3.bucket.uri");
|
URIBase += MicroServiceConfigGetString("s3.bucket.uri","");
|
||||||
|
|
||||||
Bucket.clear();
|
Bucket.clear();
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,13 @@
|
|||||||
// Created by stephane bourque on 2021-06-02.
|
// Created by stephane bourque on 2021-06-02.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALFWS_MANIFESTCREATOR_H
|
#pragma once
|
||||||
#define UCENTRALFWS_MANIFESTCREATOR_H
|
|
||||||
|
|
||||||
#include <aws/core/Aws.h>
|
#include <aws/core/Aws.h>
|
||||||
#include <aws/s3/S3Client.h>
|
#include <aws/s3/S3Client.h>
|
||||||
#include <aws/core/auth/AWSCredentials.h>
|
#include <aws/core/auth/AWSCredentials.h>
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
#include "Poco/Timer.h"
|
#include "Poco/Timer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
@@ -71,5 +70,3 @@ namespace OpenWifi {
|
|||||||
inline auto ManifestCreator() { return ManifestCreator::instance(); };
|
inline auto ManifestCreator() { return ManifestCreator::instance(); };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //UCENTRALFWS_MANIFESTCREATOR_H
|
|
||||||
|
|||||||
@@ -5,6 +5,10 @@
|
|||||||
#include "NewCommandHandler.h"
|
#include "NewCommandHandler.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
|
|
||||||
|
#include "framework/KafkaManager.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
void NewCommandHandler::run() {
|
void NewCommandHandler::run() {
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
// Created by stephane bourque on 2021-11-21.
|
// Created by stephane bourque on 2021-11-21.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef OWFMS_NEWCOMMANDHANDLER_H
|
#pragma once
|
||||||
#define OWFMS_NEWCOMMANDHANDLER_H
|
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
#include "framework/OpenWifiTypes.h"
|
#include "framework/OpenWifiTypes.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
@@ -37,5 +36,3 @@ namespace OpenWifi {
|
|||||||
inline auto NewCommandHandler() { return NewCommandHandler::instance(); };
|
inline auto NewCommandHandler() { return NewCommandHandler::instance(); };
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //OWFMS_NEWCOMMANDHANDLER_H
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#include "DeviceCache.h"
|
#include "DeviceCache.h"
|
||||||
#include "AutoUpdater.h"
|
#include "AutoUpdater.h"
|
||||||
|
|
||||||
|
#include "framework/KafkaManager.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{ "system" : { "id" : 6715803232063 , "host" : "https://localhost:17002" } ,
|
{ "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}}
|
"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}}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
// Created by stephane bourque on 2021-07-13.
|
// Created by stephane bourque on 2021-07-13.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRALFMS_NEWCONNECTIONHANDLER_H
|
#pragma once
|
||||||
#define UCENTRALFMS_NEWCONNECTIONHANDLER_H
|
|
||||||
|
|
||||||
|
#include "framework/SubSystemServer.h"
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include "framework/OpenWifiTypes.h"
|
#include "framework/OpenWifiTypes.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
@@ -40,4 +38,3 @@ namespace OpenWifi {
|
|||||||
inline auto NewConnectionHandler() { return NewConnectionHandler::instance(); };
|
inline auto NewConnectionHandler() { return NewConnectionHandler::instance(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //UCENTRALFMS_NEWCONNECTIONHANDLER_H
|
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
// Created by stephane bourque on 2021-10-23.
|
// 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_firmwareHandler.h"
|
||||||
#include "RESTAPI/RESTAPI_firmwaresHandler.h"
|
#include "RESTAPI/RESTAPI_firmwaresHandler.h"
|
||||||
#include "RESTAPI/RESTAPI_firmwareAgeHandler.h"
|
#include "RESTAPI/RESTAPI_firmwareAgeHandler.h"
|
||||||
@@ -12,11 +11,13 @@
|
|||||||
#include "RESTAPI/RESTAPI_historyHandler.h"
|
#include "RESTAPI/RESTAPI_historyHandler.h"
|
||||||
#include "RESTAPI/RESTAPI_deviceReportHandler.h"
|
#include "RESTAPI/RESTAPI_deviceReportHandler.h"
|
||||||
#include "RESTAPI/RESTAPI_deviceInformation_handler.h"
|
#include "RESTAPI/RESTAPI_deviceInformation_handler.h"
|
||||||
|
#include "framework/RESTAPI_SystemCommand.h"
|
||||||
|
#include "framework/RESTAPI_WebSocketServer.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
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<
|
return RESTAPI_Router<
|
||||||
RESTAPI_firmwaresHandler,
|
RESTAPI_firmwaresHandler,
|
||||||
RESTAPI_firmwareHandler,
|
RESTAPI_firmwareHandler,
|
||||||
@@ -26,12 +27,13 @@ namespace OpenWifi {
|
|||||||
RESTAPI_connectedDeviceHandler,
|
RESTAPI_connectedDeviceHandler,
|
||||||
RESTAPI_historyHandler,
|
RESTAPI_historyHandler,
|
||||||
RESTAPI_deviceReportHandler,
|
RESTAPI_deviceReportHandler,
|
||||||
RESTAPI_deviceInformation_handler
|
RESTAPI_deviceInformation_handler,
|
||||||
|
RESTAPI_webSocketServer
|
||||||
>(Path,Bindings,L, S, TransactionId);
|
>(Path,Bindings,L, S, TransactionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
|
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<
|
return RESTAPI_Router_I<
|
||||||
RESTAPI_firmwaresHandler,
|
RESTAPI_firmwaresHandler,
|
||||||
RESTAPI_firmwareHandler,
|
RESTAPI_firmwareHandler,
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
#ifndef UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
|
#ifndef UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
|
||||||
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
|
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICEHANDLER_H
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_connectedDeviceHandler : public RESTAPIHandler {
|
class RESTAPI_connectedDeviceHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICESHANDLER_H
|
#define UCENTRALFMS_RESTAPI_CONNECTEDDEVICESHANDLER_H
|
||||||
|
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_connectedDevicesHandler : public RESTAPIHandler {
|
class RESTAPI_connectedDevicesHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_deviceInformation_handler : public RESTAPIHandler {
|
class RESTAPI_deviceInformation_handler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -9,9 +9,13 @@
|
|||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
void RESTAPI_deviceReportHandler::DoGet() {
|
void RESTAPI_deviceReportHandler::DoGet() {
|
||||||
Daemon()->CreateDashboard();
|
poco_information(Logger(),fmt::format("GET-DASHBOARD: {}", Requester()));
|
||||||
Poco::JSON::Object O;
|
FMSObjects::DeviceReport Data;
|
||||||
Daemon()->GetDashboard().to_json(O);
|
if(Daemon()->GetDashboard().Get(Data, Logger())) {
|
||||||
ReturnObject(O);
|
Poco::JSON::Object Answer;
|
||||||
|
Data.to_json(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
return BadRequest(RESTAPI::Errors::InternalError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_deviceReportHandler : public RESTAPIHandler {
|
class RESTAPI_deviceReportHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
#ifndef UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
|
#ifndef UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
|
||||||
#define UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
|
#define UCENTRALFMS_RESTAPI_FIRMWAREAGEHANDLER_H
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_firmwareAgeHandler : public RESTAPIHandler {
|
class RESTAPI_firmwareAgeHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
#include "Poco/JSON/Parser.h"
|
#include "Poco/JSON/Parser.h"
|
||||||
|
|
||||||
#include "RESTAPI_firmwareHandler.h"
|
#include "RESTAPI/RESTAPI_firmwareHandler.h"
|
||||||
#include "StorageService.h"
|
#include "StorageService.h"
|
||||||
#include "framework/ow_constants.h"
|
#include "framework/ow_constants.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
void
|
void
|
||||||
@@ -16,7 +18,7 @@ namespace OpenWifi {
|
|||||||
if (!F.from_json(Obj)) {
|
if (!F.from_json(Obj)) {
|
||||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
}
|
}
|
||||||
F.id = MicroService::instance().CreateUUID();
|
F.id = MicroServiceCreateUUID();
|
||||||
if(StorageService()->FirmwaresDB().AddFirmware(F)) {
|
if(StorageService()->FirmwaresDB().AddFirmware(F)) {
|
||||||
Poco::JSON::Object Answer;
|
Poco::JSON::Object Answer;
|
||||||
F.to_json(Answer);
|
F.to_json(Answer);
|
||||||
@@ -78,7 +80,7 @@ namespace OpenWifi {
|
|||||||
SecurityObjects::NoteInfoVec NIV;
|
SecurityObjects::NoteInfoVec NIV;
|
||||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get(RESTAPI::Protocol::NOTES).toString());
|
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get(RESTAPI::Protocol::NOTES).toString());
|
||||||
for(auto const &i:NIV) {
|
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);
|
F.notes.push_back(ii);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
#ifndef UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
|
#ifndef UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
|
||||||
#define UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
|
#define UCENTRALFWS_RESTAPI_FIRMWAREHANDLER_H
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_firmwareHandler : public RESTAPIHandler {
|
class RESTAPI_firmwareHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
#ifndef UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
|
#ifndef UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
|
||||||
#define UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
|
#define UCENTRALFWS_RESTAPI_FIRMWARESHANDLER_H
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_firmwaresHandler : public RESTAPIHandler {
|
class RESTAPI_firmwaresHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
class RESTAPI_historyHandler : public RESTAPIHandler {
|
class RESTAPI_historyHandler : public RESTAPIHandler {
|
||||||
public:
|
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,
|
: RESTAPIHandler(bindings, L,
|
||||||
std::vector<std::string>
|
std::vector<std::string>
|
||||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "RESTAPI_AnalyticsObjects.h"
|
#include "RESTAPI_AnalyticsObjects.h"
|
||||||
#include "RESTAPI_ProvObjects.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_to_json;
|
||||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "RESTAPI_ProvObjects.h"
|
#include "RESTAPI_ProvObjects.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
@@ -375,7 +376,7 @@ namespace OpenWifi {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct WifiClientHistory {
|
struct WifiClientHistory {
|
||||||
uint64_t timestamp=OpenWifi::Now();
|
uint64_t timestamp=Utils::Now();
|
||||||
std::string station_id;
|
std::string station_id;
|
||||||
std::string bssid;
|
std::string bssid;
|
||||||
std::string ssid;
|
std::string ssid;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "RESTAPI_CertObjects.h"
|
#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_to_json;
|
||||||
using OpenWifi::RESTAPI_utils::field_from_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,"submitted", submitted);
|
||||||
field_to_json(Obj,"started", started);
|
field_to_json(Obj,"started", started);
|
||||||
field_to_json(Obj,"completed", completed);
|
field_to_json(Obj,"completed", completed);
|
||||||
|
field_to_json(Obj,"requesterUsername", requesterUsername);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
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,"submitted", submitted);
|
||||||
field_from_json(Obj,"started", started);
|
field_from_json(Obj,"started", started);
|
||||||
field_from_json(Obj,"completed", completed);
|
field_from_json(Obj,"completed", completed);
|
||||||
|
field_from_json(Obj,"requesterUsername", requesterUsername);
|
||||||
return true;
|
return true;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ namespace OpenWifi::CertObjects {
|
|||||||
uint64_t submitted=0;
|
uint64_t submitted=0;
|
||||||
uint64_t started=0;
|
uint64_t started=0;
|
||||||
uint64_t completed=0;
|
uint64_t completed=0;
|
||||||
|
std::string requesterUsername;
|
||||||
|
|
||||||
void to_json(Poco::JSON::Object &Obj) const;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "RESTAPI_FMSObjects.h"
|
#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_to_json;
|
||||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||||
@@ -233,7 +234,7 @@ namespace OpenWifi::FMSObjects {
|
|||||||
UnknownFirmwares_.clear();
|
UnknownFirmwares_.clear();
|
||||||
totalSecondsOld_.clear();
|
totalSecondsOld_.clear();
|
||||||
numberOfDevices = 0 ;
|
numberOfDevices = 0 ;
|
||||||
snapshot = OpenWifi::Now();
|
snapshot = Utils::Now();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
|
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
|
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
#ifdef TIP_GATEWAY_SERVICE
|
#ifdef TIP_GATEWAY_SERVICE
|
||||||
#include "DeviceRegistry.h"
|
#include "AP_WS_Server.h"
|
||||||
#include "CapabilitiesCache.h"
|
#include "CapabilitiesCache.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "RESTAPI_GWobjects.h"
|
#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_to_json;
|
||||||
using OpenWifi::RESTAPI_utils::field_from_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,"entity", entity);
|
||||||
field_to_json(Obj,"modified", modified);
|
field_to_json(Obj,"modified", modified);
|
||||||
field_to_json(Obj,"locale", locale);
|
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 {
|
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
|
||||||
@@ -57,7 +62,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
#ifdef TIP_GATEWAY_SERVICE
|
#ifdef TIP_GATEWAY_SERVICE
|
||||||
ConnectionState ConState;
|
ConnectionState ConState;
|
||||||
|
|
||||||
if (DeviceRegistry()->GetState(SerialNumber, ConState)) {
|
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
|
||||||
ConState.to_json(Obj);
|
ConState.to_json(Obj);
|
||||||
} else {
|
} else {
|
||||||
field_to_json(Obj,"ipAddress", "");
|
field_to_json(Obj,"ipAddress", "");
|
||||||
@@ -69,6 +74,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
|
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
|
||||||
field_to_json(Obj,"associations_2G", (uint64_t) 0);
|
field_to_json(Obj,"associations_2G", (uint64_t) 0);
|
||||||
field_to_json(Obj,"associations_5G", (uint64_t) 0);
|
field_to_json(Obj,"associations_5G", (uint64_t) 0);
|
||||||
|
field_to_json(Obj,"associations_6G", (uint64_t) 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -88,6 +94,10 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_from_json(Obj,"subscriber", subscriber);
|
field_from_json(Obj,"subscriber", subscriber);
|
||||||
field_from_json(Obj,"entity", entity);
|
field_from_json(Obj,"entity", entity);
|
||||||
field_from_json(Obj,"locale", locale);
|
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;
|
return true;
|
||||||
} catch (const Poco::Exception &E) {
|
} catch (const Poco::Exception &E) {
|
||||||
}
|
}
|
||||||
@@ -198,6 +208,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_to_json(Obj,"lastContact", LastContact);
|
field_to_json(Obj,"lastContact", LastContact);
|
||||||
field_to_json(Obj,"associations_2G", Associations_2G);
|
field_to_json(Obj,"associations_2G", Associations_2G);
|
||||||
field_to_json(Obj,"associations_5G", Associations_5G);
|
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,"webSocketClients", webSocketClients);
|
||||||
field_to_json(Obj,"websocketPackets", websocketPackets);
|
field_to_json(Obj,"websocketPackets", websocketPackets);
|
||||||
field_to_json(Obj,"kafkaClients", kafkaClients);
|
field_to_json(Obj,"kafkaClients", kafkaClients);
|
||||||
@@ -206,7 +217,8 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_to_json(Obj,"started", started);
|
field_to_json(Obj,"started", started);
|
||||||
field_to_json(Obj,"sessionId", sessionId);
|
field_to_json(Obj,"sessionId", sessionId);
|
||||||
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
|
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
|
||||||
field_to_json(Obj,"totalConnectionTime", OpenWifi::Now() - started);
|
field_to_json(Obj,"totalConnectionTime", Utils::Now() - started);
|
||||||
|
field_to_json(Obj,"certificateExpiryDate", certificateExpiryDate);
|
||||||
|
|
||||||
switch(VerifiedCertificate) {
|
switch(VerifiedCertificate) {
|
||||||
case NO_CERTIFICATE:
|
case NO_CERTIFICATE:
|
||||||
@@ -225,12 +237,14 @@ namespace OpenWifi::GWObjects {
|
|||||||
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
|
||||||
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
|
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||||
field_to_json(Obj,"connectedDevices", connectedDevices );
|
field_to_json(Obj,"connectedDevices", connectedDevices );
|
||||||
|
field_to_json(Obj,"connectingDevices", connectingDevices );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
try {
|
try {
|
||||||
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
|
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
|
||||||
field_from_json(Obj,"connectedDevices", connectedDevices );
|
field_from_json(Obj,"connectedDevices", connectedDevices );
|
||||||
|
field_from_json(Obj,"connectingDevices", connectingDevices );
|
||||||
return true;
|
return true;
|
||||||
} catch (const Poco::Exception &E) {
|
} catch (const Poco::Exception &E) {
|
||||||
}
|
}
|
||||||
@@ -283,7 +297,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
lastContact.clear();
|
lastContact.clear();
|
||||||
associations.clear();
|
associations.clear();
|
||||||
numberOfDevices = 0 ;
|
numberOfDevices = 0 ;
|
||||||
snapshot = OpenWifi::Now();
|
snapshot = Utils::Now();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
|
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
|
||||||
@@ -295,9 +309,12 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_to_json(Obj,"serialNumber",serialNumber);
|
field_to_json(Obj,"serialNumber",serialNumber);
|
||||||
field_to_json(Obj,"timeout",timeout);
|
field_to_json(Obj,"timeout",timeout);
|
||||||
field_to_json(Obj,"type",type);
|
field_to_json(Obj,"type",type);
|
||||||
field_to_json(Obj,"script",script);
|
|
||||||
field_to_json(Obj,"scriptId",scriptId);
|
field_to_json(Obj,"scriptId",scriptId);
|
||||||
|
field_to_json(Obj,"script",script);
|
||||||
field_to_json(Obj,"when",when);
|
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) {
|
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
@@ -308,6 +325,9 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_from_json(Obj,"script",script);
|
field_from_json(Obj,"script",script);
|
||||||
field_from_json(Obj,"scriptId",scriptId);
|
field_from_json(Obj,"scriptId",scriptId);
|
||||||
field_from_json(Obj,"when",when);
|
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;
|
return true;
|
||||||
} catch (const Poco::Exception &E) {
|
} catch (const Poco::Exception &E) {
|
||||||
}
|
}
|
||||||
@@ -379,6 +399,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_to_json(Obj,"secret",secret);
|
field_to_json(Obj,"secret",secret);
|
||||||
field_to_json(Obj,"certificate",certificate);
|
field_to_json(Obj,"certificate",certificate);
|
||||||
field_to_json(Obj,"radsec",radsec);
|
field_to_json(Obj,"radsec",radsec);
|
||||||
|
field_to_json(Obj,"allowSelfSigned",allowSelfSigned);
|
||||||
field_to_json(Obj,"radsecPort",radsecPort);
|
field_to_json(Obj,"radsecPort",radsecPort);
|
||||||
field_to_json(Obj,"radsecSecret",radsecSecret);
|
field_to_json(Obj,"radsecSecret",radsecSecret);
|
||||||
field_to_json(Obj,"radsecCacerts",radsecCacerts);
|
field_to_json(Obj,"radsecCacerts",radsecCacerts);
|
||||||
@@ -397,6 +418,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
field_from_json(Obj,"secret",secret);
|
field_from_json(Obj,"secret",secret);
|
||||||
field_from_json(Obj,"certificate",certificate);
|
field_from_json(Obj,"certificate",certificate);
|
||||||
field_from_json(Obj,"radsec",radsec);
|
field_from_json(Obj,"radsec",radsec);
|
||||||
|
field_from_json(Obj,"allowSelfSigned",allowSelfSigned);
|
||||||
field_from_json(Obj,"radsecSecret",radsecSecret);
|
field_from_json(Obj,"radsecSecret",radsecSecret);
|
||||||
field_from_json(Obj,"radsecPort",radsecPort);
|
field_from_json(Obj,"radsecPort",radsecPort);
|
||||||
field_from_json(Obj,"radsecCacerts",radsecCacerts);
|
field_from_json(Obj,"radsecCacerts",radsecCacerts);
|
||||||
@@ -409,5 +431,117 @@ namespace OpenWifi::GWObjects {
|
|||||||
}
|
}
|
||||||
return false;
|
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,23 +28,52 @@ namespace OpenWifi::GWObjects {
|
|||||||
uint64_t TX = 0, RX = 0;
|
uint64_t TX = 0, RX = 0;
|
||||||
uint64_t Associations_2G=0;
|
uint64_t Associations_2G=0;
|
||||||
uint64_t Associations_5G=0;
|
uint64_t Associations_5G=0;
|
||||||
|
uint64_t Associations_6G=0;
|
||||||
bool Connected = false;
|
bool Connected = false;
|
||||||
uint64_t LastContact=0;
|
uint64_t LastContact=0;
|
||||||
std::string Firmware;
|
std::string Firmware;
|
||||||
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
|
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
|
||||||
std::string Compatible;
|
std::string Compatible;
|
||||||
uint64_t kafkaClients=0;
|
uint64_t kafkaClients=0;
|
||||||
uint64_t webSocketClients=0;
|
uint64_t webSocketClients=0;
|
||||||
uint64_t kafkaPackets=0;
|
uint64_t kafkaPackets=0;
|
||||||
uint64_t websocketPackets=0;
|
uint64_t websocketPackets=0;
|
||||||
std::string locale;
|
std::string locale;
|
||||||
uint64_t started=0;
|
uint64_t started=0;
|
||||||
uint64_t sessionId=0;
|
uint64_t sessionId=0;
|
||||||
double connectionCompletionTime=0.0;
|
double connectionCompletionTime=0.0;
|
||||||
|
std::uint64_t certificateExpiryDate=0;
|
||||||
|
|
||||||
void to_json(Poco::JSON::Object &Obj) const;
|
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 {
|
struct Device {
|
||||||
std::string SerialNumber;
|
std::string SerialNumber;
|
||||||
std::string DeviceType;
|
std::string DeviceType;
|
||||||
@@ -68,6 +97,10 @@ namespace OpenWifi::GWObjects {
|
|||||||
std::string entity;
|
std::string entity;
|
||||||
uint64_t modified=0;
|
uint64_t modified=0;
|
||||||
std::string locale;
|
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(Poco::JSON::Object &Obj) const;
|
||||||
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
void to_json_with_status(Poco::JSON::Object &Obj) const;
|
||||||
@@ -78,6 +111,8 @@ namespace OpenWifi::GWObjects {
|
|||||||
struct DeviceConnectionStatistics {
|
struct DeviceConnectionStatistics {
|
||||||
std::uint64_t connectedDevices = 0;
|
std::uint64_t connectedDevices = 0;
|
||||||
std::uint64_t averageConnectionTime = 0;
|
std::uint64_t averageConnectionTime = 0;
|
||||||
|
std::uint64_t connectingDevices = 0;
|
||||||
|
|
||||||
void to_json(Poco::JSON::Object &Obj) const;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
};
|
};
|
||||||
@@ -211,13 +246,44 @@ namespace OpenWifi::GWObjects {
|
|||||||
void to_json(Poco::JSON::Object &Obj) const;
|
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 {
|
struct ScriptRequest {
|
||||||
uint64_t timeout=30;
|
|
||||||
std::string serialNumber;
|
std::string serialNumber;
|
||||||
|
uint64_t timeout=30;
|
||||||
std::string type;
|
std::string type;
|
||||||
std::string script;
|
std::string script;
|
||||||
std::string scriptId;
|
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;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
};
|
};
|
||||||
@@ -230,6 +296,7 @@ namespace OpenWifi::GWObjects {
|
|||||||
std::string secret;
|
std::string secret;
|
||||||
std::string certificate;
|
std::string certificate;
|
||||||
bool radsec=false;
|
bool radsec=false;
|
||||||
|
bool allowSelfSigned=false;
|
||||||
uint16_t radsecPort=2083;
|
uint16_t radsecPort=2083;
|
||||||
std::string radsecSecret;
|
std::string radsecSecret;
|
||||||
std::string radsecKey;
|
std::string radsecKey;
|
||||||
@@ -271,4 +338,5 @@ namespace OpenWifi::GWObjects {
|
|||||||
void to_json(Poco::JSON::Object &Obj) const;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
110
src/RESTObjects/RESTAPI_OWLSobjects.cpp
Normal file
110
src/RESTObjects/RESTAPI_OWLSobjects.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-08-31.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "framework/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 "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_to_json;
|
||||||
using OpenWifi::RESTAPI_utils::field_from_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, "devClass",devClass);
|
||||||
field_to_json( Obj, "locale",locale);
|
field_to_json( Obj, "locale",locale);
|
||||||
field_to_json( Obj, "realMacAddress",realMacAddress);
|
field_to_json( Obj, "realMacAddress",realMacAddress);
|
||||||
|
field_to_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
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,"devClass",devClass);
|
||||||
field_from_json( Obj,"locale",locale);
|
field_from_json( Obj,"locale",locale);
|
||||||
field_from_json( Obj,"realMacAddress",realMacAddress);
|
field_from_json( Obj,"realMacAddress",realMacAddress);
|
||||||
|
field_from_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
|
||||||
return true;
|
return true;
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
|
|
||||||
@@ -1091,7 +1095,7 @@ namespace OpenWifi::ProvObjects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
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"))
|
if(O->has("name"))
|
||||||
I.name = O->get("name").toString();
|
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) {
|
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"))
|
if(O->has("name"))
|
||||||
I.name = O->get("name").toString();
|
I.name = O->get("name").toString();
|
||||||
|
|
||||||
@@ -1130,14 +1134,14 @@ namespace OpenWifi::ProvObjects {
|
|||||||
}
|
}
|
||||||
I.notes = N;
|
I.notes = N;
|
||||||
I.modified = I.created = Now;
|
I.modified = I.created = Now;
|
||||||
I.id = MicroService::CreateUUID();
|
I.id = MicroServiceCreateUUID();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) {
|
||||||
I.modified = I.created = OpenWifi::Now();
|
I.modified = I.created = Utils::Now();
|
||||||
I.id = MicroService::CreateUUID();
|
I.id = MicroServiceCreateUUID();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1159,5 +1163,82 @@ namespace OpenWifi::ProvObjects {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RRMAlgorithmDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
field_to_json(Obj,"name",name);
|
||||||
|
field_to_json(Obj,"parameters",parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RRMAlgorithmDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
try {
|
||||||
|
field_from_json(Obj,"name",name);
|
||||||
|
field_from_json(Obj,"parameters",parameters);
|
||||||
|
return true;
|
||||||
|
} catch(...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RRMDetails::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
field_to_json(Obj,"vendor",vendor);
|
||||||
|
field_to_json(Obj,"schedule",schedule);
|
||||||
|
field_to_json(Obj,"algorithms",algorithms);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RRMDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
try {
|
||||||
|
field_from_json(Obj,"vendor",vendor);
|
||||||
|
field_from_json(Obj,"schedule",schedule);
|
||||||
|
field_from_json(Obj,"algorithms",algorithms);
|
||||||
|
return true;
|
||||||
|
} catch(...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||||
#include "RESTAPI_SecurityObjects.h"
|
|
||||||
|
|
||||||
namespace OpenWifi::ProvObjects {
|
namespace OpenWifi::ProvObjects {
|
||||||
|
|
||||||
@@ -62,6 +61,21 @@ namespace OpenWifi::ProvObjects {
|
|||||||
};
|
};
|
||||||
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
|
||||||
|
|
||||||
|
struct RRMAlgorithmDetails {
|
||||||
|
std::string name;
|
||||||
|
std::string parameters;
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RRMDetails {
|
||||||
|
std::string vendor;
|
||||||
|
std::string schedule;
|
||||||
|
std::vector<RRMAlgorithmDetails> algorithms;
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
|
};
|
||||||
|
|
||||||
struct DeviceRules {
|
struct DeviceRules {
|
||||||
std::string rcOnly{"inherit"};
|
std::string rcOnly{"inherit"};
|
||||||
std::string rrm{"inherit"};
|
std::string rrm{"inherit"};
|
||||||
@@ -414,6 +428,7 @@ namespace OpenWifi::ProvObjects {
|
|||||||
std::string devClass;
|
std::string devClass;
|
||||||
std::string locale;
|
std::string locale;
|
||||||
std::string realMacAddress;
|
std::string realMacAddress;
|
||||||
|
bool doNotAllowOverrides=false;
|
||||||
|
|
||||||
void to_json(Poco::JSON::Object &Obj) const;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
@@ -679,6 +694,27 @@ namespace OpenWifi::ProvObjects {
|
|||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
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 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 Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||||
bool CreateObjectInfo(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/Parser.h"
|
||||||
#include "Poco/JSON/Stringifier.h"
|
#include "Poco/JSON/Stringifier.h"
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_utils.h"
|
||||||
#include "RESTAPI_SecurityObjects.h"
|
#include "RESTAPI_SecurityObjects.h"
|
||||||
|
|
||||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||||
@@ -433,7 +433,7 @@ namespace OpenWifi::SecurityObjects {
|
|||||||
SecurityObjects::NoteInfoVec NIV;
|
SecurityObjects::NoteInfoVec NIV;
|
||||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
|
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
|
||||||
for(auto const &i:NIV) {
|
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);
|
Notes.push_back(ii);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -446,7 +446,7 @@ namespace OpenWifi::SecurityObjects {
|
|||||||
|
|
||||||
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
|
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
|
||||||
for(auto const &i:NewNotes) {
|
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);
|
ExistingNotes.push_back(ii);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -619,5 +619,80 @@ namespace OpenWifi::SecurityObjects {
|
|||||||
field_to_json(Obj,"login",login);
|
field_to_json(Obj,"login",login);
|
||||||
field_to_json(Obj,"logout",logout);
|
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/JSON/Object.h"
|
||||||
#include "Poco/Data/LOB.h"
|
#include "Poco/Data/LOB.h"
|
||||||
#include "Poco/Data/LOBStream.h"
|
#include "Poco/Data/LOBStream.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
uint64_t Now();
|
uint64_t Now();
|
||||||
@@ -62,7 +63,7 @@ namespace OpenWifi {
|
|||||||
std::string UserTypeToString(USER_ROLE U);
|
std::string UserTypeToString(USER_ROLE U);
|
||||||
|
|
||||||
struct NoteInfo {
|
struct NoteInfo {
|
||||||
uint64_t created=0; // = OpenWifi::Now();
|
uint64_t created=0; // = Utils::Now();
|
||||||
std::string createdBy;
|
std::string createdBy;
|
||||||
std::string note;
|
std::string note;
|
||||||
|
|
||||||
@@ -101,7 +102,7 @@ namespace OpenWifi {
|
|||||||
std::string uuid;
|
std::string uuid;
|
||||||
std::string question;
|
std::string question;
|
||||||
std::string method;
|
std::string method;
|
||||||
uint64_t created = OpenWifi::Now();
|
uint64_t created = Utils::Now();
|
||||||
|
|
||||||
void to_json(Poco::JSON::Object &Obj) const;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||||
@@ -251,7 +252,8 @@ namespace OpenWifi {
|
|||||||
VERIFY_EMAIL,
|
VERIFY_EMAIL,
|
||||||
SUB_FORGOT_PASSWORD,
|
SUB_FORGOT_PASSWORD,
|
||||||
SUB_VERIFY_EMAIL,
|
SUB_VERIFY_EMAIL,
|
||||||
SUB_SIGNUP
|
SUB_SIGNUP,
|
||||||
|
EMAIL_INVITATION
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ActionLink {
|
struct ActionLink {
|
||||||
@@ -263,7 +265,7 @@ namespace OpenWifi {
|
|||||||
std::string locale;
|
std::string locale;
|
||||||
std::string message;
|
std::string message;
|
||||||
uint64_t sent=0;
|
uint64_t sent=0;
|
||||||
uint64_t created=OpenWifi::Now();
|
uint64_t created=Utils::Now();
|
||||||
uint64_t expires=0;
|
uint64_t expires=0;
|
||||||
uint64_t completed=0;
|
uint64_t completed=0;
|
||||||
uint64_t canceled=0;
|
uint64_t canceled=0;
|
||||||
@@ -323,5 +325,44 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
void to_json(Poco::JSON::Object &Obj) const;
|
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 "RESTAPI_SubObjects.h"
|
||||||
#include "framework/MicroService.h"
|
#include "framework/RESTAPI_utils.h"
|
||||||
|
|
||||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||||
|
|
||||||
|
|
||||||
namespace OpenWifi::SubObjects {
|
namespace OpenWifi::SubObjects {
|
||||||
|
|
||||||
void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const {
|
void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include "GW_SDK.h"
|
#include "GW_SDK.h"
|
||||||
#include "Daemon.h"
|
|
||||||
#include "Poco/Net/HTTPResponse.h"
|
#include "Poco/Net/HTTPResponse.h"
|
||||||
|
|
||||||
|
#include "framework/MicroServiceNames.h"
|
||||||
|
#include "framework/OpenAPIRequests.h"
|
||||||
|
|
||||||
namespace OpenWifi::SDK::GW {
|
namespace OpenWifi::SDK::GW {
|
||||||
|
|
||||||
bool SendFirmwareUpgradeCommand( const std::string & serialNumber, const std::string & URI, [[maybe_unused]] uint64_t When ) {
|
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.
|
// Created by stephane bourque on 2021-10-05.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef OWFMS_GW_SDK_H
|
#pragma once
|
||||||
#define OWFMS_GW_SDK_H
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include "framework/MicroService.h"
|
|
||||||
|
|
||||||
namespace OpenWifi::SDK::GW {
|
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.
|
// Created by stephane bourque on 2021-10-04.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/OpenAPIRequests.h"
|
||||||
|
#include "framework/MicroServiceNames.h"
|
||||||
|
|
||||||
namespace OpenWifi::SDK::Prov {
|
namespace OpenWifi::SDK::Prov {
|
||||||
bool GetFirmwareOptions( const std::string & serialNumber, std::string &firmwareUpgrade,
|
bool GetFirmwareOptions( const std::string & serialNumber, std::string &firmwareUpgrade,
|
||||||
|
|||||||
@@ -2,10 +2,9 @@
|
|||||||
// Created by stephane bourque on 2021-10-04.
|
// Created by stephane bourque on 2021-10-04.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef OWFMS_PROV_SDK_H
|
#pragma once
|
||||||
#define OWFMS_PROV_SDK_H
|
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include <string>
|
||||||
|
|
||||||
namespace OpenWifi::SDK::Prov {
|
namespace OpenWifi::SDK::Prov {
|
||||||
|
|
||||||
@@ -14,5 +13,3 @@ namespace OpenWifi::SDK::Prov {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif //OWFMS_PROV_SDK_H
|
|
||||||
|
|||||||
@@ -6,10 +6,8 @@
|
|||||||
// Arilia Wireless Inc.
|
// Arilia Wireless Inc.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef UCENTRAL_USTORAGESERVICE_H
|
#pragma once
|
||||||
#define UCENTRAL_USTORAGESERVICE_H
|
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
|
||||||
#include "framework/StorageClass.h"
|
#include "framework/StorageClass.h"
|
||||||
|
|
||||||
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
#include "RESTObjects/RESTAPI_FMSObjects.h"
|
||||||
@@ -53,4 +51,3 @@ namespace OpenWifi {
|
|||||||
|
|
||||||
} // namespace
|
} // 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
|
#pragma once
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "Poco/Logger.h"
|
||||||
#include "Poco/JSON/Parser.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 {
|
namespace OpenWifi {
|
||||||
inline void API_Proxy( Poco::Logger &Logger,
|
inline void API_Proxy( Poco::Logger &Logger,
|
||||||
@@ -15,7 +21,7 @@ namespace OpenWifi {
|
|||||||
const char * PathRewrite,
|
const char * PathRewrite,
|
||||||
uint64_t msTimeout_ = 10000 ) {
|
uint64_t msTimeout_ = 10000 ) {
|
||||||
try {
|
try {
|
||||||
auto Services = MicroService::instance().GetServices(ServiceType);
|
auto Services = MicroServiceGetServices(ServiceType);
|
||||||
for(auto const &Svc:Services) {
|
for(auto const &Svc:Services) {
|
||||||
Poco::URI SourceURI(Request->getURI());
|
Poco::URI SourceURI(Request->getURI());
|
||||||
Poco::URI DestinationURI(Svc.PrivateEndPoint);
|
Poco::URI DestinationURI(Svc.PrivateEndPoint);
|
||||||
@@ -35,7 +41,7 @@ namespace OpenWifi {
|
|||||||
ProxyRequest.add("Authorization", Request->get("Authorization"));
|
ProxyRequest.add("Authorization", Request->get("Authorization"));
|
||||||
} else {
|
} else {
|
||||||
ProxyRequest.add("X-API-KEY", Svc.AccessKey);
|
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) {
|
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
|
#pragma once
|
||||||
|
|
||||||
#include <nlohmann/json-schema.hpp>
|
#include <nlohmann/json-schema.hpp>
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
using nlohmann::json_schema::json_validator;
|
using nlohmann::json_schema::json_validator;
|
||||||
@@ -32,7 +32,7 @@ namespace OpenWifi {
|
|||||||
nlohmann::json RootSchema_;
|
nlohmann::json RootSchema_;
|
||||||
|
|
||||||
ConfigurationValidator():
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
namespace OpenWifi::KafkaTopics {
|
namespace OpenWifi::KafkaTopics {
|
||||||
static const std::string HEALTHCHECK{"healthcheck"};
|
static const std::string HEALTHCHECK{"healthcheck"};
|
||||||
static const std::string STATE{"state"};
|
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
@@ -10,6 +10,7 @@
|
|||||||
#include "Poco/Net/NetException.h"
|
#include "Poco/Net/NetException.h"
|
||||||
#include "Poco/Net/SSLException.h"
|
#include "Poco/Net/SSLException.h"
|
||||||
#include "Poco/JSON/Template.h"
|
#include "Poco/JSON/Template.h"
|
||||||
|
#include "Poco/JSON/JSONException.h"
|
||||||
#include "Poco/Thread.h"
|
#include "Poco/Thread.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
@@ -101,6 +102,48 @@ namespace OpenWifi {
|
|||||||
E.displayText(),
|
E.displayText(),
|
||||||
E.message(),
|
E.message(),
|
||||||
E.what()));
|
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) {
|
} catch (const Poco::RuntimeException &E) {
|
||||||
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
|
||||||
t_name, t_id, E.code(),
|
t_name, t_id, E.code(),
|
||||||
|
|||||||
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::string UUID_t;
|
||||||
typedef std::vector<UUID_t> UUIDvec_t;
|
typedef std::vector<UUID_t> UUIDvec_t;
|
||||||
typedef std::map<std::string,std::map<uint32_t,uint64_t>> Counted3DMapSII;
|
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 {
|
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
|
||||||
|
|
||||||
66
src/framework/RESTAPI_PartHandler.h
Normal file
66
src/framework/RESTAPI_PartHandler.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "Poco/Net/PartHandler.h"
|
||||||
|
#include "Poco/Net/MessageHeader.h"
|
||||||
|
#include "Poco/CountingStream.h"
|
||||||
|
#include "Poco/NullStream.h"
|
||||||
|
#include "Poco/StreamCopier.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
class RESTAPI_PartHandler: public Poco::Net::PartHandler {
|
||||||
|
public:
|
||||||
|
RESTAPI_PartHandler():
|
||||||
|
_length(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream) override
|
||||||
|
{
|
||||||
|
_type = header.get("Content-Type", "(unspecified)");
|
||||||
|
if (header.has("Content-Disposition"))
|
||||||
|
{
|
||||||
|
std::string disp;
|
||||||
|
Poco::Net::NameValueCollection params;
|
||||||
|
Poco::Net::MessageHeader::splitParameters(header["Content-Disposition"], disp, params);
|
||||||
|
_name = params.get("name", "(unnamed)");
|
||||||
|
_fileName = params.get("filename", "(unnamed)");
|
||||||
|
}
|
||||||
|
|
||||||
|
Poco::CountingInputStream istr(stream);
|
||||||
|
Poco::NullOutputStream ostr;
|
||||||
|
Poco::StreamCopier::copyStream(istr, ostr);
|
||||||
|
_length = (int)istr.chars();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline int length() const
|
||||||
|
{
|
||||||
|
return _length;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline const std::string& name() const
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline const std::string& fileName() const
|
||||||
|
{
|
||||||
|
return _fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline const std::string& contentType() const
|
||||||
|
{
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _length;
|
||||||
|
std::string _type;
|
||||||
|
std::string _name;
|
||||||
|
std::string _fileName;
|
||||||
|
};
|
||||||
|
}
|
||||||
75
src/framework/RESTAPI_RateLimiter.h
Normal file
75
src/framework/RESTAPI_RateLimiter.h
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
|
#include "Poco/URI.h"
|
||||||
|
#include "Poco/Net/HTTPServerRequest.h"
|
||||||
|
#include "Poco/ExpireLRUCache.h"
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
|
||||||
|
class RESTAPI_RateLimiter : public SubSystemServer {
|
||||||
|
public:
|
||||||
|
|
||||||
|
struct ClientCacheEntry {
|
||||||
|
int64_t Start=0;
|
||||||
|
int Count=0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto instance() {
|
||||||
|
static auto instance_ = new RESTAPI_RateLimiter;
|
||||||
|
return instance_;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int Start() final { return 0;};
|
||||||
|
inline void Stop() final { };
|
||||||
|
|
||||||
|
inline bool IsRateLimited(const Poco::Net::HTTPServerRequest &R, int64_t Period, int64_t MaxCalls) {
|
||||||
|
Poco::URI uri(R.getURI());
|
||||||
|
auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
|
||||||
|
auto E = Cache_.get(H);
|
||||||
|
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
if(E.isNull()) {
|
||||||
|
Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if((Now-E->Start)<Period) {
|
||||||
|
E->Count++;
|
||||||
|
Cache_.update(H,E);
|
||||||
|
if(E->Count > MaxCalls) {
|
||||||
|
poco_warning(Logger(),fmt::format("RATE-LIMIT-EXCEEDED: from '{}'", R.clientAddress().toString()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
E->Start = Now;
|
||||||
|
E->Count = 1;
|
||||||
|
Cache_.update(H,E);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Clear() {
|
||||||
|
Cache_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Poco::ExpireLRUCache<uint64_t,ClientCacheEntry> Cache_{2048};
|
||||||
|
std::hash<std::string> str_hash;
|
||||||
|
|
||||||
|
RESTAPI_RateLimiter() noexcept:
|
||||||
|
SubSystemServer("RateLimiter", "RATE-LIMITER", "rate.limiter")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
157
src/framework/RESTAPI_SystemCommand.h
Normal file
157
src/framework/RESTAPI_SystemCommand.h
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
|
||||||
|
#include "Poco/Environment.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
|
||||||
|
class RESTAPI_system_command : public RESTAPIHandler {
|
||||||
|
public:
|
||||||
|
RESTAPI_system_command(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_POST,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
|
Server,
|
||||||
|
TransactionId,
|
||||||
|
Internal) {}
|
||||||
|
static auto PathName() { return std::list<std::string>{"/api/v1/system"};}
|
||||||
|
|
||||||
|
inline void DoGet() {
|
||||||
|
std::string Arg;
|
||||||
|
if(HasParameter("command",Arg) && Arg=="info") {
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
|
||||||
|
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
|
||||||
|
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
|
||||||
|
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
|
||||||
|
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
|
||||||
|
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
|
||||||
|
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
|
||||||
|
|
||||||
|
Poco::JSON::Array Certificates;
|
||||||
|
auto SubSystems = MicroServiceGetFullSubSystems();
|
||||||
|
std::set<std::string> CertNames;
|
||||||
|
|
||||||
|
for(const auto &i:SubSystems) {
|
||||||
|
auto Hosts=i->HostSize();
|
||||||
|
for(uint64_t j=0;j<Hosts;++j) {
|
||||||
|
auto CertFileName = i->Host(j).CertFile();
|
||||||
|
if(!CertFileName.empty()) {
|
||||||
|
Poco::File F1(CertFileName);
|
||||||
|
if(F1.exists()) {
|
||||||
|
auto InsertResult = CertNames.insert(CertFileName);
|
||||||
|
if(InsertResult.second) {
|
||||||
|
Poco::JSON::Object Inner;
|
||||||
|
Poco::Path F(CertFileName);
|
||||||
|
Inner.set("filename", F.getFileName());
|
||||||
|
Poco::Crypto::X509Certificate C(CertFileName);
|
||||||
|
auto ExpiresOn = C.expiresOn();
|
||||||
|
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
|
||||||
|
Certificates.add(Inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Answer.set("certificates", Certificates);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
if(GetBoolParameter("extraConfiguration")) {
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
MicroServiceGetExtraConfiguration(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DoPost() final {
|
||||||
|
const auto & Obj = ParsedBody_;
|
||||||
|
if (Obj->has(RESTAPI::Protocol::COMMAND)) {
|
||||||
|
auto Command = Poco::toLower(Obj->get(RESTAPI::Protocol::COMMAND).toString());
|
||||||
|
if (Command == RESTAPI::Protocol::SETLOGLEVEL) {
|
||||||
|
if (Obj->has(RESTAPI::Protocol::SUBSYSTEMS) &&
|
||||||
|
Obj->isArray(RESTAPI::Protocol::SUBSYSTEMS)) {
|
||||||
|
auto ParametersBlock = Obj->getArray(RESTAPI::Protocol::SUBSYSTEMS);
|
||||||
|
for (const auto &i : *ParametersBlock) {
|
||||||
|
Poco::JSON::Parser pp;
|
||||||
|
auto InnerObj = pp.parse(i).extract<Poco::JSON::Object::Ptr>();
|
||||||
|
if (InnerObj->has(RESTAPI::Protocol::TAG) &&
|
||||||
|
InnerObj->has(RESTAPI::Protocol::VALUE)) {
|
||||||
|
auto Name = GetS(RESTAPI::Protocol::TAG, InnerObj);
|
||||||
|
auto Value = GetS(RESTAPI::Protocol::VALUE, InnerObj);
|
||||||
|
MicroServiceSetSubsystemLogLevel(Name, Value);
|
||||||
|
poco_information(Logger_,
|
||||||
|
fmt::format("Setting log level for {} at {}", Name, Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK();
|
||||||
|
}
|
||||||
|
} else if (Command == RESTAPI::Protocol::GETLOGLEVELS) {
|
||||||
|
auto CurrentLogLevels = MicroServiceGetLogLevels();
|
||||||
|
Poco::JSON::Object Result;
|
||||||
|
Poco::JSON::Array Array;
|
||||||
|
for (auto &[Name, Level] : CurrentLogLevels) {
|
||||||
|
Poco::JSON::Object Pair;
|
||||||
|
Pair.set(RESTAPI::Protocol::TAG, Name);
|
||||||
|
Pair.set(RESTAPI::Protocol::VALUE, Level);
|
||||||
|
Array.add(Pair);
|
||||||
|
}
|
||||||
|
Result.set(RESTAPI::Protocol::TAGLIST, Array);
|
||||||
|
return ReturnObject(Result);
|
||||||
|
} else if (Command == RESTAPI::Protocol::GETLOGLEVELNAMES) {
|
||||||
|
Poco::JSON::Object Result;
|
||||||
|
Poco::JSON::Array LevelNamesArray;
|
||||||
|
const Types::StringVec &LevelNames = MicroServiceGetLogLevelNames();
|
||||||
|
for (const auto &i : LevelNames)
|
||||||
|
LevelNamesArray.add(i);
|
||||||
|
Result.set(RESTAPI::Protocol::LIST, LevelNamesArray);
|
||||||
|
return ReturnObject(Result);
|
||||||
|
} else if (Command == RESTAPI::Protocol::GETSUBSYSTEMNAMES) {
|
||||||
|
Poco::JSON::Object Result;
|
||||||
|
Poco::JSON::Array LevelNamesArray;
|
||||||
|
const Types::StringVec &SubSystemNames = MicroServiceGetSubSystems();
|
||||||
|
for (const auto &i : SubSystemNames)
|
||||||
|
LevelNamesArray.add(i);
|
||||||
|
Result.set(RESTAPI::Protocol::LIST, LevelNamesArray);
|
||||||
|
return ReturnObject(Result);
|
||||||
|
} else if (Command == RESTAPI::Protocol::STATS) {
|
||||||
|
|
||||||
|
} else if (Command == RESTAPI::Protocol::RELOAD) {
|
||||||
|
if (Obj->has(RESTAPI::Protocol::SUBSYSTEMS) &&
|
||||||
|
Obj->isArray(RESTAPI::Protocol::SUBSYSTEMS)) {
|
||||||
|
auto SubSystems = Obj->getArray(RESTAPI::Protocol::SUBSYSTEMS);
|
||||||
|
std::vector<std::string> Names;
|
||||||
|
for (const auto &i : *SubSystems)
|
||||||
|
Names.push_back(i.toString());
|
||||||
|
std::thread ReloadThread([Names](){
|
||||||
|
std::this_thread::sleep_for(10000ms);
|
||||||
|
for(const auto &i:Names) {
|
||||||
|
if(i=="daemon")
|
||||||
|
MicroServiceReload();
|
||||||
|
else
|
||||||
|
MicroServiceReload(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ReloadThread.detach();
|
||||||
|
}
|
||||||
|
return OK();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return BadRequest(RESTAPI::Errors::InvalidCommand);
|
||||||
|
}
|
||||||
|
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoPut() final {};
|
||||||
|
void DoDelete() final {};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
52
src/framework/RESTAPI_SystemConfiguration.h
Normal file
52
src/framework/RESTAPI_SystemConfiguration.h
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-31.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
|
||||||
|
class RESTAPI_system_configuration : public RESTAPIHandler {
|
||||||
|
public:
|
||||||
|
RESTAPI_system_configuration(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_PUT,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_GET,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
|
Server, TransactionId, Internal) {}
|
||||||
|
|
||||||
|
static auto PathName() { return std::list<std::string>{"/api/v1/systemConfiguration"}; }
|
||||||
|
|
||||||
|
inline void DoPost() final {}
|
||||||
|
|
||||||
|
inline void DoGet() final {
|
||||||
|
|
||||||
|
return OK();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DoPut() final{
|
||||||
|
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
|
||||||
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK();
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void DoDelete() final{
|
||||||
|
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
|
||||||
|
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
|
||||||
|
}
|
||||||
|
MicroServiceDeleteOverrideConfiguration();
|
||||||
|
return OK();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
45
src/framework/RESTAPI_WebSocketServer.h
Normal file
45
src/framework/RESTAPI_WebSocketServer.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-26.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "framework/RESTAPI_Handler.h"
|
||||||
|
#include "Poco/Net/WebSocket.h"
|
||||||
|
|
||||||
|
#include "framework/UI_WebSocketClientServer.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
class RESTAPI_webSocketServer : public RESTAPIHandler {
|
||||||
|
public:
|
||||||
|
inline RESTAPI_webSocketServer(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,
|
||||||
|
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||||
|
Server, TransactionId, Internal,false) {}
|
||||||
|
static auto PathName() { return std::list<std::string>{"/api/v1/ws"};}
|
||||||
|
void DoGet() final {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Poco::Net::WebSocket WS(*Request, *Response);
|
||||||
|
auto Id = MicroServiceCreateUUID();
|
||||||
|
UI_WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email, TransactionId_);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
std::cout << "Cannot create websocket client..." << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(...) {
|
||||||
|
std::cout << "Cannot upgrade connection..." << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
void DoDelete() final {};
|
||||||
|
void DoPost() final {};
|
||||||
|
void DoPut() final {};
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
}
|
||||||
484
src/framework/RESTAPI_utils.h
Normal file
484
src/framework/RESTAPI_utils.h
Normal file
@@ -0,0 +1,484 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "Poco/JSON/Object.h"
|
||||||
|
#include "Poco/JSON/Parser.h"
|
||||||
|
#include "Poco/Data/LOB.h"
|
||||||
|
#include "Poco/Net/HTTPServerRequest.h"
|
||||||
|
|
||||||
|
#include "framework/OpenWifiTypes.h"
|
||||||
|
#include "framework/utils.h"
|
||||||
|
|
||||||
|
namespace OpenWifi::RESTAPI_utils {
|
||||||
|
|
||||||
|
inline void EmbedDocument(const std::string & ObjName, Poco::JSON::Object & Obj, const std::string &ObjStr) {
|
||||||
|
std::string D = ObjStr.empty() ? "{}" : ObjStr;
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
Poco::Dynamic::Var result = P.parse(D);
|
||||||
|
const auto &DetailsObj = result.extract<Poco::JSON::Object::Ptr>();
|
||||||
|
Obj.set(ObjName, DetailsObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, bool V) {
|
||||||
|
Obj.set(Field,V);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, double V) {
|
||||||
|
Obj.set(Field,V);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, float V) {
|
||||||
|
Obj.set(Field,V);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::string & S) {
|
||||||
|
Obj.set(Field,S);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const char * S) {
|
||||||
|
Obj.set(Field,S);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int16_t Value) {
|
||||||
|
Obj.set(Field, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int32_t Value) {
|
||||||
|
Obj.set(Field, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, int64_t Value) {
|
||||||
|
Obj.set(Field, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint16_t Value) {
|
||||||
|
Obj.set(Field, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint32_t Value) {
|
||||||
|
Obj.set(Field, Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, uint64_t Value) {
|
||||||
|
Obj.set(Field,Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Poco::Data::BLOB &Value) {
|
||||||
|
auto Result = Utils::base64encode((const unsigned char *)Value.rawContent(),Value.size());
|
||||||
|
Obj.set(Field,Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringPairVec & S) {
|
||||||
|
Poco::JSON::Array Array;
|
||||||
|
for(const auto &i:S) {
|
||||||
|
Poco::JSON::Object O;
|
||||||
|
O.set("tag",i.first);
|
||||||
|
O.set("value", i.second);
|
||||||
|
Array.add(O);
|
||||||
|
}
|
||||||
|
Obj.set(Field,Array);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::StringVec &V) {
|
||||||
|
Poco::JSON::Array A;
|
||||||
|
for(const auto &i:V)
|
||||||
|
A.add(i);
|
||||||
|
Obj.set(Field,A);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::TagList &V) {
|
||||||
|
Poco::JSON::Array A;
|
||||||
|
for(const auto &i:V)
|
||||||
|
A.add(i);
|
||||||
|
Obj.set(Field,A);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::CountedMap &M) {
|
||||||
|
Poco::JSON::Array A;
|
||||||
|
for(const auto &[Key,Value]:M) {
|
||||||
|
Poco::JSON::Object O;
|
||||||
|
O.set("tag",Key);
|
||||||
|
O.set("value", Value);
|
||||||
|
A.add(O);
|
||||||
|
}
|
||||||
|
Obj.set(Field,A);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_to_json(Poco::JSON::Object &Obj, const char *Field, const Types::Counted3DMapSII &M) {
|
||||||
|
Poco::JSON::Array A;
|
||||||
|
for(const auto &[OrgName,MonthlyNumberMap]:M) {
|
||||||
|
Poco::JSON::Object OrgObject;
|
||||||
|
OrgObject.set("tag",OrgName);
|
||||||
|
Poco::JSON::Array MonthlyArray;
|
||||||
|
for(const auto &[Month,Counter]:MonthlyNumberMap) {
|
||||||
|
Poco::JSON::Object Inner;
|
||||||
|
Inner.set("value", Month);
|
||||||
|
Inner.set("counter", Counter);
|
||||||
|
MonthlyArray.add(Inner);
|
||||||
|
}
|
||||||
|
OrgObject.set("index",MonthlyArray);
|
||||||
|
A.add(OrgObject);
|
||||||
|
}
|
||||||
|
Obj.set(Field, A);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> void field_to_json(Poco::JSON::Object &Obj,
|
||||||
|
const char *Field,
|
||||||
|
const T &V,
|
||||||
|
std::function<std::string(const T &)> F) {
|
||||||
|
Obj.set(Field, F(V));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void field_to_json(Poco::JSON::Object &Obj, const char *Field, const std::vector<T> &Value) {
|
||||||
|
Poco::JSON::Array Arr;
|
||||||
|
for(const auto &i:Value) {
|
||||||
|
Poco::JSON::Object AO;
|
||||||
|
i.to_json(AO);
|
||||||
|
Arr.add(AO);
|
||||||
|
}
|
||||||
|
Obj.set(Field, Arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void field_to_json(Poco::JSON::Object &Obj, const char *Field, const T &Value) {
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
Value.to_json(Answer);
|
||||||
|
Obj.set(Field, Answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
///////////////////////////
|
||||||
|
///////////////////////////
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
template<typename T> bool field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, T & V,
|
||||||
|
std::function<T(const std::string &)> F) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
V = F(Obj->get(Field).toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, std::string &S) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
S = Obj->get(Field).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, double & Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (double)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, float & Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (float)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, bool &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (Obj->get(Field).toString() == "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int16_t &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (int16_t)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int32_t &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (int32_t) Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, int64_t &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (int64_t)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint16_t &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (uint16_t)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint32_t &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (uint32_t)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, uint64_t &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field))
|
||||||
|
Value = (uint64_t)Obj->get(Field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Poco::Data::BLOB &Value) {
|
||||||
|
if(Obj->has(Field) && !Obj->isNull(Field)) {
|
||||||
|
auto Result = Utils::base64decode(Obj->get(Field).toString());
|
||||||
|
Value.assignRaw((const unsigned char *)&Result[0],Result.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringPairVec &Vec) {
|
||||||
|
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
|
||||||
|
auto O = Obj->getArray(Field);
|
||||||
|
for(const auto &i:*O) {
|
||||||
|
std::string S1,S2;
|
||||||
|
auto Inner = i.extract<Poco::JSON::Object::Ptr>();
|
||||||
|
if(Inner->has("tag"))
|
||||||
|
S1 = Inner->get("tag").toString();
|
||||||
|
if(Inner->has("value"))
|
||||||
|
S2 = Inner->get("value").toString();
|
||||||
|
auto P = std::make_pair(S1,S2);
|
||||||
|
Vec.push_back(P);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::StringVec &Value) {
|
||||||
|
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
|
||||||
|
Value.clear();
|
||||||
|
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
|
||||||
|
for(const auto &i:*A) {
|
||||||
|
Value.push_back(i.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, Types::TagList &Value) {
|
||||||
|
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
|
||||||
|
Value.clear();
|
||||||
|
Poco::JSON::Array::Ptr A = Obj->getArray(Field);
|
||||||
|
for(const auto &i:*A) {
|
||||||
|
Value.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, std::vector<T> &Value) {
|
||||||
|
if(Obj->isArray(Field) && !Obj->isNull(Field)) {
|
||||||
|
Poco::JSON::Array::Ptr Arr = Obj->getArray(Field);
|
||||||
|
for(auto &i:*Arr) {
|
||||||
|
auto InnerObj = i.extract<Poco::JSON::Object::Ptr>();
|
||||||
|
T NewItem;
|
||||||
|
NewItem.from_json(InnerObj);
|
||||||
|
Value.push_back(NewItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> void field_from_json(const Poco::JSON::Object::Ptr &Obj, const char *Field, T &Value) {
|
||||||
|
if(Obj->isObject(Field) && !Obj->isNull(Field)) {
|
||||||
|
Poco::JSON::Object::Ptr A = Obj->getObject(Field);
|
||||||
|
Value.from_json(A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_string(const Types::TagList & ObjectArray) {
|
||||||
|
Poco::JSON::Array OutputArr;
|
||||||
|
if(ObjectArray.empty())
|
||||||
|
return "[]";
|
||||||
|
for(auto const &i:ObjectArray) {
|
||||||
|
OutputArr.add(i);
|
||||||
|
}
|
||||||
|
std::ostringstream OS;
|
||||||
|
Poco::JSON::Stringifier::stringify(OutputArr,OS, 0,0, Poco::JSON_PRESERVE_KEY_ORDER );
|
||||||
|
return OS.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_string(const Types::StringVec & ObjectArray) {
|
||||||
|
Poco::JSON::Array OutputArr;
|
||||||
|
if(ObjectArray.empty())
|
||||||
|
return "[]";
|
||||||
|
for(auto const &i:ObjectArray) {
|
||||||
|
OutputArr.add(i);
|
||||||
|
}
|
||||||
|
std::ostringstream OS;
|
||||||
|
Poco::JSON::Stringifier::condense(OutputArr,OS);
|
||||||
|
return OS.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string to_string(const Types::StringPairVec & ObjectArray) {
|
||||||
|
Poco::JSON::Array OutputArr;
|
||||||
|
if(ObjectArray.empty())
|
||||||
|
return "[]";
|
||||||
|
for(auto const &i:ObjectArray) {
|
||||||
|
Poco::JSON::Array InnerArray;
|
||||||
|
InnerArray.add(i.first);
|
||||||
|
InnerArray.add(i.second);
|
||||||
|
OutputArr.add(InnerArray);
|
||||||
|
}
|
||||||
|
std::ostringstream OS;
|
||||||
|
Poco::JSON::Stringifier::condense(OutputArr,OS);
|
||||||
|
return OS.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> std::string to_string(const std::vector<T> & ObjectArray) {
|
||||||
|
Poco::JSON::Array OutputArr;
|
||||||
|
if(ObjectArray.empty())
|
||||||
|
return "[]";
|
||||||
|
for(auto const &i:ObjectArray) {
|
||||||
|
Poco::JSON::Object O;
|
||||||
|
i.to_json(O);
|
||||||
|
OutputArr.add(O);
|
||||||
|
}
|
||||||
|
std::ostringstream OS;
|
||||||
|
Poco::JSON::Stringifier::condense(OutputArr,OS);
|
||||||
|
return OS.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> std::string to_string(const std::vector<std::vector<T>> & ObjectArray) {
|
||||||
|
Poco::JSON::Array OutputArr;
|
||||||
|
if(ObjectArray.empty())
|
||||||
|
return "[]";
|
||||||
|
for(auto const &i:ObjectArray) {
|
||||||
|
Poco::JSON::Array InnerArr;
|
||||||
|
for(auto const &j:i) {
|
||||||
|
if constexpr(std::is_integral<T>::value) {
|
||||||
|
InnerArr.add(j);
|
||||||
|
} if constexpr(std::is_same_v<T,std::string>) {
|
||||||
|
InnerArr.add(j);
|
||||||
|
} else {
|
||||||
|
InnerArr.add(j);
|
||||||
|
Poco::JSON::Object O;
|
||||||
|
j.to_json(O);
|
||||||
|
InnerArr.add(O);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputArr.add(InnerArr);
|
||||||
|
}
|
||||||
|
std::ostringstream OS;
|
||||||
|
Poco::JSON::Stringifier::condense(OutputArr,OS);
|
||||||
|
return OS.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> std::string to_string(const T & Object) {
|
||||||
|
Poco::JSON::Object OutputObj;
|
||||||
|
Object.to_json(OutputObj);
|
||||||
|
std::ostringstream OS;
|
||||||
|
Poco::JSON::Stringifier::condense(OutputObj,OS);
|
||||||
|
return OS.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Types::StringVec to_object_array(const std::string & ObjectString) {
|
||||||
|
|
||||||
|
Types::StringVec Result;
|
||||||
|
if(ObjectString.empty())
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
for (auto const &i : *Object) {
|
||||||
|
Result.push_back(i.toString());
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline OpenWifi::Types::TagList to_taglist(const std::string & ObjectString) {
|
||||||
|
Types::TagList Result;
|
||||||
|
if(ObjectString.empty())
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
for (auto const &i : *Object) {
|
||||||
|
Result.push_back(i);
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Types::StringPairVec to_stringpair_array(const std::string &S) {
|
||||||
|
Types::StringPairVec R;
|
||||||
|
if(S.empty())
|
||||||
|
return R;
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto Object = P.parse(S).template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
for (const auto &i : *Object) {
|
||||||
|
auto InnerObject = i.template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
if(InnerObject->size()==2) {
|
||||||
|
auto S1 = InnerObject->getElement<std::string>(0);
|
||||||
|
auto S2 = InnerObject->getElement<std::string>(1);
|
||||||
|
R.push_back(std::make_pair(S1,S2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> std::vector<T> to_object_array(const std::string & ObjectString) {
|
||||||
|
std::vector<T> Result;
|
||||||
|
if(ObjectString.empty())
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
for (auto const &i : *Object) {
|
||||||
|
auto InnerObject = i.template extract<Poco::JSON::Object::Ptr>();
|
||||||
|
T Obj;
|
||||||
|
Obj.from_json(InnerObject);
|
||||||
|
Result.push_back(Obj);
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> std::vector<std::vector<T>> to_array_of_array_of_object(const std::string & ObjectString) {
|
||||||
|
std::vector<std::vector<T>> Result;
|
||||||
|
if(ObjectString.empty())
|
||||||
|
return Result;
|
||||||
|
try {
|
||||||
|
Poco::JSON::Parser P1;
|
||||||
|
auto OutterArray = P1.parse(ObjectString).template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
for (auto const &i : *OutterArray) {
|
||||||
|
Poco::JSON::Parser P2;
|
||||||
|
auto InnerArray = P2.parse(i).template extract<Poco::JSON::Array::Ptr>();
|
||||||
|
std::vector<T> InnerVector;
|
||||||
|
for(auto const &j: *InnerArray) {
|
||||||
|
auto Object = j.template extract<Poco::JSON::Object::Ptr>();
|
||||||
|
T Obj;
|
||||||
|
Obj.from_json(Object);
|
||||||
|
InnerVector.push_back(Obj);
|
||||||
|
}
|
||||||
|
Result.push_back(InnerVector);
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> T to_object(const std::string & ObjectString) {
|
||||||
|
T Result;
|
||||||
|
|
||||||
|
if(ObjectString.empty())
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
Poco::JSON::Parser P;
|
||||||
|
auto Object = P.parse(ObjectString).template extract<Poco::JSON::Object::Ptr>();
|
||||||
|
Result.from_json(Object);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T> bool from_request(T & Obj, Poco::Net::HTTPServerRequest &Request) {
|
||||||
|
Poco::JSON::Parser IncomingParser;
|
||||||
|
auto RawObject = IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||||
|
Obj.from_json(RawObject);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
#include "Poco/Data/MySQL/Connector.h"
|
#include "Poco/Data/MySQL/Connector.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "framework/MicroService.h"
|
#include "framework/SubSystemServer.h"
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
enum DBType {
|
enum DBType {
|
||||||
@@ -34,7 +35,7 @@ namespace OpenWifi {
|
|||||||
std::lock_guard Guard(Mutex_);
|
std::lock_guard Guard(Mutex_);
|
||||||
|
|
||||||
Logger().notice("Starting.");
|
Logger().notice("Starting.");
|
||||||
std::string DBType = MicroService::instance().ConfigGetString("storage.type");
|
std::string DBType = MicroServiceConfigGetString("storage.type","");
|
||||||
|
|
||||||
if (DBType == "sqlite") {
|
if (DBType == "sqlite") {
|
||||||
Setup_SQLite();
|
Setup_SQLite();
|
||||||
@@ -72,9 +73,9 @@ namespace OpenWifi {
|
|||||||
inline int StorageClass::Setup_SQLite() {
|
inline int StorageClass::Setup_SQLite() {
|
||||||
Logger().notice("SQLite StorageClass enabled.");
|
Logger().notice("SQLite StorageClass enabled.");
|
||||||
dbType_ = sqlite;
|
dbType_ = sqlite;
|
||||||
auto DBName = MicroService::instance().DataDir() + "/" + MicroService::instance().ConfigGetString("storage.type.sqlite.db");
|
auto DBName = MicroServiceDataDirectory() + "/" + MicroServiceConfigGetString("storage.type.sqlite.db","");
|
||||||
int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.maxsessions", 64);
|
int NumSessions = (int) MicroServiceConfigGetInt("storage.type.sqlite.maxsessions", 64);
|
||||||
int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.sqlite.idletime", 60);
|
int IdleTime = (int) MicroServiceConfigGetInt("storage.type.sqlite.idletime", 60);
|
||||||
|
|
||||||
Poco::Data::SQLite::Connector::registerConnector();
|
Poco::Data::SQLite::Connector::registerConnector();
|
||||||
// Pool_ = std::make_unique<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
|
// Pool_ = std::make_unique<Poco::Data::SessionPool>(new Poco::Data::SessionPool(SQLiteConn_.name(), DBName, 8,
|
||||||
@@ -87,13 +88,13 @@ namespace OpenWifi {
|
|||||||
inline int StorageClass::Setup_MySQL() {
|
inline int StorageClass::Setup_MySQL() {
|
||||||
Logger().notice("MySQL StorageClass enabled.");
|
Logger().notice("MySQL StorageClass enabled.");
|
||||||
dbType_ = mysql;
|
dbType_ = mysql;
|
||||||
int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.maxsessions", 64);
|
int NumSessions = (int) MicroServiceConfigGetInt("storage.type.mysql.maxsessions", 64);
|
||||||
int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.mysql.idletime", 60);
|
int IdleTime = (int) MicroServiceConfigGetInt("storage.type.mysql.idletime", 60);
|
||||||
auto Host = MicroService::instance().ConfigGetString("storage.type.mysql.host");
|
auto Host = MicroServiceConfigGetString("storage.type.mysql.host","");
|
||||||
auto Username = MicroService::instance().ConfigGetString("storage.type.mysql.username");
|
auto Username = MicroServiceConfigGetString("storage.type.mysql.username","");
|
||||||
auto Password = MicroService::instance().ConfigGetString("storage.type.mysql.password");
|
auto Password = MicroServiceConfigGetString("storage.type.mysql.password","");
|
||||||
auto Database = MicroService::instance().ConfigGetString("storage.type.mysql.database");
|
auto Database = MicroServiceConfigGetString("storage.type.mysql.database","");
|
||||||
auto Port = MicroService::instance().ConfigGetString("storage.type.mysql.port");
|
auto Port = MicroServiceConfigGetString("storage.type.mysql.port","");
|
||||||
|
|
||||||
std::string ConnectionStr =
|
std::string ConnectionStr =
|
||||||
"host=" + Host +
|
"host=" + Host +
|
||||||
@@ -112,14 +113,14 @@ namespace OpenWifi {
|
|||||||
inline int StorageClass::Setup_PostgreSQL() {
|
inline int StorageClass::Setup_PostgreSQL() {
|
||||||
Logger().notice("PostgreSQL StorageClass enabled.");
|
Logger().notice("PostgreSQL StorageClass enabled.");
|
||||||
dbType_ = pgsql;
|
dbType_ = pgsql;
|
||||||
int NumSessions = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.maxsessions", 64);
|
int NumSessions = (int) MicroServiceConfigGetInt("storage.type.postgresql.maxsessions", 64);
|
||||||
int IdleTime = (int) MicroService::instance().ConfigGetInt("storage.type.postgresql.idletime", 60);
|
int IdleTime = (int) MicroServiceConfigGetInt("storage.type.postgresql.idletime", 60);
|
||||||
auto Host = MicroService::instance().ConfigGetString("storage.type.postgresql.host");
|
auto Host = MicroServiceConfigGetString("storage.type.postgresql.host", "");
|
||||||
auto Username = MicroService::instance().ConfigGetString("storage.type.postgresql.username");
|
auto Username = MicroServiceConfigGetString("storage.type.postgresql.username", "");
|
||||||
auto Password = MicroService::instance().ConfigGetString("storage.type.postgresql.password");
|
auto Password = MicroServiceConfigGetString("storage.type.postgresql.password", "");
|
||||||
auto Database = MicroService::instance().ConfigGetString("storage.type.postgresql.database");
|
auto Database = MicroServiceConfigGetString("storage.type.postgresql.database", "");
|
||||||
auto Port = MicroService::instance().ConfigGetString("storage.type.postgresql.port");
|
auto Port = MicroServiceConfigGetString("storage.type.postgresql.port", "");
|
||||||
auto ConnectionTimeout = MicroService::instance().ConfigGetString("storage.type.postgresql.connectiontimeout");
|
auto ConnectionTimeout = MicroServiceConfigGetString("storage.type.postgresql.connectiontimeout", "");
|
||||||
|
|
||||||
std::string ConnectionStr =
|
std::string ConnectionStr =
|
||||||
"host=" + Host +
|
"host=" + Host +
|
||||||
|
|||||||
320
src/framework/SubSystemServer.cpp
Normal file
320
src/framework/SubSystemServer.cpp
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "fmt/format.h"
|
||||||
|
|
||||||
|
#include "framework/SubSystemServer.h"
|
||||||
|
|
||||||
|
#include "Poco/Net/SSLManager.h"
|
||||||
|
#include "Poco/DateTimeFormatter.h"
|
||||||
|
#include "Poco/DateTimeFormat.h"
|
||||||
|
|
||||||
|
#include "framework/MicroServiceFuncs.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
|
||||||
|
PropertiesFileServerEntry::PropertiesFileServerEntry(std::string Address, uint32_t port, std::string Key_file,
|
||||||
|
std::string Cert_file, std::string RootCa, std::string Issuer,
|
||||||
|
std::string ClientCas, std::string Cas,
|
||||||
|
std::string Key_file_password, std::string Name,
|
||||||
|
Poco::Net::Context::VerificationMode M,
|
||||||
|
int backlog)
|
||||||
|
: address_(std::move(Address)),
|
||||||
|
port_(port),
|
||||||
|
cert_file_(std::move(Cert_file)),
|
||||||
|
key_file_(std::move(Key_file)),
|
||||||
|
root_ca_(std::move(RootCa)),
|
||||||
|
key_file_password_(std::move(Key_file_password)),
|
||||||
|
issuer_cert_file_(std::move(Issuer)),
|
||||||
|
client_cas_(std::move(ClientCas)),
|
||||||
|
cas_(std::move(Cas)),
|
||||||
|
name_(std::move(Name)),
|
||||||
|
backlog_(backlog),
|
||||||
|
level_(M) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] Poco::Net::SecureServerSocket PropertiesFileServerEntry::CreateSecureSocket(Poco::Logger &L) const {
|
||||||
|
Poco::Net::Context::Params P;
|
||||||
|
|
||||||
|
P.verificationMode = level_;
|
||||||
|
P.verificationDepth = 9;
|
||||||
|
P.loadDefaultCAs = root_ca_.empty();
|
||||||
|
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||||
|
P.dhUse2048Bits = true;
|
||||||
|
P.caLocation = cas_;
|
||||||
|
|
||||||
|
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||||
|
|
||||||
|
if(!key_file_password_.empty()) {
|
||||||
|
auto PassphraseHandler = Poco::SharedPtr<MyPrivateKeyPassphraseHandler>( new MyPrivateKeyPassphraseHandler(key_file_password_,L));
|
||||||
|
Poco::Net::SSLManager::instance().initializeServer(PassphraseHandler, nullptr,Context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cert_file_.empty() && !key_file_.empty()) {
|
||||||
|
Poco::Crypto::X509Certificate Cert(cert_file_);
|
||||||
|
Poco::Crypto::X509Certificate Root(root_ca_);
|
||||||
|
|
||||||
|
Context->useCertificate(Cert);
|
||||||
|
Context->addChainCertificate(Root);
|
||||||
|
|
||||||
|
Context->addCertificateAuthority(Root);
|
||||||
|
|
||||||
|
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
|
||||||
|
if (issuer_cert_file_.empty()) {
|
||||||
|
L.fatal("In strict mode, you must supply ans issuer certificate");
|
||||||
|
}
|
||||||
|
if (client_cas_.empty()) {
|
||||||
|
L.fatal("In strict mode, client cas must be supplied");
|
||||||
|
}
|
||||||
|
Poco::Crypto::X509Certificate Issuing(issuer_cert_file_);
|
||||||
|
Context->addChainCertificate(Issuing);
|
||||||
|
Context->addCertificateAuthority(Issuing);
|
||||||
|
}
|
||||||
|
|
||||||
|
Poco::Crypto::RSAKey Key("", key_file_, key_file_password_);
|
||||||
|
Context->usePrivateKey(Key);
|
||||||
|
|
||||||
|
SSL_CTX *SSLCtx = Context->sslContext();
|
||||||
|
if (!SSL_CTX_check_private_key(SSLCtx)) {
|
||||||
|
L.fatal(fmt::format("Wrong Certificate({}) for Key({})", cert_file_, key_file_));
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_CTX_set_verify(SSLCtx, SSL_VERIFY_PEER, nullptr);
|
||||||
|
|
||||||
|
if (level_ == Poco::Net::Context::VERIFY_STRICT) {
|
||||||
|
SSL_CTX_set_client_CA_list(SSLCtx, SSL_load_client_CA_file(client_cas_.c_str()));
|
||||||
|
}
|
||||||
|
SSL_CTX_enable_ct(SSLCtx, SSL_CT_VALIDATION_STRICT);
|
||||||
|
SSL_CTX_dane_enable(SSLCtx);
|
||||||
|
|
||||||
|
Context->enableSessionCache();
|
||||||
|
Context->setSessionCacheSize(0);
|
||||||
|
Context->setSessionTimeout(60);
|
||||||
|
Context->enableExtendedCertificateVerification(true);
|
||||||
|
Context->disableStatelessSessionResumption();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address_ == "*") {
|
||||||
|
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_);
|
||||||
|
|
||||||
|
return Poco::Net::SecureServerSocket(SockAddr, backlog_, Context);
|
||||||
|
} else {
|
||||||
|
Poco::Net::IPAddress Addr(address_);
|
||||||
|
Poco::Net::SocketAddress SockAddr(Addr, port_);
|
||||||
|
|
||||||
|
return Poco::Net::SecureServerSocket(SockAddr, backlog_, Context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Poco::Net::ServerSocket PropertiesFileServerEntry::CreateSocket([[maybe_unused]] Poco::Logger &L) const {
|
||||||
|
Poco::Net::Context::Params P;
|
||||||
|
|
||||||
|
if (address_ == "*") {
|
||||||
|
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_);
|
||||||
|
return Poco::Net::ServerSocket(SockAddr, backlog_);
|
||||||
|
} else {
|
||||||
|
Poco::Net::IPAddress Addr(address_);
|
||||||
|
Poco::Net::SocketAddress SockAddr(Addr, port_);
|
||||||
|
return Poco::Net::ServerSocket(SockAddr, backlog_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertiesFileServerEntry::LogCertInfo(Poco::Logger &L, const Poco::Crypto::X509Certificate &C) const {
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information(fmt::format("> Issuer: {}", C.issuerName()));
|
||||||
|
L.information("---------------------------------------------------------------------------------------------");
|
||||||
|
L.information(fmt::format("> Common Name: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_COMMON_NAME)));
|
||||||
|
L.information(fmt::format("> Country: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_COUNTRY)));
|
||||||
|
L.information(fmt::format("> Locality: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME)));
|
||||||
|
L.information(fmt::format("> State/Prov: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE)));
|
||||||
|
L.information(fmt::format("> Org name: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME)));
|
||||||
|
L.information(
|
||||||
|
fmt::format("> Org unit: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME)));
|
||||||
|
L.information(
|
||||||
|
fmt::format("> Email: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS)));
|
||||||
|
L.information(fmt::format("> Serial#: {}",
|
||||||
|
C.issuerName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER)));
|
||||||
|
L.information("---------------------------------------------------------------------------------------------");
|
||||||
|
L.information(fmt::format("> Subject: {}", C.subjectName()));
|
||||||
|
L.information("---------------------------------------------------------------------------------------------");
|
||||||
|
L.information(fmt::format("> Common Name: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_COMMON_NAME)));
|
||||||
|
L.information(fmt::format("> Country: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_COUNTRY)));
|
||||||
|
L.information(fmt::format("> Locality: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_LOCALITY_NAME)));
|
||||||
|
L.information(
|
||||||
|
fmt::format("> State/Prov: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_STATE_OR_PROVINCE)));
|
||||||
|
L.information(
|
||||||
|
fmt::format("> Org name: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_NAME)));
|
||||||
|
L.information(
|
||||||
|
fmt::format("> Org unit: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_ORGANIZATION_UNIT_NAME)));
|
||||||
|
L.information(
|
||||||
|
fmt::format("> Email: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_PKCS9_EMAIL_ADDRESS)));
|
||||||
|
L.information(fmt::format("> Serial#: {}",
|
||||||
|
C.subjectName(Poco::Crypto::X509Certificate::NID_SERIAL_NUMBER)));
|
||||||
|
L.information("---------------------------------------------------------------------------------------------");
|
||||||
|
L.information(fmt::format("> Signature Algo: {}", C.signatureAlgorithm()));
|
||||||
|
auto From = Poco::DateTimeFormatter::format(C.validFrom(), Poco::DateTimeFormat::HTTP_FORMAT);
|
||||||
|
L.information(fmt::format("> Valid from: {}", From));
|
||||||
|
auto Expires =
|
||||||
|
Poco::DateTimeFormatter::format(C.expiresOn(), Poco::DateTimeFormat::HTTP_FORMAT);
|
||||||
|
L.information(fmt::format("> Expires on: {}", Expires));
|
||||||
|
L.information(fmt::format("> Version: {}", (int)C.version()));
|
||||||
|
L.information(fmt::format("> Serial #: {}", C.serialNumber()));
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertiesFileServerEntry::LogCert(Poco::Logger &L) const {
|
||||||
|
try {
|
||||||
|
Poco::Crypto::X509Certificate C(cert_file_);
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information(fmt::format("Certificate Filename: {}", cert_file_));
|
||||||
|
LogCertInfo(L, C);
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
|
||||||
|
if (!issuer_cert_file_.empty()) {
|
||||||
|
Poco::Crypto::X509Certificate C1(issuer_cert_file_);
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information(fmt::format("Issues Certificate Filename: {}", issuer_cert_file_));
|
||||||
|
LogCertInfo(L, C1);
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!client_cas_.empty()) {
|
||||||
|
std::vector<Poco::Crypto::X509Certificate> Certs =
|
||||||
|
Poco::Net::X509Certificate::readPEM(client_cas_);
|
||||||
|
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information(fmt::format("Client CAs Filename: {}", client_cas_));
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
auto i = 1;
|
||||||
|
for (const auto &C3 : Certs) {
|
||||||
|
L.information(fmt::format(" Index: {}", i));
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
LogCertInfo(L, C3);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (const Poco::Exception &E) {
|
||||||
|
L.log(E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertiesFileServerEntry::LogCas(Poco::Logger &L) const {
|
||||||
|
try {
|
||||||
|
std::vector<Poco::Crypto::X509Certificate> Certs =
|
||||||
|
Poco::Net::X509Certificate::readPEM(root_ca_);
|
||||||
|
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
L.information(fmt::format("CA Filename: {}", root_ca_));
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
auto i = 1;
|
||||||
|
for (const auto &C : Certs) {
|
||||||
|
L.information(fmt::format(" Index: {}", i));
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
LogCertInfo(L, C);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
L.information("=============================================================================================");
|
||||||
|
} catch (const Poco::Exception &E) {
|
||||||
|
L.log(E);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SubSystemServer::SubSystemServer(const std::string &Name, const std::string &LoggingPrefix,
|
||||||
|
const std::string &SubSystemConfigPrefix):
|
||||||
|
Name_(Name),
|
||||||
|
LoggerPrefix_(LoggingPrefix),
|
||||||
|
SubSystemConfigPrefix_(SubSystemConfigPrefix) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubSystemServer::initialize([[maybe_unused]] Poco::Util::Application &self) {
|
||||||
|
auto i = 0;
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
auto NewLevel = MicroServiceConfigGetString("logging.level." + Name_, "");
|
||||||
|
if(NewLevel.empty())
|
||||||
|
Logger_ = std::make_unique<LoggerWrapper>(Poco::Logger::create(LoggerPrefix_, Poco::Logger::root().getChannel(), Poco::Logger::root().getLevel()));
|
||||||
|
else
|
||||||
|
Logger_ = std::make_unique<LoggerWrapper>(Poco::Logger::create(LoggerPrefix_, Poco::Logger::root().getChannel(), Poco::Logger::parseLevel(NewLevel)));
|
||||||
|
|
||||||
|
ConfigServersList_.clear();
|
||||||
|
while (good) {
|
||||||
|
std::string root{SubSystemConfigPrefix_ + ".host." + std::to_string(i) + "."};
|
||||||
|
|
||||||
|
std::string address{root + "address"};
|
||||||
|
if (MicroServiceConfigGetString(address, "").empty()) {
|
||||||
|
good = false;
|
||||||
|
} else {
|
||||||
|
std::string port{root + "port"};
|
||||||
|
std::string key{root + "key"};
|
||||||
|
std::string key_password{root + "key.password"};
|
||||||
|
std::string cert{root + "cert"};
|
||||||
|
std::string name{root + "name"};
|
||||||
|
std::string backlog{root + "backlog"};
|
||||||
|
std::string rootca{root + "rootca"};
|
||||||
|
std::string issuer{root + "issuer"};
|
||||||
|
std::string clientcas(root + "clientcas");
|
||||||
|
std::string cas{root + "cas"};
|
||||||
|
|
||||||
|
std::string level{root + "security"};
|
||||||
|
Poco::Net::Context::VerificationMode M = Poco::Net::Context::VERIFY_RELAXED;
|
||||||
|
|
||||||
|
auto L = MicroServiceConfigGetString(level, "");
|
||||||
|
|
||||||
|
if (L == "strict") {
|
||||||
|
M = Poco::Net::Context::VERIFY_STRICT;
|
||||||
|
} else if (L == "none") {
|
||||||
|
M = Poco::Net::Context::VERIFY_NONE;
|
||||||
|
} else if (L == "relaxed") {
|
||||||
|
M = Poco::Net::Context::VERIFY_RELAXED;
|
||||||
|
} else if (L == "once")
|
||||||
|
M = Poco::Net::Context::VERIFY_ONCE;
|
||||||
|
|
||||||
|
PropertiesFileServerEntry entry(MicroServiceConfigGetString(address, ""),
|
||||||
|
MicroServiceConfigGetInt(port, 0),
|
||||||
|
MicroServiceConfigPath(key, ""),
|
||||||
|
MicroServiceConfigPath(cert, ""),
|
||||||
|
MicroServiceConfigPath(rootca, ""),
|
||||||
|
MicroServiceConfigPath(issuer, ""),
|
||||||
|
MicroServiceConfigPath(clientcas, ""),
|
||||||
|
MicroServiceConfigPath(cas, ""),
|
||||||
|
MicroServiceConfigGetString(key_password, ""),
|
||||||
|
MicroServiceConfigGetString(name, ""), M,
|
||||||
|
(int)MicroServiceConfigGetInt(backlog, 64));
|
||||||
|
ConfigServersList_.push_back(entry);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace OpenWifi
|
||||||
124
src/framework/SubSystemServer.h
Normal file
124
src/framework/SubSystemServer.h
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2022-10-25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "Poco/Util/Application.h"
|
||||||
|
#include "Poco/Net/Context.h"
|
||||||
|
#include "Poco/Net/SecureServerSocket.h"
|
||||||
|
#include "Poco/Net/PrivateKeyPassphraseHandler.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
|
||||||
|
class MyPrivateKeyPassphraseHandler : public Poco::Net::PrivateKeyPassphraseHandler {
|
||||||
|
public:
|
||||||
|
explicit MyPrivateKeyPassphraseHandler(const std::string &Password, Poco::Logger & Logger):
|
||||||
|
PrivateKeyPassphraseHandler(true),
|
||||||
|
Password_(Password),
|
||||||
|
Logger_(Logger) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPrivateKeyRequested([[maybe_unused]] const void * pSender,std::string & privateKey) {
|
||||||
|
poco_information(Logger_,"Returning key passphrase.");
|
||||||
|
privateKey = Password_;
|
||||||
|
};
|
||||||
|
inline Poco::Logger & Logger() { return Logger_; }
|
||||||
|
private:
|
||||||
|
std::string Password_;
|
||||||
|
Poco::Logger & Logger_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PropertiesFileServerEntry {
|
||||||
|
public:
|
||||||
|
PropertiesFileServerEntry(std::string Address, uint32_t port, std::string Key_file,
|
||||||
|
std::string Cert_file, std::string RootCa, std::string Issuer,
|
||||||
|
std::string ClientCas, std::string Cas,
|
||||||
|
std::string Key_file_password = "", std::string Name = "",
|
||||||
|
Poco::Net::Context::VerificationMode M =
|
||||||
|
Poco::Net::Context::VerificationMode::VERIFY_RELAXED,
|
||||||
|
int backlog = 64);
|
||||||
|
|
||||||
|
[[nodiscard]] inline const std::string &Address() const { return address_; };
|
||||||
|
[[nodiscard]] inline uint32_t Port() const { return port_; };
|
||||||
|
[[nodiscard]] inline auto KeyFile() const { return key_file_; };
|
||||||
|
[[nodiscard]] inline auto CertFile() const { return cert_file_; };
|
||||||
|
[[nodiscard]] inline auto RootCA() const { return root_ca_; };
|
||||||
|
[[nodiscard]] inline auto KeyFilePassword() const { return key_file_password_; };
|
||||||
|
[[nodiscard]] inline auto IssuerCertFile() const { return issuer_cert_file_; };
|
||||||
|
[[nodiscard]] inline auto Name() const { return name_; };
|
||||||
|
[[nodiscard]] inline int Backlog() const { return backlog_; }
|
||||||
|
[[nodiscard]] inline auto Cas() const { return cas_; }
|
||||||
|
|
||||||
|
[[nodiscard]] Poco::Net::SecureServerSocket CreateSecureSocket(Poco::Logger &L) const;
|
||||||
|
[[nodiscard]] Poco::Net::ServerSocket CreateSocket([[maybe_unused]] Poco::Logger &L) const;
|
||||||
|
void LogCertInfo(Poco::Logger &L, const Poco::Crypto::X509Certificate &C) const;
|
||||||
|
void LogCert(Poco::Logger &L) const;
|
||||||
|
void LogCas(Poco::Logger &L) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string address_;
|
||||||
|
uint32_t port_;
|
||||||
|
std::string cert_file_;
|
||||||
|
std::string key_file_;
|
||||||
|
std::string root_ca_;
|
||||||
|
std::string key_file_password_;
|
||||||
|
std::string issuer_cert_file_;
|
||||||
|
std::string client_cas_;
|
||||||
|
std::string cas_;
|
||||||
|
std::string name_;
|
||||||
|
int backlog_;
|
||||||
|
Poco::Net::Context::VerificationMode level_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SubSystemServer : public Poco::Util::Application::Subsystem {
|
||||||
|
public:
|
||||||
|
SubSystemServer(const std::string & Name, const std::string &LoggingPrefix,
|
||||||
|
const std::string & SubSystemConfigPrefix);
|
||||||
|
|
||||||
|
void initialize(Poco::Util::Application &self) override;
|
||||||
|
inline void uninitialize() override {
|
||||||
|
}
|
||||||
|
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
|
||||||
|
poco_information(Logger_->L_,"Reloading of this subsystem is not supported.");
|
||||||
|
}
|
||||||
|
inline void defineOptions([[maybe_unused]] Poco::Util::OptionSet &options) override {
|
||||||
|
}
|
||||||
|
inline const std::string & Name() const { return Name_; };
|
||||||
|
inline const char * name() const override { return Name_.c_str(); }
|
||||||
|
|
||||||
|
inline const PropertiesFileServerEntry & Host(uint64_t index) { return ConfigServersList_[index]; };
|
||||||
|
inline uint64_t HostSize() const { return ConfigServersList_.size(); }
|
||||||
|
inline Poco::Logger & Logger() const { return Logger_->L_; }
|
||||||
|
inline void SetLoggingLevel(const std::string & levelName) {
|
||||||
|
Logger_->L_.setLevel(Poco::Logger::parseLevel(levelName));
|
||||||
|
}
|
||||||
|
inline int GetLoggingLevel() { return Logger_->L_.getLevel(); }
|
||||||
|
|
||||||
|
virtual int Start() = 0;
|
||||||
|
virtual void Stop() = 0;
|
||||||
|
|
||||||
|
struct LoggerWrapper {
|
||||||
|
Poco::Logger & L_;
|
||||||
|
LoggerWrapper(Poco::Logger &L) :
|
||||||
|
L_(L) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::recursive_mutex Mutex_;
|
||||||
|
std::vector<PropertiesFileServerEntry> ConfigServersList_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<LoggerWrapper> Logger_;
|
||||||
|
std::string Name_;
|
||||||
|
std::string LoggerPrefix_;
|
||||||
|
std::string SubSystemConfigPrefix_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<SubSystemServer *> SubSystemVec;
|
||||||
|
|
||||||
|
} // 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