mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralgw.git
synced 2026-03-20 03:41:02 +00:00
Compare commits
335 Commits
v2.0.0
...
release/v2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d938c26329 | ||
|
|
6dd1ee63a0 | ||
|
|
a28904ba62 | ||
|
|
bc4bcd7a5c | ||
|
|
01cc10bd63 | ||
|
|
2961b7bb42 | ||
|
|
ee2df31e51 | ||
|
|
2717ed9d23 | ||
|
|
942e99cf41 | ||
|
|
7340abf40e | ||
|
|
1d1d744d67 | ||
|
|
8656cac16e | ||
|
|
d9552b3971 | ||
|
|
1685224cba | ||
|
|
1ab94d0b78 | ||
|
|
35cc18b1dc | ||
|
|
35fbf1d5ca | ||
|
|
d29876f948 | ||
|
|
d8b4d4a173 | ||
|
|
ff577f2aa3 | ||
|
|
6b871a27e2 | ||
|
|
b4b2707f3f | ||
|
|
153477b649 | ||
|
|
f73389af3c | ||
|
|
eb361cad14 | ||
|
|
0e7dcf88a3 | ||
|
|
7726c8b346 | ||
|
|
b3a0593f8e | ||
|
|
cd047f8d38 | ||
|
|
96b09eacc3 | ||
|
|
cafb26e13d | ||
|
|
007d034a54 | ||
|
|
6d578193b6 | ||
|
|
0d63f9882d | ||
|
|
1ea2542a00 | ||
|
|
87054cfaa3 | ||
|
|
b4fd04ef9c | ||
|
|
0e1bd681d8 | ||
|
|
3919c95250 | ||
|
|
e85e00a5db | ||
|
|
1ef2a62b06 | ||
|
|
95ce12fabc | ||
|
|
408183eada | ||
|
|
b7d42c76dc | ||
|
|
7ee0aa57a9 | ||
|
|
51dd6dbc13 | ||
|
|
7f4e6303c7 | ||
|
|
3b59a36012 | ||
|
|
3ca43225ae | ||
|
|
119638f108 | ||
|
|
dd8265c1c7 | ||
|
|
f2f413dbfe | ||
|
|
271d97e152 | ||
|
|
cda780bbca | ||
|
|
a739f1e48c | ||
|
|
7881e4297b | ||
|
|
0fa0af3159 | ||
|
|
3ea4e5a641 | ||
|
|
75fda33eaf | ||
|
|
1d9e30ab0f | ||
|
|
771ea62a3e | ||
|
|
c89bee14c0 | ||
|
|
f9e52526b4 | ||
|
|
ed7ecc0eff | ||
|
|
79128169c2 | ||
|
|
557538e30d | ||
|
|
5d5bdd99d8 | ||
|
|
d1b2524632 | ||
|
|
2eb3238cdc | ||
|
|
b7bc615d05 | ||
|
|
222f7df0e4 | ||
|
|
c93459bf18 | ||
|
|
8d2173a046 | ||
|
|
efd8b81625 | ||
|
|
24163b5fce | ||
|
|
f50ce2f816 | ||
|
|
cc4ba61c15 | ||
|
|
bbc0255ad4 | ||
|
|
1e0628abf4 | ||
|
|
5d8e9355b1 | ||
|
|
3eaedf4752 | ||
|
|
da38f204b6 | ||
|
|
ab29614b99 | ||
|
|
881015331c | ||
|
|
16ce257dc5 | ||
|
|
8b63e5a873 | ||
|
|
3b690b1878 | ||
|
|
c9157f1df4 | ||
|
|
d5f6c7a976 | ||
|
|
c9528b7c1d | ||
|
|
cf1b5c019f | ||
|
|
ee075fff67 | ||
|
|
348f30a05f | ||
|
|
c0930929d9 | ||
|
|
cbd2b3ccb9 | ||
|
|
c53d98282a | ||
|
|
871063e029 | ||
|
|
94c6f89f4a | ||
|
|
24f1561847 | ||
|
|
61472453a1 | ||
|
|
4031c94fb9 | ||
|
|
25079004b8 | ||
|
|
61f89fb005 | ||
|
|
5b51a097b2 | ||
|
|
417b82ce70 | ||
|
|
6ca66e313f | ||
|
|
45a7d5066e | ||
|
|
000a01ab09 | ||
|
|
fca3fcf6a8 | ||
|
|
f3ff04c185 | ||
|
|
5d96d5f572 | ||
|
|
7fc45c160e | ||
|
|
83c1bb305b | ||
|
|
63ac9d2c72 | ||
|
|
0ee5c56d33 | ||
|
|
f6cd8bd73e | ||
|
|
d49b89b775 | ||
|
|
7183767a50 | ||
|
|
b38c657a27 | ||
|
|
2ea8fdf57f | ||
|
|
b8d5b86b3e | ||
|
|
0aa5837ea2 | ||
|
|
187f1669cf | ||
|
|
faebf38a3f | ||
|
|
488d5d0a24 | ||
|
|
461094d883 | ||
|
|
bf00fa34f4 | ||
|
|
2d283ffd32 | ||
|
|
5ec8523b46 | ||
|
|
a78c2f6961 | ||
|
|
14f2ea79e1 | ||
|
|
fcb3f2efbc | ||
|
|
2061a3a699 | ||
|
|
8e4c528da5 | ||
|
|
8277f8dd92 | ||
|
|
6a1f844631 | ||
|
|
0ba02f1c70 | ||
|
|
79e0304841 | ||
|
|
5fa7a2d766 | ||
|
|
1d1caa7270 | ||
|
|
d740167972 | ||
|
|
bf93257343 | ||
|
|
2286a9063f | ||
|
|
1e35473b82 | ||
|
|
17f0dc4de9 | ||
|
|
8c21b86d5c | ||
|
|
f6780d545d | ||
|
|
6a63a252d5 | ||
|
|
51f8bd7342 | ||
|
|
c0d199a12e | ||
|
|
06a997c6cb | ||
|
|
c2ead350aa | ||
|
|
9941b9a15c | ||
|
|
ef58d30ae3 | ||
|
|
aa6e4e6350 | ||
|
|
6e03253aac | ||
|
|
79c37e3e71 | ||
|
|
44fca56806 | ||
|
|
7d0571269a | ||
|
|
0734e93b7c | ||
|
|
5986d34e24 | ||
|
|
0edd85e991 | ||
|
|
1d4995641b | ||
|
|
3be56ada41 | ||
|
|
a1160f7de5 | ||
|
|
17971d1dd0 | ||
|
|
7a762ab3f2 | ||
|
|
1a9ddd2df9 | ||
|
|
f3ae6de093 | ||
|
|
219e8fc59e | ||
|
|
389fcb9f3b | ||
|
|
e40abd2a91 | ||
|
|
ee11dc8d91 | ||
|
|
a9ec2e7821 | ||
|
|
b6b1c99c86 | ||
|
|
31f96968b2 | ||
|
|
1e845a6ff2 | ||
|
|
0e9ddee588 | ||
|
|
6e167372b5 | ||
|
|
1e1f0c37e9 | ||
|
|
4cf10b0f3a | ||
|
|
314fef87e2 | ||
|
|
e4e2075021 | ||
|
|
314ae21d6a | ||
|
|
8ad0da5781 | ||
|
|
935cc78bb4 | ||
|
|
5bc7508d96 | ||
|
|
498e8f880c | ||
|
|
e9e5d8be41 | ||
|
|
319e8918b1 | ||
|
|
7892489e96 | ||
|
|
24785e2f63 | ||
|
|
52736f4a4c | ||
|
|
e7334122b5 | ||
|
|
33168f35d5 | ||
|
|
0d6471acae | ||
|
|
41a04c9108 | ||
|
|
95cc17bb16 | ||
|
|
9f9e1b4cdb | ||
|
|
df71d60c2c | ||
|
|
9eef500eb9 | ||
|
|
8172b9c55e | ||
|
|
a35d3d73c2 | ||
|
|
5ae99dd04b | ||
|
|
5f118b51d4 | ||
|
|
b7a762ad44 | ||
|
|
a236bd7e4a | ||
|
|
25af9bee46 | ||
|
|
897f5076b2 | ||
|
|
dd7a7bbc74 | ||
|
|
ef4af5b379 | ||
|
|
cfb562bb7a | ||
|
|
0675192f2c | ||
|
|
27f0c5fe75 | ||
|
|
5153f16d00 | ||
|
|
deff8e5253 | ||
|
|
152ba10a13 | ||
|
|
36cb68fef7 | ||
|
|
7874cf3bd0 | ||
|
|
6ea7e93cb0 | ||
|
|
3520fb5ed4 | ||
|
|
c2266581b9 | ||
|
|
389de28cfb | ||
|
|
595dc5d42b | ||
|
|
c1d75c09be | ||
|
|
c0941512ae | ||
|
|
1f83f954dd | ||
|
|
3f7385d248 | ||
|
|
25d13d3cb2 | ||
|
|
5120b2cb64 | ||
|
|
bca4f6cfcd | ||
|
|
0b2ca909ed | ||
|
|
3a5a5ae7bc | ||
|
|
1d102cf1e9 | ||
|
|
4644d231c4 | ||
|
|
c50ed2f252 | ||
|
|
7bba3da732 | ||
|
|
6f9abd32e7 | ||
|
|
1c3e98619a | ||
|
|
20fe93fcdc | ||
|
|
57a9114ac5 | ||
|
|
4b2eecf8b0 | ||
|
|
ed88cbfce6 | ||
|
|
f7e70f5839 | ||
|
|
d76ef5e1d0 | ||
|
|
a4cf28c858 | ||
|
|
4f5e21d658 | ||
|
|
bd5f7cd373 | ||
|
|
d74795fd96 | ||
|
|
3fe17e58de | ||
|
|
adba0fbe22 | ||
|
|
64a99e5079 | ||
|
|
34def33f69 | ||
|
|
de34051cd4 | ||
|
|
346d845ee9 | ||
|
|
83ada431de | ||
|
|
2563d7e9b3 | ||
|
|
1f0f3e8f38 | ||
|
|
f13ecd0d1c | ||
|
|
54f35de99f | ||
|
|
f7b6c6f90f | ||
|
|
f003149b8d | ||
|
|
4f9e7c9677 | ||
|
|
14d7aad56c | ||
|
|
aa4d2ae764 | ||
|
|
4e60b248ca | ||
|
|
685f9024d7 | ||
|
|
104d429b69 | ||
|
|
8cf5672a73 | ||
|
|
186f7624a6 | ||
|
|
8986cde273 | ||
|
|
0abc3de4cd | ||
|
|
d219fab455 | ||
|
|
3b3e79ac14 | ||
|
|
2ff32a69e6 | ||
|
|
2b66f15bda | ||
|
|
508ff00663 | ||
|
|
d0fc391cde | ||
|
|
77a031eaa3 | ||
|
|
a6f6421992 | ||
|
|
fdf497397e | ||
|
|
ab605655e1 | ||
|
|
422574ed65 | ||
|
|
34f9b6f761 | ||
|
|
27e8178444 | ||
|
|
ba6796cd16 | ||
|
|
816d5da3ba | ||
|
|
c9c3c16e0b | ||
|
|
35dc055c40 | ||
|
|
6760ca1da1 | ||
|
|
36e6ee3ac4 | ||
|
|
362d97de1f | ||
|
|
530a2bb772 | ||
|
|
b333af3465 | ||
|
|
1b405987bf | ||
|
|
6dd52f86b9 | ||
|
|
76081e82af | ||
|
|
ebe2d16a87 | ||
|
|
60e4ced29a | ||
|
|
5683054349 | ||
|
|
210a96c143 | ||
|
|
92e108aa6b | ||
|
|
691b82589d | ||
|
|
4b471af065 | ||
|
|
3c556da991 | ||
|
|
9ddd371c86 | ||
|
|
5391468ea2 | ||
|
|
8daffc2ccf | ||
|
|
f58c204f51 | ||
|
|
5e857d6019 | ||
|
|
a7fe50f956 | ||
|
|
40239079a4 | ||
|
|
27c4602fca | ||
|
|
c107c6da93 | ||
|
|
f67995b4a9 | ||
|
|
851fdb1f1d | ||
|
|
8f52dc57ba | ||
|
|
427ee37b16 | ||
|
|
fc153f7fc9 | ||
|
|
5c9f571565 | ||
|
|
ab3905f6d8 | ||
|
|
9cee7d4588 | ||
|
|
dd95731b22 | ||
|
|
101384d595 | ||
|
|
77297d5a3e | ||
|
|
8b3c3a50ed | ||
|
|
4b5128e41d | ||
|
|
b11d713e5b | ||
|
|
143c4078d4 | ||
|
|
b6babaa2f8 | ||
|
|
57f0425bc0 | ||
|
|
c28159ebe7 | ||
|
|
2a0be33c23 | ||
|
|
f1c77c0a63 | ||
|
|
64fd80f489 |
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Build Docker image
|
||||
run: docker build -t wlan-cloud-ucentralgw:${{ github.sha }} .
|
||||
run: docker build -t wlan-cloud-owgw:${{ github.sha }} .
|
||||
|
||||
- name: Tag Docker image
|
||||
run: |
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
echo "Result tags: $TAGS"
|
||||
|
||||
for tag in $TAGS; do
|
||||
docker tag wlan-cloud-ucentralgw:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/ucentralgw:$tag
|
||||
docker tag wlan-cloud-owgw:${{ github.sha }} ${{ env.DOCKER_REGISTRY_URL }}/owgw:$tag
|
||||
done
|
||||
|
||||
- name: Log into Docker registry
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
- name: Push Docker images
|
||||
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/master'
|
||||
run: |
|
||||
docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/ucentralgw | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {}
|
||||
docker images | grep ${{ env.DOCKER_REGISTRY_URL }}/owgw | awk -F ' ' '{print $1":"$2}' | xargs -I {} docker push {}
|
||||
|
||||
docker-compose:
|
||||
if: startsWith(github.ref, 'refs/tags/') || startsWith(github.ref, 'refs/pull/') || github.ref == 'refs/heads/master'
|
||||
@@ -82,11 +82,11 @@ jobs:
|
||||
- name: Instantiate Docker Compose deployment
|
||||
working-directory: ./wlan-cloud-ucentral-deploy/docker-compose
|
||||
env:
|
||||
UCENTRALGW_TAG: ${{ github.sha }}
|
||||
OWGW_TAG: ${{ github.sha }}
|
||||
run: |
|
||||
docker-compose up -d
|
||||
docker-compose -f docker-compose.yml -f docker-compose.selfsigned.yml --env-file .env.selfsigned up -d
|
||||
|
||||
- name: Wait for uCentralSec to be alive and kicking
|
||||
- name: Wait for OWSec to be alive and kicking
|
||||
run: |
|
||||
n=0
|
||||
until [ "$n" -ge 3 ]
|
||||
@@ -100,11 +100,6 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Add self-signed certificates to system trust store of containers
|
||||
working-directory: ./wlan-cloud-ucentral-deploy/docker-compose
|
||||
run: |
|
||||
./add-ca-cert.sh
|
||||
|
||||
- name: Check out wlan-cloud-ucentralgw repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
@@ -112,8 +107,8 @@ jobs:
|
||||
|
||||
- name: Check functionality of microservices
|
||||
env:
|
||||
UCENTRALSEC: "ucentral.wlan.local:16001"
|
||||
FLAGS: "-s --cacert ./wlan-cloud-ucentral-deploy/docker-compose/certs/restapi-ca.pem --resolve ucentral.wlan.local:16001:127.0.0.1"
|
||||
OWSEC: "openwifi.wlan.local:16001"
|
||||
FLAGS: "-s --cacert ./wlan-cloud-ucentral-deploy/docker-compose/certs/restapi-ca.pem --resolve openwifi.wlan.local:16001:127.0.0.1"
|
||||
run: |
|
||||
./wlan-cloud-ucentralgw/test_scripts/curl/cli listdevices
|
||||
|
||||
@@ -121,8 +116,8 @@ jobs:
|
||||
working-directory: ./wlan-cloud-ucentral-deploy/docker-compose
|
||||
if: always()
|
||||
run: |
|
||||
docker-compose ps -a
|
||||
docker-compose logs
|
||||
docker-compose -f docker-compose.yml -f docker-compose.selfsigned.yml --env-file .env.selfsigned ps -a
|
||||
docker-compose -f docker-compose.yml -f docker-compose.selfsigned.yml --env-file .env.selfsigned logs
|
||||
|
||||
# disable until repo is public
|
||||
#- name: export Docker image
|
||||
|
||||
2
.github/workflows/cleanup.yml
vendored
2
.github/workflows/cleanup.yml
vendored
@@ -17,4 +17,4 @@ jobs:
|
||||
- name: Cleanup Docker image with PR branch tag
|
||||
run: |
|
||||
export PR_BRANCH_TAG=$(echo ${GITHUB_HEAD_REF#refs/heads/} | tr '/' '-')
|
||||
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/ucentralgw/$PR_BRANCH_TAG"
|
||||
curl -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owgw/$PR_BRANCH_TAG"
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -25,3 +25,6 @@ _deps
|
||||
test_scripts/curl/token.json
|
||||
.vscode/c_cpp_properties.json
|
||||
test_scripts/curl/result.json
|
||||
*.swp
|
||||
helm/charts/*
|
||||
!helm/charts/.gitkeep
|
||||
|
||||
@@ -82,6 +82,9 @@ Do wifiscan for a device.
|
||||
- `serial`: device serial number
|
||||
- `verbose`: verbose=true/false
|
||||
|
||||
### telemetry <serial>
|
||||
Start `telemetry` stream for a device.
|
||||
|
||||
### trace <serial> <duration> <network>
|
||||
Launch a remote trace for a device.
|
||||
- `serial`: device serial number
|
||||
@@ -161,12 +164,23 @@ Get a list of devices based on a list.
|
||||
### deviceswithstatus
|
||||
Get devices with their status.
|
||||
|
||||
### setloglevel <sys> <level>
|
||||
Set the logging system level for individual subsystems.
|
||||
- `sys`: ufileuploader/websocket/storage/restapi/commandmanager/auth/deviceregistry/all
|
||||
- `level`: level:none/fatal/critical/error/warning/notice/information/debug/trace
|
||||
### setloglevel <subsystem> <loglevel>
|
||||
Set the log level for s specific subsystem.
|
||||
|
||||
### getfile <uuid>
|
||||
### getloglevels
|
||||
Get the current log levels for all subsystems.
|
||||
|
||||
### getloglevelnames
|
||||
Get the log level names available.
|
||||
|
||||
### getsubsystemnames
|
||||
Get the list of subsystems.
|
||||
|
||||
### systeminfo
|
||||
Get basic system information.
|
||||
|
||||
### reloadsubsystem <subsystem name>
|
||||
Reload the configuration for a subsystem.### getfile <uuid>
|
||||
Get the file associated with trace command <uuid>.
|
||||
- `uuid`: UUID of file to retrieve
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
project(ucentralgw VERSION 2.0.0)
|
||||
project(owgw VERSION 2.2.0)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
@@ -38,6 +38,8 @@ set(Boost_USE_STATIC_RUNTIME OFF)
|
||||
find_package(Boost REQUIRED system)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(nlohmann_json_schema_validator REQUIRED)
|
||||
|
||||
if(SMALL_BUILD)
|
||||
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
|
||||
@@ -50,7 +52,7 @@ endif()
|
||||
|
||||
include_directories(/usr/local/include /usr/local/opt/openssl/include src include/kafka /usr/local/opt/mysql-client/include)
|
||||
|
||||
add_executable( ucentralgw
|
||||
add_executable( owgw
|
||||
build
|
||||
src/Daemon.cpp src/Daemon.h
|
||||
src/RESTAPI_server.cpp src/RESTAPI_server.h
|
||||
@@ -73,38 +75,50 @@ add_executable( ucentralgw
|
||||
src/RESTAPI_command.cpp src/RESTAPI_command.h
|
||||
src/FileUploader.cpp src/FileUploader.h
|
||||
src/RESTAPI_file.cpp src/RESTAPI_file.h
|
||||
src/CommandChannel.cpp src/CommandChannel.h
|
||||
src/RESTAPI_system_command.cpp src/RESTAPI_system_command.h
|
||||
src/RESTAPI_BlackList.cpp src/RESTAPI_BlackList.h
|
||||
src/Utils.h src/Utils.cpp src/storage_blacklist.cpp
|
||||
src/storage_command.cpp src/storage_healthcheck.cpp src/storage_statistics.cpp src/storage_logs.cpp
|
||||
src/storage_device.cpp src/storage_capabilities.cpp src/storage_defconfig.cpp src/storage_sqlite.cpp
|
||||
src/storage_mysql.cpp src/storage_pgql.cpp src/storage_tables.cpp
|
||||
src/storage_device.cpp src/storage_capabilities.cpp src/storage_defconfig.cpp
|
||||
src/storage_tables.cpp
|
||||
src/storage_setup.cpp
|
||||
src/StateProcessor.cpp src/StateProcessor.h
|
||||
src/storage_lifetime_stats.cpp src/uCentralProtocol.h src/RESTAPI_protocol.h
|
||||
src/ALBHealthCheckServer.h src/Kafka_topics.h src/uCentralTypes.h
|
||||
src/ALBHealthCheckServer.h src/Kafka_topics.h
|
||||
src/OUIServer.cpp src/OUIServer.h
|
||||
src/RESTAPI_ouis.cpp src/RESTAPI_ouis.h
|
||||
src/MicroService.cpp src/MicroService.h
|
||||
src/RESTAPI_RPC.cpp src/RESTAPI_RPC.h src/AuthClient.cpp src/AuthClient.h src/OpenAPIRequest.cpp src/OpenAPIRequest.h
|
||||
src/RESTAPI_utils.h src/RESTAPI_utils.cpp src/StorageArchiver.cpp src/StorageArchiver.h src/Dashboard.cpp src/Dashboard.h src/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI_deviceDashboardHandler.h)
|
||||
src/RESTAPI_RPC.cpp src/RESTAPI_RPC.h
|
||||
src/AuthClient.cpp src/AuthClient.h
|
||||
src/OpenAPIRequest.cpp src/OpenAPIRequest.h
|
||||
src/RESTAPI_utils.h src/RESTAPI_utils.cpp
|
||||
src/StorageArchiver.cpp src/StorageArchiver.h
|
||||
src/Dashboard.cpp src/Dashboard.h
|
||||
src/RESTAPI_deviceDashboardHandler.cpp src/RESTAPI_deviceDashboardHandler.h
|
||||
src/SerialNumberCache.cpp src/SerialNumberCache.h
|
||||
src/RESTAPI_webSocketServer.cpp src/RESTAPI_webSocketServer.h
|
||||
src/OpenWifiTypes.h src/TelemetryStream.cpp src/TelemetryStream.h
|
||||
src/RESTAPI_GenericServer.cpp src/RESTAPI_GenericServer.h
|
||||
src/RESTAPI_errors.h src/RESTAPI_TelemetryWebSocket.cpp src/RESTAPI_TelemetryWebSocket.h
|
||||
src/ConfigurationValidator.cpp src/ConfigurationValidator.h src/ConfigurationCache.cpp src/ConfigurationCache.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_sources(ucentralgw PUBLIC src/KafkaManager.cpp src/KafkaManager.h)
|
||||
target_sources(owgw PUBLIC src/KafkaManager.cpp src/KafkaManager.h)
|
||||
endif()
|
||||
|
||||
INSTALL(TARGETS ucentralgw
|
||||
INSTALL(TARGETS owgw
|
||||
RUNTIME DESTINATION /usr/bin
|
||||
)
|
||||
|
||||
target_link_libraries(ucentralgw PUBLIC
|
||||
target_link_libraries(owgw PUBLIC
|
||||
${Poco_LIBRARIES} ${Boost_LIBRARIES} ${ZLIB_LIBRARIES})
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(ucentralgw PUBLIC
|
||||
target_link_libraries(owgw PUBLIC
|
||||
${MySQL_LIBRARIES} ${ZLIB_LIBRARIES}
|
||||
CppKafka::cppkafka
|
||||
CppKafka::cppkafka
|
||||
nlohmann_json_schema_validator
|
||||
)
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_link_libraries(ucentralgw PUBLIC PocoJSON)
|
||||
target_link_libraries(owgw PUBLIC PocoJSON)
|
||||
endif()
|
||||
endif()
|
||||
48
Dockerfile
48
Dockerfile
@@ -7,10 +7,12 @@ RUN apk add --update --no-cache \
|
||||
make cmake gcc g++ libstdc++ libgcc git zlib-dev yaml-cpp-dev \
|
||||
openssl-dev boost-dev unixodbc-dev postgresql-dev mariadb-dev \
|
||||
apache2-utils yaml-dev apr-util-dev \
|
||||
lua-dev librdkafka-dev
|
||||
lua-dev librdkafka-dev \
|
||||
nlohmann-json
|
||||
|
||||
RUN git clone https://github.com/stephb9959/poco /poco
|
||||
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
|
||||
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
|
||||
|
||||
WORKDIR /cppkafka
|
||||
RUN mkdir cmake-build
|
||||
@@ -26,35 +28,47 @@ RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
RUN cmake --build . --target install
|
||||
|
||||
ADD CMakeLists.txt build /ucentralgw/
|
||||
ADD cmake /ucentralgw/cmake
|
||||
ADD src /ucentralgw/src
|
||||
|
||||
WORKDIR /ucentralgw
|
||||
WORKDIR /json-schema-validator
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR /ucentralgw/cmake-build
|
||||
WORKDIR cmake-build
|
||||
RUN cmake ..
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
ADD CMakeLists.txt build /owgw/
|
||||
ADD cmake /owgw/cmake
|
||||
ADD src /owgw/src
|
||||
|
||||
WORKDIR /owgw
|
||||
RUN mkdir cmake-build
|
||||
WORKDIR /owgw/cmake-build
|
||||
RUN cmake ..
|
||||
RUN cmake --build . --config Release -j8
|
||||
|
||||
FROM alpine
|
||||
|
||||
ENV UCENTRALGW_USER=ucentralgw \
|
||||
UCENTRALGW_ROOT=/ucentralgw-data \
|
||||
UCENTRALGW_CONFIG=/ucentralgw-data
|
||||
ENV OWGW_USER=owgw \
|
||||
OWGW_ROOT=/owgw-data \
|
||||
OWGW_CONFIG=/owgw-data
|
||||
|
||||
RUN addgroup -S "$UCENTRALGW_USER" && \
|
||||
adduser -S -G "$UCENTRALGW_USER" "$UCENTRALGW_USER"
|
||||
RUN addgroup -S "$OWGW_USER" && \
|
||||
adduser -S -G "$OWGW_USER" "$OWGW_USER"
|
||||
|
||||
RUN mkdir /ucentral
|
||||
RUN mkdir -p "$UCENTRALGW_ROOT" "$UCENTRALGW_CONFIG"
|
||||
RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec
|
||||
RUN mkdir /openwifi
|
||||
RUN mkdir -p "$OWGW_ROOT" "$OWGW_CONFIG" && \
|
||||
chown "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
|
||||
RUN apk add --update --no-cache librdkafka mariadb-connector-c libpq unixodbc su-exec gettext ca-certificates
|
||||
|
||||
COPY --from=builder /ucentralgw/cmake-build/ucentralgw /ucentral/ucentralgw
|
||||
COPY --from=builder /owgw/cmake-build/owgw /openwifi/owgw
|
||||
COPY --from=builder /cppkafka/cmake-build/src/lib/* /lib/
|
||||
COPY --from=builder /poco/cmake-build/lib/* /lib/
|
||||
|
||||
COPY owgw.properties.tmpl ${OWGW_CONFIG}/
|
||||
COPY docker-entrypoint.sh /
|
||||
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
|
||||
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
|
||||
|
||||
EXPOSE 15002 16002 16003 17002 16102
|
||||
|
||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||
CMD ["/ucentral/ucentralgw"]
|
||||
CMD ["/openwifi/owgw"]
|
||||
|
||||
42
PROTOCOL.md
42
PROTOCOL.md
@@ -518,6 +518,48 @@ The device should answer:
|
||||
}
|
||||
```
|
||||
|
||||
#### Controller requesting telemetry stream information
|
||||
Controller sends this command when it needs the device to telemetry streaming.
|
||||
```
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "telemetry" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"interval" : 0-60, # number of seconds for polling information. 0 means to shutdown the stream
|
||||
"types" : [ "dhcp", "rrm"], <this must be an array: array of 1 or 2 elements, right now only "rrm" and "dhcp" are supported
|
||||
},
|
||||
"id" : <some number>
|
||||
}
|
||||
```
|
||||
|
||||
The device should answer:
|
||||
```
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"result" : {
|
||||
"serial" : <serial number> ,
|
||||
"status" : {
|
||||
"error" : 0 or an error number,
|
||||
"text" : <description of the error or success>
|
||||
}
|
||||
},
|
||||
"id" : <same number>
|
||||
}
|
||||
```
|
||||
|
||||
When the interval is greater than 0, the gateway will start to receive messages
|
||||
```
|
||||
{ "jsonrpc" : "2.0" ,
|
||||
"method" : "telemetry" ,
|
||||
"params" : {
|
||||
"serial" : <serial number> ,
|
||||
"data" : <A JSON document describing the information coming from the device>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The device will stop sending data after 30 minutes or if it receives a `telemetry` command with an interval of 0.
|
||||
|
||||
|
||||
#### Controller requesting an `rtty` session
|
||||
Controller sends this command an administrator requests to start an `rtty` session with the AP.
|
||||
```
|
||||
|
||||
128
README.md
128
README.md
@@ -26,9 +26,9 @@ Poco may take several minutes depending on the platform you are building on.
|
||||
### Ubuntu
|
||||
These instructions have proven to work on Ubuntu 20.4.
|
||||
```
|
||||
sudo apt install git cmake g++ libssl-dev libmariabd-dev unixodbc-dev
|
||||
sudo apt install git cmake g++ libssl-dev libmariadb-dev unixodbc-dev
|
||||
sudo apt install libpq-dev libaprutil1-dev apache2-dev libboost-all-dev
|
||||
sudo apt install librdkafka-dev liblua5.3-dev
|
||||
sudo apt install librdkafka-dev liblua5.3-dev libmysqlclient-dev
|
||||
|
||||
git clone https://github.com/stephb9959/poco
|
||||
cd poco
|
||||
@@ -153,8 +153,8 @@ cmake -DSMALL_BUILD=1 ..
|
||||
make
|
||||
```
|
||||
|
||||
### After the build step is completed
|
||||
Once your build is done. You can remove the Poco source as it is no longer needed.
|
||||
### After completing the build
|
||||
After completing the build, you can remove the Poco source as it is no longer needed.
|
||||
|
||||
#### Expected directory layout
|
||||
From the directory where your cloned source is, you will need to create the `certs`, `logs`, and `uploads` directories.
|
||||
@@ -179,7 +179,7 @@ You should now have the following:
|
||||
+-- test_scripts
|
||||
+-- openapi
|
||||
+-- uploads
|
||||
+-- ucentralgw.properties
|
||||
+-- owgw.properties
|
||||
```
|
||||
|
||||
### Certificates
|
||||
@@ -218,15 +218,15 @@ document. Once you have these files, you need to renamed them `restapi-key.pem`,
|
||||
in your browner
|
||||
|
||||
#### Configuration
|
||||
The configuration for this service is kept in a properties file. This file is called `ucentralgw.properties` and you can
|
||||
see the latest version [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/ucentralgw.properties). The file will be loaded from
|
||||
the directory set by the environment variable `UCENTRAL_CONFIG`. To use environment variables in the configuration,
|
||||
The configuration for this service is kept in a properties file. This file is called `owgw.properties` and you can
|
||||
see the latest version [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/owgw.properties). The file will be loaded from
|
||||
the directory set by the environment variable `UCENTRALGW_CONFIG`. To use environment variables in the configuration,
|
||||
you must use `$<varname>`. Only `path names` support the use of environment variables. The sample configuration requires very
|
||||
little changes if you keep the suggested directory structure. For the sample configuration to work, you need to define 2
|
||||
environment variables.
|
||||
```
|
||||
export UCENTRAL_ROOT=`pwd`
|
||||
export UCENTRAL_CONFIG=`pwd`
|
||||
export OWGW_ROOT=`pwd`
|
||||
export UCENTRALGW_CONFIG=`pwd`
|
||||
```
|
||||
If you current working directory is the root of the project, this will set the variables properly. Otherwise, you can set the variables
|
||||
to point to wherever is necessary.
|
||||
@@ -234,7 +234,7 @@ to point to wherever is necessary.
|
||||
##### Important config entries
|
||||
###### This is the logging directory
|
||||
```
|
||||
logging.channels.c2.path = $UCENTRAL_ROOT/logs/sample.log
|
||||
logging.channels.c2.path = $OWGW_ROOT/logs/sample.log
|
||||
```
|
||||
|
||||
###### This is the type of storage in use
|
||||
@@ -244,23 +244,23 @@ storage.type = sqlite
|
||||
|
||||
###### Autoprovisioning settings
|
||||
```asm
|
||||
ucentral.autoprovisioning = true
|
||||
ucentral.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
ucentral.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
|
||||
ucentral.devicetypes.2 = IOT:esp32
|
||||
openwifi.autoprovisioning = true
|
||||
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2 = IOT:esp32
|
||||
```
|
||||
|
||||
###### This is the RESTAPI endpoint
|
||||
|
||||
```asm
|
||||
ucentral.restapi.host.0.backlog = 100
|
||||
ucentral.restapi.host.0.security = relaxed
|
||||
ucentral.restapi.host.0.rootca = $UCENTRAL_ROOT/certs/restapi-ca.pem
|
||||
ucentral.restapi.host.0.address = *
|
||||
ucentral.restapi.host.0.port = 16002
|
||||
ucentral.restapi.host.0.cert = $UCENTRAL_ROOT/certs/restapi-cert.pem
|
||||
ucentral.restapi.host.0.key = $UCENTRAL_ROOT/certs/restapi-key.pem
|
||||
ucentral.restapi.host.0.key.password = mypassword
|
||||
openwifi.restapi.host.0.backlog = 100
|
||||
openwifi.restapi.host.0.security = relaxed
|
||||
openwifi.restapi.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.restapi.host.0.address = *
|
||||
openwifi.restapi.host.0.port = 16002
|
||||
openwifi.restapi.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.restapi.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.restapi.host.0.key.password = mypassword
|
||||
```
|
||||
|
||||
##### This is the end point for the devices to connect with
|
||||
@@ -309,12 +309,12 @@ You will need to get the `cert.pem` and `key.pem` from Digicert. The rest is her
|
||||
|
||||
```asm
|
||||
ucentral.websocket.host.0.backlog = 500
|
||||
ucentral.websocket.host.0.rootca = $UCENTRAL_ROOT/certs/root.pem
|
||||
ucentral.websocket.host.0.issuer = $UCENTRAL_ROOT/certs/issuer.pem
|
||||
ucentral.websocket.host.0.cert = $UCENTRAL_ROOT/certs/websocket-cert.pem
|
||||
ucentral.websocket.host.0.key = $UCENTRAL_ROOT/certs/websocket-key.pem
|
||||
ucentral.websocket.host.0.clientcas = $UCENTRAL_ROOT/certs/clientcas.pem
|
||||
ucentral.websocket.host.0.cas = $UCENTRAL_ROOT/certs/cas
|
||||
ucentral.websocket.host.0.rootca = $OWGW_ROOT/certs/root.pem
|
||||
ucentral.websocket.host.0.issuer = $OWGW_ROOT/certs/issuer.pem
|
||||
ucentral.websocket.host.0.cert = $OWGW_ROOT/certs/websocket-cert.pem
|
||||
ucentral.websocket.host.0.key = $OWGW_ROOT/certs/websocket-key.pem
|
||||
ucentral.websocket.host.0.clientcas = $OWGW_ROOT/certs/clientcas.pem
|
||||
ucentral.websocket.host.0.cas = $OWGW_ROOT/certs/cas
|
||||
ucentral.websocket.host.0.address = *
|
||||
ucentral.websocket.host.0.port = 15002
|
||||
ucentral.websocket.host.0.security = strict
|
||||
@@ -324,17 +324,17 @@ ucentral.websocket.maxreactors = 20
|
||||
|
||||
###### This is the end point for the devices when uploading files
|
||||
```asm
|
||||
ucentral.fileuploader.host.0.backlog = 100
|
||||
ucentral.fileuploader.host.0.rootca = $UCENTRAL_ROOT/certs/restapi-ca.pem
|
||||
ucentral.fileuploader.host.0.security = relaxed
|
||||
ucentral.fileuploader.host.0.address = *
|
||||
ucentral.fileuploader.host.0.name = 192.168.1.176
|
||||
ucentral.fileuploader.host.0.port = 16003
|
||||
ucentral.fileuploader.host.0.cert = $UCENTRAL_ROOT/certs/restapi-cert.pem
|
||||
ucentral.fileuploader.host.0.key = $UCENTRAL_ROOT/certs/restapi-key.pem
|
||||
ucentral.fileuploader.host.0.key.password = mypassword
|
||||
ucentral.fileuploader.path = $UCENTRAL_ROOT/uploads
|
||||
ucentral.fileuploader.maxsize = 10000
|
||||
openwifi.fileuploader.host.0.backlog = 100
|
||||
openwifi.fileuploader.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.fileuploader.host.0.security = relaxed
|
||||
openwifi.fileuploader.host.0.address = *
|
||||
openwifi.fileuploader.host.0.name = 192.168.1.176
|
||||
openwifi.fileuploader.host.0.port = 16003
|
||||
openwifi.fileuploader.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.fileuploader.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.fileuploader.host.0.key.password = mypassword
|
||||
openwifi.fileuploader.path = $OWGW_ROOT/uploads
|
||||
openwifi.fileuploader.maxsize = 10000
|
||||
```
|
||||
|
||||
###### host.0.address entries
|
||||
@@ -343,7 +343,7 @@ the `*`. Using the `*` means all interfaces will be able to accept connections.
|
||||
by changing the `0` to another index. You need to repeat the whole configuration block for each index. Indexes must be sequential
|
||||
start at `0`.
|
||||
|
||||
###### ucentral.fileuploader.host.0.name
|
||||
###### openwifi.fileuploader.host.0.name
|
||||
This must point to the IP or FQDN of your uCentralGW.
|
||||
|
||||
#### Running the gateway
|
||||
@@ -369,7 +369,7 @@ can be any of the keys you are already using. You must keep that keep secret and
|
||||
this is the entry
|
||||
|
||||
```asm
|
||||
ucentral.service.key = $UCENTRAL_ROOT/certs/websocket-key.pem
|
||||
openwifi.service.key = $OWGW_ROOT/certs/websocket-key.pem
|
||||
```
|
||||
|
||||
#### Command line options
|
||||
@@ -391,7 +391,7 @@ A uCentral gateway implementation for TIP.
|
||||
```
|
||||
|
||||
##### file
|
||||
This allows you to point to another file without specifying the UCENTRAL_CONFIG variable. The file name must end in `.properties`.
|
||||
This allows you to point to another file without specifying the UCENTRALGW_CONFIG variable. The file name must end in `.properties`.
|
||||
##### daemon
|
||||
Run this as a UNIX service
|
||||
##### pidfile
|
||||
@@ -440,9 +440,9 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f ucentralgw.properties ]]
|
||||
if [[ ! -f owgw.properties ]]
|
||||
then
|
||||
echo "Configuration file ucentralgw.properties is missing in the current directory"
|
||||
echo "Configuration file owgw.properties is missing in the current directory"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
@@ -452,15 +452,15 @@ docker run -d -p 15002:15002 \
|
||||
--init \
|
||||
--volume="$PWD:/ucentral-data" \
|
||||
-e UCENTRAL_ROOT="/ucentral-data" \
|
||||
-e UCENTRAL_CONFIG="/ucentral-data" \
|
||||
-e UCENTRALGW_CONFIG="/ucentral-data" \
|
||||
--name="ucentralgw" $DOCKER_NAME
|
||||
|
||||
```
|
||||
|
||||
Create yourself a directory and copy that script which you can also get from [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/docker_run.sh).
|
||||
You must have the basic configuration file copied in the directory. This file must be called `ucentralgw.properties`. You can bring your own or
|
||||
copy it from [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/ucentralgw.properties). Please look at [this](#certificates-with-docker) to have the right
|
||||
certificates. You need to make sure that the names match the content of the `ucentralgw.properties`
|
||||
You must have the basic configuration file copied in the directory. This file must be called `owgw.properties`. You can bring your own or
|
||||
copy it from [here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/owgw.properties). Please look at [this](#certificates-with-docker) to have the right
|
||||
certificates. You need to make sure that the names match the content of the `owgw.properties`
|
||||
file. Once all this is done, you can simply run `docker_run.sh`.
|
||||
|
||||
#### Docker installation directory layout
|
||||
@@ -472,15 +472,15 @@ Run-time root
|
||||
----- certs (same as above)
|
||||
+---- logs (dir)
|
||||
+---- uploads (dir)
|
||||
+---- ucentralgw.properties (file)
|
||||
+---- owgw.properties (file)
|
||||
```
|
||||
|
||||
#### `ucentralgw.properties` for Docker
|
||||
#### `owgw.properties` for Docker
|
||||
If you use the pre-made configuration file, and you follow the directory layout, the only line you must change
|
||||
is the following line:
|
||||
|
||||
```asm
|
||||
ucentral.fileuploader.host.0.name = 192.168.1.176
|
||||
openwifi.fileuploader.host.0.name = 192.168.1.176
|
||||
```
|
||||
|
||||
This line should reflect the IP of your gateway or its FQDN. You must make sure that this name or IP is accessible
|
||||
@@ -491,9 +491,9 @@ Please refer to the `certs` directory from the sections above.
|
||||
|
||||
#### Configuration with Docker
|
||||
The configuration for this service is kept in a properties file. Currently, this configuration file must be kept in the
|
||||
current directory of uCentral or one level up. This file is called `ucentralgw.properties` and you can see the latest version
|
||||
[here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/ucentralgw.properties). The file will be loaded from
|
||||
the directory set by the environment variable `UCENTRAL_CONFIG`. To use environment variables in the configuration,
|
||||
current directory of uCentral or one level up. This file is called `owgw.properties` and you can see the latest version
|
||||
[here](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/owgw.properties). The file will be loaded from
|
||||
the directory set by the environment variable `UCENTRALGW_CONFIG`. To use environment variables in the configuration,
|
||||
you must use `$<varname>`. The path for the logs for the service must exist prior to starting the
|
||||
service. The path is defined under `logging.channels.c2.path`. Only `path names` support the use of
|
||||
environment variables. Here is a sample configuration:
|
||||
@@ -507,29 +507,29 @@ And here is [how to use it](https://github.com/Telecominfraproject/wlan-cloud-uc
|
||||
|
||||
## Using the API
|
||||
In the `test_scripts` directory, you will find a series of scripts that will show you how to use the API
|
||||
with [curl](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/TEST_CURL.md)
|
||||
with [curl](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/CLI.md)
|
||||
or [python](https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/main/TEST_PYTHON.md).
|
||||
More scripts will be added in the future.
|
||||
|
||||
## Firewall Considerations
|
||||
- The protocol uses TCP port 15002 between the devices and the gateway. This port must be opened.
|
||||
- Devices use the TCP port 16003 to upload files. This port is configurable in the `ucentralgw.properties` file. Look for `ucentral.fileuploader.host.0.port`.
|
||||
- The RESTAPI is accessed through TCP port 16002 by default. This port is configurable in the `ucentralgw.properties` file. Look for the entry `ucentral.restapi.host.0.port`.
|
||||
- Devices use the TCP port 16003 to upload files. This port is configurable in the `owgw.properties` file. Look for `openwifi.fileuploader.host.0.port`.
|
||||
- The RESTAPI is accessed through TCP port 16002 by default. This port is configurable in the `owgw.properties` file. Look for the entry `openwifi.restapi.host.0.port`.
|
||||
|
||||
## Kafka integration
|
||||
So what about Kafka? Well, the gateway has basic integration with Kafka. It is turned off by default, to turn it on, in the configuration:
|
||||
|
||||
```asm
|
||||
ucentral.kafka.enable = false
|
||||
ucentral.kafka.brokerlist = 127.0.0.1:9092
|
||||
ucentral.kafka.commit = false
|
||||
ucentral.kafka.queue.buffering.max.ms = 50
|
||||
openwifi.kafka.enable = false
|
||||
openwifi.kafka.brokerlist = 127.0.0.1:9092
|
||||
openwifi.kafka.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
```
|
||||
|
||||
#### `ucentral.kafka.enable`
|
||||
#### `openwifi.kafka.enable`
|
||||
Kind of obvious but hey, set `true` or `false`. Default is `false`
|
||||
|
||||
#### `ucentral.kafka.brokerlist`
|
||||
#### `openwifi.kafka.brokerlist`
|
||||
This is a comma separator list of the brokers in your `kafka` deployment.
|
||||
|
||||
#### Kafka topics
|
||||
|
||||
@@ -1,11 +1,70 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
if [ "$1" = '/ucentral/ucentralgw' -a "$(id -u)" = '0' ]; then
|
||||
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
|
||||
update-ca-certificates
|
||||
fi
|
||||
|
||||
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWGW_CONFIG"/owgw.properties ]]; then
|
||||
WEBSOCKET_HOST_ROOTCA=${WEBSOCKET_HOST_ROOTCA:-"\$OWGW_ROOT/certs/root.pem"} \
|
||||
WEBSOCKET_HOST_ISSUER=${WEBSOCKET_HOST_ISSUER:-"\$OWGW_ROOT/certs/issuer.pem"} \
|
||||
WEBSOCKET_HOST_CERT=${WEBSOCKET_HOST_CERT:-"\$OWGW_ROOT/certs/websocket-cert.pem"} \
|
||||
WEBSOCKET_HOST_KEY=${WEBSOCKET_HOST_KEY:-"\$OWGW_ROOT/certs/websocket-key.pem"} \
|
||||
WEBSOCKET_HOST_CLIENTCAS=${WEBSOCKET_HOST_CLIENTCAS:-"\$OWGW_ROOT/certs/clientcas.pem"} \
|
||||
WEBSOCKET_HOST_CAS=${WEBSOCKET_HOST_CAS:-"\$OWGW_ROOT/certs/cas"} \
|
||||
WEBSOCKET_HOST_PORT=${WEBSOCKET_HOST_PORT:-"15002"} \
|
||||
WEBSOCKET_HOST_KEY_PASSWORD=${WEBSOCKET_HOST_KEY_PASSWORD:-"mypassword"} \
|
||||
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
|
||||
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16002"} \
|
||||
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
|
||||
RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
|
||||
RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
|
||||
INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
|
||||
INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17002"} \
|
||||
INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
|
||||
INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
|
||||
INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \
|
||||
FILEUPLOADER_HOST_ROOTCA=${FILEUPLOADER_HOST_ROOTCA:-"\$OWGW_ROOT/certs/restapi-ca.pem"} \
|
||||
FILEUPLOADER_HOST_NAME=${FILEUPLOADER_HOST_NAME:-"localhost"} \
|
||||
FILEUPLOADER_HOST_PORT=${FILEUPLOADER_HOST_PORT:-"16003"} \
|
||||
FILEUPLOADER_HOST_CERT=${FILEUPLOADER_HOST_CERT:-"\$OWGW_ROOT/certs/restapi-cert.pem"} \
|
||||
FILEUPLOADER_HOST_KEY=${FILEUPLOADER_HOST_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
|
||||
FILEUPLOADER_HOST_KEY_PASSWORD=${FILEUPLOADER_HOST_KEY_PASSWORD:-"mypassword"} \
|
||||
FILEUPLOADER_PATH=${FILEUPLOADER_PATH:-"\$OWGW_ROOT/uploads"} \
|
||||
FILEUPLOADER_URI=${FILEUPLOADER_URI:-"https://localhost:16003"} \
|
||||
SERVICE_KEY=${SERVICE_KEY:-"\$OWGW_ROOT/certs/restapi-key.pem"} \
|
||||
SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \
|
||||
SYSTEM_DATA=${SYSTEM_DATA:-"\$OWGW_ROOT/data"} \
|
||||
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17002"} \
|
||||
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16002"} \
|
||||
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
|
||||
RTTY_ENABLED=${RTTY_ENABLED:-"false"} \
|
||||
RTTY_SERVER=${RTTY_SERVER:-"localhost"} \
|
||||
RTTY_PORT=${RTTY_PORT:-"5912"} \
|
||||
RTTY_TOKEN=${RTTY_TOKEN:-"96181c567b4d0d98c50f127230068fa8"} \
|
||||
RTTY_TIMEOUT=${RTTY_TIMEOUT:-"60"} \
|
||||
RTTY_VIEWPORT=${RTTY_VIEWPORT:-"5913"} \
|
||||
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
|
||||
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
|
||||
STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \
|
||||
STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \
|
||||
STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owgw"} \
|
||||
STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owgw"} \
|
||||
STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owgw"} \
|
||||
STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \
|
||||
STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \
|
||||
STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owgw"} \
|
||||
STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owgw"} \
|
||||
STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owgw"} \
|
||||
STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \
|
||||
envsubst < $OWGW_CONFIG/owgw.properties.tmpl > $OWGW_CONFIG/owgw.properties
|
||||
fi
|
||||
|
||||
if [ "$1" = '/openwifi/owgw' -a "$(id -u)" = '0' ]; then
|
||||
if [ "$RUN_CHOWN" = 'true' ]; then
|
||||
chown -R "$UCENTRALGW_USER": "$UCENTRALGW_ROOT" "$UCENTRALGW_CONFIG"
|
||||
chown -R "$OWGW_USER": "$OWGW_ROOT" "$OWGW_CONFIG"
|
||||
fi
|
||||
exec su-exec "$UCENTRALGW_USER" "$@"
|
||||
exec su-exec "$OWGW_USER" "$@"
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -26,7 +26,7 @@ then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f ucentral.properties ]]
|
||||
if [[ ! -f owgw.properties ]]
|
||||
then
|
||||
echo "Configuration file ucentral.properties is missing in the current directory"
|
||||
exit 2
|
||||
@@ -37,7 +37,7 @@ docker run -d -p 15002:15002 \
|
||||
-p 16003:16003 \
|
||||
--init \
|
||||
--volume="$PWD:/ucentral-data" \
|
||||
-e UCENTRAL_ROOT="/ucentral-data" \
|
||||
-e UCENTRAL_CONFIG="/ucentral-data" \
|
||||
-e UCENTRALGW_ROOT="/ucentral-data" \
|
||||
-e UCENTRALGW_CONFIG="/ucentral-data" \
|
||||
--name="ucentralgw" $DOCKER_NAME
|
||||
|
||||
|
||||
0
helm/.gitkeep
Normal file
0
helm/.gitkeep
Normal file
12
helm/Chart.lock
Normal file
12
helm/Chart.lock
Normal file
@@ -0,0 +1,12 @@
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 10.9.2
|
||||
- name: mysql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 8.8.3
|
||||
- name: mariadb
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 9.4.2
|
||||
digest: sha256:1fdae7cbea906e41dccd8618ff9e2c68d0c684724ae27c79a12bb6089968df5c
|
||||
generated: "2021-08-17T12:18:40.341427893+03:00"
|
||||
@@ -1,5 +1,18 @@
|
||||
apiVersion: v1
|
||||
apiVersion: v2
|
||||
appVersion: "1.0"
|
||||
description: A Helm chart for Kubernetes
|
||||
name: ucentralgw
|
||||
name: owgw
|
||||
version: 0.1.0
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 10.9.2
|
||||
condition: postgresql.enabled
|
||||
- name: mysql
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 8.8.3
|
||||
condition: mysql.enabled
|
||||
- name: mariadb
|
||||
repository: https://charts.bitnami.com/bitnami
|
||||
version: 9.4.2
|
||||
condition: mariadb.enabled
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ucentralgw
|
||||
# owgw
|
||||
|
||||
This Helm chart helps to deploy uCentralGW to the Kubernetes clusters. It is mainly used in [assembly chart](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart) as uCentralGW requires other services as dependencies that are considered in that Helm chart. This chart is purposed to define deployment logic close to the application code itself and define default values that could be overriden during deployment.
|
||||
This Helm chart helps to deploy OpenWIFI Gateway (further on refered as __Gateway__) to the Kubernetes clusters. It is mainly used in [assembly chart](https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart) as Gateway requires other services as dependencies that are considered in that Helm chart. This chart is purposed to define deployment logic close to the application code itself and define default values that could be overriden during deployment.
|
||||
|
||||
|
||||
## TL;DR;
|
||||
@@ -11,7 +11,7 @@ $ helm install .
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart bootstraps an ucentralgw on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
|
||||
This chart bootstraps the Gateway on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
@@ -23,7 +23,7 @@ To install the chart with the release name `my-release`:
|
||||
$ helm install --name my-release git+https://github.com/Telecominfraproject/wlan-cloud-ucentralgw@helm?ref=master
|
||||
```
|
||||
|
||||
The command deploys ucentralgw on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
The command deploys the Gateway on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
|
||||
|
||||
> **Tip**: List all releases using `helm list`
|
||||
|
||||
@@ -47,40 +47,40 @@ The following table lists the configurable parameters of the chart and their def
|
||||
| strategyType | string | Application deployment strategy | `'Recreate'` |
|
||||
| nameOverride | string | Override to be used for application deployment | |
|
||||
| fullnameOverride | string | Override to be used for application deployment (has priority over nameOverride) | |
|
||||
| images.ucentralgw.repository | string | Docker image repository | |
|
||||
| images.ucentralgw.tag | string | Docker image tag | `'master'` |
|
||||
| images.ucentralgw.pullPolicy | string | Docker image pull policy | `'Always'` |
|
||||
| services.ucentralgw.type | string | uCentralGW service type | `'LoadBalancer'` |
|
||||
| services.ucentralgw.ports.websocket.servicePort | number | Websocket endpoint port to be exposed on service | `15002` |
|
||||
| services.ucentralgw.ports.websocket.targetPort | number | Websocket endpoint port to be targeted by service | `15002` |
|
||||
| services.ucentralgw.ports.websocket.protocol | string | Websocket endpoint protocol | `'TCP'` |
|
||||
| services.ucentralgw.ports.restapi.servicePort | number | REST API endpoint port to be exposed on service | `16002` |
|
||||
| services.ucentralgw.ports.restapi.targetPort | number | REST API endpoint port to be targeted by service | `16002` |
|
||||
| services.ucentralgw.ports.restapi.protocol | string | REST API endpoint protocol | `'TCP'` |
|
||||
| services.ucentralgw.ports.restapiinternal.servicePort | string | Internal REST API endpoint port to be exposed on service | `17002` |
|
||||
| services.ucentralgw.ports.restapiinternal.targetPort | number | Internal REST API endpoint port to be targeted by service | `17002` |
|
||||
| services.ucentralgw.ports.restapiinternal.protocol | string | Internal REST API endpoint protocol | `'TCP'` |
|
||||
| services.ucentralgw.ports.fileuploader.servicePort | string | Fileuploader endpoint port to be exposed on service | `16003` |
|
||||
| services.ucentralgw.ports.fileuploader.targetPort | number | Fileuploader endpoint port to be targeted by service | `16003` |
|
||||
| services.ucentralgw.ports.fileuploader.protocol | string | Fileuploader endpoint protocol | `'TCP'` |
|
||||
| checks.ucentralgw.liveness.httpGet.path | string | Liveness check path to be used | `'/'` |
|
||||
| checks.ucentralgw.liveness.httpGet.port | number | Liveness check port to be used (should be pointint to ALB endpoint) | `16102` |
|
||||
| checks.ucentralgw.readiness.httpGet.path | string | Readiness check path to be used | `'/'` |
|
||||
| checks.ucentralgw.readiness.httpGet.port | number | Readiness check port to be used (should be pointint to ALB endpoint) | `16102` |
|
||||
| images.owgw.repository | string | Docker image repository | |
|
||||
| images.owgw.tag | string | Docker image tag | `'master'` |
|
||||
| images.owgw.pullPolicy | string | Docker image pull policy | `'Always'` |
|
||||
| services.owgw.type | string | OpenWIFI Gateway service type | `'LoadBalancer'` |
|
||||
| services.owgw.ports.websocket.servicePort | number | Websocket endpoint port to be exposed on service | `15002` |
|
||||
| services.owgw.ports.websocket.targetPort | number | Websocket endpoint port to be targeted by service | `15002` |
|
||||
| services.owgw.ports.websocket.protocol | string | Websocket endpoint protocol | `'TCP'` |
|
||||
| services.owgw.ports.restapi.servicePort | number | REST API endpoint port to be exposed on service | `16002` |
|
||||
| services.owgw.ports.restapi.targetPort | number | REST API endpoint port to be targeted by service | `16002` |
|
||||
| services.owgw.ports.restapi.protocol | string | REST API endpoint protocol | `'TCP'` |
|
||||
| services.owgw.ports.restapiinternal.servicePort | string | Internal REST API endpoint port to be exposed on service | `17002` |
|
||||
| services.owgw.ports.restapiinternal.targetPort | number | Internal REST API endpoint port to be targeted by service | `17002` |
|
||||
| services.owgw.ports.restapiinternal.protocol | string | Internal REST API endpoint protocol | `'TCP'` |
|
||||
| services.owgw.ports.fileuploader.servicePort | string | Fileuploader endpoint port to be exposed on service | `16003` |
|
||||
| services.owgw.ports.fileuploader.targetPort | number | Fileuploader endpoint port to be targeted by service | `16003` |
|
||||
| services.owgw.ports.fileuploader.protocol | string | Fileuploader endpoint protocol | `'TCP'` |
|
||||
| checks.owgw.liveness.httpGet.path | string | Liveness check path to be used | `'/'` |
|
||||
| checks.owgw.liveness.httpGet.port | number | Liveness check port to be used (should be pointint to ALB endpoint) | `16102` |
|
||||
| checks.owgw.readiness.httpGet.path | string | Readiness check path to be used | `'/'` |
|
||||
| checks.owgw.readiness.httpGet.port | number | Readiness check port to be used (should be pointint to ALB endpoint) | `16102` |
|
||||
| ingresses.restapi.enabled | boolean | Defines if REST API endpoint should be exposed via Ingress controller | `False` |
|
||||
| ingresses.restapi.hosts | array | List of hosts for exposed REST API | |
|
||||
| ingresses.restapi.paths | array | List of paths to be exposed for REST API | |
|
||||
| ingresses.fileuploader.enabled | boolean | Defines if Fileuploader endpoint should be exposed via Ingress controller | `False` |
|
||||
| ingresses.fileuploader.hosts | array | List of hosts for exposed Fileuploader | |
|
||||
| ingresses.fileuploader.paths | array | List of paths for exposed Fileuploader | |
|
||||
| volumes.ucentralgw | array | Defines list of volumes to be attached to uCentralGW | |
|
||||
| persistence.enabled | boolean | Defines if uCentralGW requires Persistent Volume (required for permanent files storage and SQLite DB if enabled) | `True` |
|
||||
| volumes.owgw | array | Defines list of volumes to be attached to the Gateway | |
|
||||
| persistence.enabled | boolean | Defines if the Gateway requires Persistent Volume (required for permanent files storage and SQLite DB if enabled) | `True` |
|
||||
| persistence.accessModes | array | Defines PV access modes | |
|
||||
| persistence.size | string | Defines PV size | `'10Gi'` |
|
||||
| public_env_variables | hash | Defines list of environment variables to be passed to uCentralGW | |
|
||||
| configProperties | hash | Configuration properties that should be passed to the application in `ucentralgw.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to uCentralGW (PEM format is adviced to be used) (see `volumes.ucentralgw` on where it is mounted) | |
|
||||
| certsCAs | hash | Defines files with CAs that should be passed to uCentralGW (see `volumes.ucentralgw` on where it is mounted) | |
|
||||
| public_env_variables | hash | Defines list of environment variables to be passed to the Gateway | |
|
||||
| configProperties | hash | Configuration properties that should be passed to the application in `owgw.properties`. May be passed by key in set (i.e. `configProperties."rtty\.token"`) | |
|
||||
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owgw` on where it is mounted) | |
|
||||
| certsCAs | hash | Defines files with CAs that should be passed to the Gateway (see `volumes.owgw` on where it is mounted) | |
|
||||
|
||||
|
||||
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
|
||||
@@ -100,5 +100,3 @@ $ helm install --name my-release -f values.yaml .
|
||||
```
|
||||
|
||||
> **Tip**: You can use the default [values.yaml](values.yaml) as a base for customization.
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{{- define "ucentralgw.config" -}}
|
||||
{{- define "owgw.config" -}}
|
||||
{{- range $key, $value := .Values.configProperties }}
|
||||
{{ $key }} = {{ $value }}
|
||||
{{- end }}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "ucentralgw.name" -}}
|
||||
{{- define "owgw.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -11,7 +11,7 @@ Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "ucentralgw.fullname" -}}
|
||||
{{- define "owgw.fullname" -}}
|
||||
{{- if .Values.fullnameOverride -}}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
|
||||
{{- else -}}
|
||||
@@ -27,6 +27,6 @@ If release name contains chart name it will be used as a full name.
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "ucentralgw.chart" -}}
|
||||
{{- define "owgw.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||
{{- end -}}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "ucentralgw.fullname" . }}
|
||||
name: {{ include "owgw.fullname" . }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" . }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" . }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" . }}
|
||||
helm.sh/chart: {{ include "owgw.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
spec:
|
||||
@@ -15,28 +15,28 @@ spec:
|
||||
type: {{ .Values.strategyType }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" . }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- with .Values.services.ucentralgw.labels }}
|
||||
{{- with .Values.services.owgw.labels }}
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include "ucentralgw.config" . | sha256sum }}
|
||||
checksum/config: {{ include "owgw.config" . | sha256sum }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" . }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- with .Values.services.ucentralgw.labels }}
|
||||
{{- with .Values.services.owgw.labels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
|
||||
containers:
|
||||
|
||||
- name: ucentralgw
|
||||
image: "{{ .Values.images.ucentralgw.repository }}:{{ .Values.images.ucentralgw.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.ucentralgw.pullPolicy }}
|
||||
- name: owgw
|
||||
image: "{{ .Values.images.owgw.repository }}:{{ .Values.images.owgw.tag }}"
|
||||
imagePullPolicy: {{ .Values.images.owgw.pullPolicy }}
|
||||
|
||||
env:
|
||||
- name: KUBERNETES_DEPLOYED
|
||||
@@ -49,19 +49,19 @@ spec:
|
||||
- name: {{ $key }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "ucentralgw.fullname" $root }}-env
|
||||
name: {{ include "owgw.fullname" $root }}-env
|
||||
key: {{ $key }}
|
||||
{{- end }}
|
||||
|
||||
ports:
|
||||
{{- range $port, $portValue := .Values.services.ucentralgw.ports }}
|
||||
{{- range $port, $portValue := .Values.services.owgw.ports }}
|
||||
- name: {{ $port }}
|
||||
containerPort: {{ $portValue.targetPort }}
|
||||
protocol: {{ $portValue.protocol }}
|
||||
{{- end }}
|
||||
|
||||
volumeMounts:
|
||||
{{- range .Values.volumes.ucentralgw }}
|
||||
{{- range .Values.volumes.owgw }}
|
||||
- name: {{ .name }}
|
||||
mountPath: {{ .mountPath }}
|
||||
{{- if .subPath }}
|
||||
@@ -69,13 +69,13 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.checks.ucentralgw.liveness }}
|
||||
{{- if .Values.checks.owgw.liveness }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.checks.ucentralgw.liveness | nindent 12 }}
|
||||
{{- toYaml .Values.checks.owgw.liveness | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.checks.ucentralgw.readiness }}
|
||||
{{- if .Values.checks.owgw.readiness }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.checks.ucentralgw.readiness | nindent 12 }}
|
||||
{{- toYaml .Values.checks.owgw.readiness | nindent 12 }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.resources }}
|
||||
@@ -83,10 +83,15 @@ spec:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
|
||||
{{- with .Values.securityContext }}
|
||||
securityContext:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
||||
imagePullSecrets:
|
||||
{{- range $image, $imageValue := .Values.images }}
|
||||
{{- if $imageValue.regcred }}
|
||||
- name: {{ include "ucentralgw.fullname" $root }}-{{ $image }}-regcred
|
||||
- name: {{ include "owgw.fullname" $root }}-{{ $image }}-regcred
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "ucentralgw.fullname" $root }}-{{ $ingress }}
|
||||
name: {{ include "owgw.fullname" $root }}-{{ $ingress }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" $root }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" $root }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" $root }}
|
||||
helm.sh/chart: {{ include "owgw.chart" $root }}
|
||||
app.kubernetes.io/instance: {{ $root.Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ $root.Release.Service }}
|
||||
{{- with $ingressValue.annotations }}
|
||||
@@ -37,7 +37,7 @@ spec:
|
||||
{{- range $ingressValue.paths }}
|
||||
- path: {{ .path }}
|
||||
backend:
|
||||
serviceName: {{ include "ucentralgw.fullname" $root }}-{{ .serviceName }}
|
||||
serviceName: {{ include "owgw.fullname" $root }}-{{ .serviceName }}
|
||||
servicePort: {{ .servicePort }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ template "ucentralgw.fullname" . }}-pvc
|
||||
name: {{ template "owgw.fullname" . }}-pvc
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" . }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" . }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" . }}
|
||||
helm.sh/chart: {{ include "owgw.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- with .Values.persistence.annotations }}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
labels:
|
||||
app.kuberentes.io/name: {{ include "ucentralgw.name" . }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" . }}
|
||||
app.kuberentes.io/name: {{ include "owgw.name" . }}
|
||||
helm.sh/chart: {{ include "owgw.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ include "ucentralgw.fullname" . }}-certs-cas
|
||||
name: {{ include "owgw.fullname" . }}-certs-cas
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
data:
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
labels:
|
||||
app.kuberentes.io/name: {{ include "ucentralgw.name" . }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" . }}
|
||||
app.kuberentes.io/name: {{ include "owgw.name" . }}
|
||||
helm.sh/chart: {{ include "owgw.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ include "ucentralgw.fullname" . }}-certs
|
||||
name: {{ include "owgw.fullname" . }}-certs
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
data:
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
labels:
|
||||
app.kuberentes.io/name: {{ include "ucentralgw.name" . }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" . }}
|
||||
app.kuberentes.io/name: {{ include "owgw.name" . }}
|
||||
helm.sh/chart: {{ include "owgw.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ include "ucentralgw.fullname" . }}-config
|
||||
name: {{ include "owgw.fullname" . }}-config
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
data:
|
||||
ucentralgw.properties: {{ include "ucentralgw.config" . | b64enc }}
|
||||
owgw.properties: {{ include "owgw.config" . | b64enc }}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
labels:
|
||||
app.kuberentes.io/name: {{ include "ucentralgw.name" . }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" . }}
|
||||
app.kuberentes.io/name: {{ include "owgw.name" . }}
|
||||
helm.sh/chart: {{ include "owgw.chart" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
name: {{ include "ucentralgw.fullname" . }}-env
|
||||
name: {{ include "owgw.fullname" . }}-env
|
||||
kind: Secret
|
||||
type: Opaque
|
||||
data:
|
||||
|
||||
@@ -10,11 +10,11 @@ kind: Secret
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
metadata:
|
||||
labels:
|
||||
app.kuberentes.io/name: {{ include "ucentralgw.name" $root }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" $root }}
|
||||
app.kuberentes.io/name: {{ include "owgw.name" $root }}
|
||||
helm.sh/chart: {{ include "owgw.chart" $root }}
|
||||
app.kubernetes.io/instance: {{ $root.Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ $root.Release.Service }}
|
||||
name: {{ include "ucentralgw.fullname" $root }}-{{ $image }}-regcred
|
||||
name: {{ include "owgw.fullname" $root }}-{{ $image }}-regcred
|
||||
data:
|
||||
.dockerconfigjson: {{ template "imagePullSecret" $imageValue.regcred }}
|
||||
{{- end }}
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "ucentralgw.fullname" $root }}-{{ $service }}
|
||||
name: {{ include "owgw.fullname" $root }}-{{ $service }}
|
||||
{{- with $serviceValue.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" $root }}
|
||||
helm.sh/chart: {{ include "ucentralgw.chart" $root }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" $root }}
|
||||
helm.sh/chart: {{ include "owgw.chart" $root }}
|
||||
app.kubernetes.io/instance: {{ $root.Release.Name }}
|
||||
app.kubernetes.io/managed-by: {{ $root.Release.Service }}
|
||||
|
||||
@@ -39,7 +39,7 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
selector:
|
||||
app.kubernetes.io/name: {{ include "ucentralgw.name" $root }}
|
||||
app.kubernetes.io/name: {{ include "owgw.name" $root }}
|
||||
app.kubernetes.io/instance: {{ $root.Release.Name }}
|
||||
{{- with $serviceValue.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
|
||||
224
helm/values.yaml
224
helm/values.yaml
@@ -6,9 +6,9 @@ nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
images:
|
||||
ucentralgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/ucentralgw
|
||||
tag: master
|
||||
owgw:
|
||||
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owgw
|
||||
tag: v2.2.0-RC1
|
||||
pullPolicy: Always
|
||||
# regcred:
|
||||
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
|
||||
@@ -16,7 +16,7 @@ images:
|
||||
# password: password
|
||||
|
||||
services:
|
||||
ucentralgw:
|
||||
owgw:
|
||||
type: LoadBalancer
|
||||
ports:
|
||||
websocket:
|
||||
@@ -37,7 +37,7 @@ services:
|
||||
protocol: TCP
|
||||
|
||||
checks:
|
||||
ucentralgw:
|
||||
owgw:
|
||||
liveness:
|
||||
httpGet:
|
||||
path: /
|
||||
@@ -57,7 +57,7 @@ ingresses:
|
||||
- restapi.chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
serviceName: ucentralgw
|
||||
serviceName: owgw
|
||||
servicePort: restapi
|
||||
fileuploader:
|
||||
enabled: false
|
||||
@@ -68,34 +68,34 @@ ingresses:
|
||||
- fileuploader.chart-example.local
|
||||
paths:
|
||||
- path: /
|
||||
serviceName: ucentralgw
|
||||
serviceName: owgw
|
||||
servicePort: fileuploader
|
||||
|
||||
volumes:
|
||||
ucentralgw:
|
||||
owgw:
|
||||
- name: config
|
||||
mountPath: /ucentralgw-data/ucentralgw.properties
|
||||
subPath: ucentralgw.properties
|
||||
mountPath: /owgw-data/owgw.properties
|
||||
subPath: owgw.properties
|
||||
# Template below will be rendered in template
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ include "ucentralgw.fullname" . }}-config
|
||||
secretName: {{ include "owgw.fullname" . }}-config
|
||||
- name: certs
|
||||
mountPath: /ucentralgw-data/certs
|
||||
mountPath: /owgw-data/certs
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ include "ucentralgw.fullname" . }}-certs
|
||||
secretName: {{ include "owgw.fullname" . }}-certs
|
||||
- name: certs-cas
|
||||
mountPath: /ucentralgw-data/certs/cas
|
||||
mountPath: /owgw-data/certs/cas
|
||||
volumeDefinition: |
|
||||
secret:
|
||||
secretName: {{ include "ucentralgw.fullname" . }}-certs-cas
|
||||
secretName: {{ include "owgw.fullname" . }}-certs-cas
|
||||
# Change this if you want to use another volume type
|
||||
- name: persist
|
||||
mountPath: /ucentralgw-data/persist
|
||||
mountPath: /owgw-data/persist
|
||||
volumeDefinition: |
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ template "ucentralgw.fullname" . }}-pvc
|
||||
claimName: {{ template "owgw.fullname" . }}-pvc
|
||||
|
||||
resources: {}
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
@@ -109,6 +109,9 @@ resources: {}
|
||||
# cpu: 100m
|
||||
# memory: 128Mi
|
||||
|
||||
securityContext:
|
||||
fsGroup: 101
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
@@ -125,8 +128,8 @@ persistence:
|
||||
|
||||
# Application
|
||||
public_env_variables:
|
||||
UCENTRALGW_ROOT: /ucentralgw-data
|
||||
UCENTRALGW_CONFIG: /ucentralgw-data
|
||||
OWGW_ROOT: /owgw-data
|
||||
OWGW_CONFIG: /owgw-data
|
||||
|
||||
secret_env_variables: {}
|
||||
|
||||
@@ -134,54 +137,54 @@ configProperties:
|
||||
# -> Public part
|
||||
# Websocket
|
||||
ucentral.websocket.host.0.backlog: 500
|
||||
ucentral.websocket.host.0.rootca: $UCENTRALGW_ROOT/certs/root.pem
|
||||
ucentral.websocket.host.0.issuer: $UCENTRALGW_ROOT/certs/issuer.pem
|
||||
ucentral.websocket.host.0.cert: $UCENTRALGW_ROOT/certs/websocket-cert.pem
|
||||
ucentral.websocket.host.0.key: $UCENTRALGW_ROOT/certs/websocket-key.pem
|
||||
ucentral.websocket.host.0.clientcas: $UCENTRALGW_ROOT/certs/clientcas.pem
|
||||
ucentral.websocket.host.0.cas: $UCENTRALGW_ROOT/certs/cas
|
||||
ucentral.websocket.host.0.rootca: $OWGW_ROOT/certs/root.pem
|
||||
ucentral.websocket.host.0.issuer: $OWGW_ROOT/certs/issuer.pem
|
||||
ucentral.websocket.host.0.cert: $OWGW_ROOT/certs/websocket-cert.pem
|
||||
ucentral.websocket.host.0.key: $OWGW_ROOT/certs/websocket-key.pem
|
||||
ucentral.websocket.host.0.clientcas: $OWGW_ROOT/certs/clientcas.pem
|
||||
ucentral.websocket.host.0.cas: $OWGW_ROOT/certs/cas
|
||||
ucentral.websocket.host.0.address: "*"
|
||||
ucentral.websocket.host.0.port: 15002
|
||||
ucentral.websocket.host.0.security: strict
|
||||
ucentral.websocket.maxreactors: 20
|
||||
# REST API
|
||||
ucentral.restapi.host.0.backlog: 100
|
||||
ucentral.restapi.host.0.security: relaxed
|
||||
ucentral.restapi.host.0.rootca: $UCENTRALGW_ROOT/certs/restapi-ca.pem
|
||||
ucentral.restapi.host.0.address: "*"
|
||||
ucentral.restapi.host.0.port: 16002
|
||||
ucentral.restapi.host.0.cert: $UCENTRALGW_ROOT/certs/restapi-cert.pem
|
||||
ucentral.restapi.host.0.key: $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.internal.restapi.host.0.backlog: 100
|
||||
ucentral.internal.restapi.host.0.security: relaxed
|
||||
ucentral.internal.restapi.host.0.rootca: $UCENTRALGW_ROOT/certs/restapi-ca.pem
|
||||
ucentral.internal.restapi.host.0.address: "*"
|
||||
ucentral.internal.restapi.host.0.port: 17002
|
||||
ucentral.internal.restapi.host.0.cert: $UCENTRALGW_ROOT/certs/restapi-cert.pem
|
||||
ucentral.internal.restapi.host.0.key: $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.restapi.host.0.backlog: 100
|
||||
openwifi.restapi.host.0.security: relaxed
|
||||
openwifi.restapi.host.0.rootca: $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.restapi.host.0.address: "*"
|
||||
openwifi.restapi.host.0.port: 16002
|
||||
openwifi.restapi.host.0.cert: $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.restapi.host.0.key: $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.internal.restapi.host.0.backlog: 100
|
||||
openwifi.internal.restapi.host.0.security: relaxed
|
||||
openwifi.internal.restapi.host.0.rootca: $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.internal.restapi.host.0.address: "*"
|
||||
openwifi.internal.restapi.host.0.port: 17002
|
||||
openwifi.internal.restapi.host.0.cert: $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.internal.restapi.host.0.key: $OWGW_ROOT/certs/restapi-key.pem
|
||||
# File uploader
|
||||
ucentral.fileuploader.host.0.backlog: 100
|
||||
ucentral.fileuploader.host.0.rootca: $UCENTRALGW_ROOT/certs/restapi-ca.pem
|
||||
ucentral.fileuploader.host.0.security: relaxed
|
||||
ucentral.fileuploader.host.0.address: "*"
|
||||
ucentral.fileuploader.host.0.name: localhost
|
||||
ucentral.fileuploader.host.0.port: 16003
|
||||
ucentral.fileuploader.host.0.cert: $UCENTRALGW_ROOT/certs/restapi-cert.pem
|
||||
ucentral.fileuploader.host.0.key: $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.fileuploader.path: $UCENTRALGW_ROOT/uploads
|
||||
ucentral.fileuploader.maxsize: 10000
|
||||
openwifi.fileuploader.host.0.backlog: 100
|
||||
openwifi.fileuploader.host.0.rootca: $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.fileuploader.host.0.security: relaxed
|
||||
openwifi.fileuploader.host.0.address: "*"
|
||||
openwifi.fileuploader.host.0.name: localhost
|
||||
openwifi.fileuploader.host.0.port: 16003
|
||||
openwifi.fileuploader.host.0.cert: $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.fileuploader.host.0.key: $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.fileuploader.path: $OWGW_ROOT/uploads
|
||||
openwifi.fileuploader.maxsize: 10000
|
||||
# Auto provisioning
|
||||
ucentral.autoprovisioning: "true"
|
||||
ucentral.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
ucentral.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
|
||||
ucentral.devicetypes.2: IOT:esp32
|
||||
openwifi.autoprovisioning: "true"
|
||||
openwifi.devicetypes.0: AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1: SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2: IOT:esp32
|
||||
oui.download.uri: https://linuxnet.ca/ieee/oui.txt
|
||||
firmware.autoupdate.policy.default: auto
|
||||
# Callback
|
||||
ucentral.callback.enable: "false"
|
||||
ucentral.callback.0.local: localhost:16001
|
||||
ucentral.callback.0.remote: localhost:15055
|
||||
ucentral.callback.0.topics: ucentralfws
|
||||
openwifi.callback.enable: "false"
|
||||
openwifi.callback.0.local: localhost:16001
|
||||
openwifi.callback.0.remote: localhost:15055
|
||||
openwifi.callback.0.topics: owfws
|
||||
# rtty
|
||||
rtty.enabled: "true"
|
||||
rtty.server: localhost
|
||||
@@ -192,12 +195,12 @@ configProperties:
|
||||
alb.enable: "true"
|
||||
alb.port: 16102
|
||||
# Kafka
|
||||
ucentral.kafka.enable: "false"
|
||||
ucentral.kafka.group.id: gateway
|
||||
ucentral.kafka.client.id: gateway1
|
||||
ucentral.kafka.brokerlist: localhost:9092
|
||||
ucentral.kafka.auto.commit: false
|
||||
ucentral.kafka.queue.buffering.max.ms: 50
|
||||
openwifi.kafka.enable: "false"
|
||||
openwifi.kafka.group.id: gateway
|
||||
openwifi.kafka.client.id: gateway1
|
||||
openwifi.kafka.brokerlist: localhost:9092
|
||||
openwifi.kafka.auto.commit: false
|
||||
openwifi.kafka.queue.buffering.max.ms: 50
|
||||
# Storage
|
||||
storage.type: sqlite # (sqlite|postgresql|mysql|odbc)
|
||||
## SQLite
|
||||
@@ -208,31 +211,31 @@ configProperties:
|
||||
storage.type.postgresql.maxsessions: 64
|
||||
storage.type.postgresql.idletime: 60
|
||||
storage.type.postgresql.host: localhost
|
||||
storage.type.postgresql.database: ucentral
|
||||
storage.type.postgresql.database: owgw
|
||||
storage.type.postgresql.port: 5432
|
||||
storage.type.postgresql.connectiontimeout: 60
|
||||
## MySQL
|
||||
storage.type.mysql.maxsessions: 64
|
||||
storage.type.mysql.idletime: 60
|
||||
storage.type.mysql.host: localhost
|
||||
storage.type.mysql.database: ucentral
|
||||
storage.type.mysql.database: owgw
|
||||
storage.type.mysql.port: 3306
|
||||
storage.type.mysql.connectiontimeout: 60
|
||||
# System
|
||||
ucentral.service.key: $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.system.data: $UCENTRALGW_ROOT/persist
|
||||
ucentral.system.debug: "true"
|
||||
ucentral.system.uri.private: https://localhost:17002
|
||||
ucentral.system.uri.public: https://localhost:16002
|
||||
ucentral.system.commandchannel: /tmp/app_ucentralgw
|
||||
openwifi.service.key: $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.system.data: $OWGW_ROOT/persist
|
||||
openwifi.system.debug: "true"
|
||||
openwifi.system.uri.private: https://localhost:17002
|
||||
openwifi.system.uri.public: https://localhost:16002
|
||||
openwifi.system.commandchannel: /tmp/app_owgw
|
||||
# Logging
|
||||
logging.formatters.f1.class: PatternFormatter
|
||||
logging.formatters.f1.pattern: "%s: [%p] %t"
|
||||
logging.formatters.f1.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t"
|
||||
logging.formatters.f1.times: UTC
|
||||
logging.channels.c1.class: ConsoleChannel
|
||||
logging.channels.c1.formatter: f1
|
||||
logging.channels.c2.class: FileChannel
|
||||
logging.channels.c2.path: /tmp/log_ucentralgw
|
||||
logging.channels.c2.path: /tmp/log_owgw
|
||||
logging.channels.c2.formatter.class: PatternFormatter
|
||||
logging.channels.c2.formatter.pattern: "%Y-%m-%d %H:%M:%S %s: [%p] %t"
|
||||
logging.channels.c2.rotation: "20 M"
|
||||
@@ -240,21 +243,21 @@ configProperties:
|
||||
logging.channels.c2.purgeCount: 20
|
||||
logging.channels.c3.class: ConsoleChannel
|
||||
logging.channels.c3.pattern: "%s: [%p] %t"
|
||||
logging.loggers.root.channel: c2
|
||||
logging.loggers.root.channel: c1
|
||||
logging.loggers.root.level: debug
|
||||
|
||||
# -> Secret part
|
||||
# Websocket
|
||||
ucentral.websocket.host.0.key.password: mypassword
|
||||
# REST API
|
||||
ucentral.restapi.host.0.key.password: mypassword
|
||||
ucentral.internal.restapi.host.0.key.password: mypassword
|
||||
openwifi.restapi.host.0.key.password: mypassword
|
||||
openwifi.internal.restapi.host.0.key.password: mypassword
|
||||
# File uploader
|
||||
ucentral.fileuploader.host.0.key.password: mypassword
|
||||
openwifi.fileuploader.host.0.key.password: mypassword
|
||||
# Callback
|
||||
ucentral.callback.id: qblat6dfDHxQAZ6yMe6MrypBpgRDhQrhUtTOovOXAKAWU8qOvjjKKiUai4t9hGjA
|
||||
ucentral.callback.0.localkey: t2dEOc88OIxVDb94mw7SLcLocgnCzZzzFoQ4JJv3OCU9UO6Ou5ds5Dh4CfBnHgrk
|
||||
ucentral.callback.0.remotekey: t2dEOc88OIxVDb94mw7SLcLocgnCzZzzFoQ4JJv3OCU9UO6Ou5ds5Dh4CfBnHgrk
|
||||
openwifi.callback.id: qblat6dfDHxQAZ6yMe6MrypBpgRDhQrhUtTOovOXAKAWU8qOvjjKKiUai4t9hGjA
|
||||
openwifi.callback.0.localkey: t2dEOc88OIxVDb94mw7SLcLocgnCzZzzFoQ4JJv3OCU9UO6Ou5ds5Dh4CfBnHgrk
|
||||
openwifi.callback.0.remotekey: t2dEOc88OIxVDb94mw7SLcLocgnCzZzzFoQ4JJv3OCU9UO6Ou5ds5Dh4CfBnHgrk
|
||||
# rtty
|
||||
rtty.token: 96181c567b4d0d98c50f127230068fa8
|
||||
# Storage
|
||||
@@ -425,3 +428,64 @@ certsCAs:
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# PostgreSQL (https://github.com/bitnami/charts/tree/master/bitnami/postgresql)
|
||||
postgresql:
|
||||
enabled: false
|
||||
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: bitnami/postgresql
|
||||
tag: 11.13.0-debian-10-r0
|
||||
|
||||
postgresqlPostgresPassword: "rootPassword"
|
||||
postgresqlUsername: stephb
|
||||
postgresqlPassword: snoopy99
|
||||
postgresqlDatabase: owgw
|
||||
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: ""
|
||||
size: 8Gi
|
||||
|
||||
# MySQL (https://github.com/bitnami/charts/tree/master/bitnami/mysql)
|
||||
mysql:
|
||||
enabled: false
|
||||
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: bitnami/mysql
|
||||
tag: 8.0.26-debian-10-r10
|
||||
|
||||
auth:
|
||||
rootPassword: rootPassword
|
||||
database: owgw
|
||||
username: stephb
|
||||
password: snoopy99
|
||||
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: ""
|
||||
size: 8Gi
|
||||
|
||||
# MariaDB (https://github.com/bitnami/charts/tree/master/bitnami/mariadb)
|
||||
mariadb:
|
||||
enabled: false
|
||||
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: bitnami/mariadb
|
||||
tag: 10.5.12-debian-10-r0
|
||||
|
||||
auth:
|
||||
rootPassword: rootPassword
|
||||
database: owgw
|
||||
username: stephb
|
||||
password: snoopy99
|
||||
|
||||
primary:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClass: ""
|
||||
size: 8Gi
|
||||
|
||||
@@ -91,6 +91,9 @@ components:
|
||||
location:
|
||||
type: string
|
||||
format: uuid
|
||||
venue:
|
||||
type: string
|
||||
format: uuid
|
||||
serialNumber:
|
||||
type: string
|
||||
deviceType:
|
||||
@@ -180,6 +183,12 @@ components:
|
||||
rxBytes:
|
||||
type: integer
|
||||
format: int64
|
||||
associations_2G:
|
||||
type: integer
|
||||
format: int64
|
||||
associations_5G:
|
||||
type: integer
|
||||
format: int64
|
||||
devicePassword:
|
||||
type: string
|
||||
lastContact:
|
||||
@@ -248,6 +257,12 @@ components:
|
||||
format: int64
|
||||
firmware:
|
||||
type: string
|
||||
associations_2G:
|
||||
type: integer
|
||||
format: int64
|
||||
associations_5G:
|
||||
type: integer
|
||||
format: int64
|
||||
verifiedCertificate:
|
||||
type: string
|
||||
enum:
|
||||
@@ -584,6 +599,12 @@ components:
|
||||
DeviceDashboard:
|
||||
type: object
|
||||
properties:
|
||||
snapshot:
|
||||
type: integer
|
||||
format: int64
|
||||
numberOfDevices:
|
||||
type: integer
|
||||
format: int64
|
||||
commands:
|
||||
$ref: '#/components/schemas/TagIntPairList'
|
||||
upTimes:
|
||||
@@ -610,6 +631,40 @@ components:
|
||||
$ref: '#/components/schemas/TagIntPairList'
|
||||
lastContact:
|
||||
$ref: '#/components/schemas/TagIntPairList'
|
||||
associations:
|
||||
$ref: '#/components/schemas/TagIntPairList'
|
||||
|
||||
TelemetryStreamRequest:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
interval:
|
||||
type: integer
|
||||
example:
|
||||
0 - means to stop streaming, values 1-120 in seconds.
|
||||
types:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
example:
|
||||
only valid when terminating a stream
|
||||
|
||||
TelemetryStreamResponse:
|
||||
type: object
|
||||
properties:
|
||||
serialNumber:
|
||||
type: string
|
||||
uuid:
|
||||
type: string
|
||||
format: uuid
|
||||
uri:
|
||||
type: string
|
||||
format: uri
|
||||
example:
|
||||
wss://host.domain:port/endpoint
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
@@ -696,6 +751,107 @@ components:
|
||||
note:
|
||||
type: string
|
||||
|
||||
SystemInfoResults:
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
uptime:
|
||||
type: integer
|
||||
format: integer64
|
||||
start:
|
||||
type: integer
|
||||
format: integer64
|
||||
os:
|
||||
type: string
|
||||
processors:
|
||||
type: integer
|
||||
hostname:
|
||||
type: string
|
||||
certificates:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
filename:
|
||||
type: string
|
||||
expires:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
SystemCommandSetLogLevel:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
enum:
|
||||
- setloglevel
|
||||
subsystems:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TagValuePair'
|
||||
|
||||
SystemCommandReload:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
enum:
|
||||
- reload
|
||||
subsystems:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: these are the SubSystems names retrieve with the GetSubSystemsNamesResult.
|
||||
|
||||
SystemCommandGetLogLevels:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
enum:
|
||||
- getloglevels
|
||||
|
||||
SystemGetLogLevelsResult:
|
||||
type: object
|
||||
properties:
|
||||
taglist:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TagValuePair'
|
||||
|
||||
SystemCommandGetLogLevelNames:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
enum:
|
||||
- getloglevelnames
|
||||
|
||||
SystemCommandGetSubsystemNames:
|
||||
type: object
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
enum:
|
||||
- getsubsystemnames
|
||||
|
||||
SystemCommandGetLogLevelNamesResult:
|
||||
type: object
|
||||
properties:
|
||||
list:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
SystemGetSubSystemNemesResult:
|
||||
type: object
|
||||
properties:
|
||||
taglist:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TagValuePair'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## End of uCentral system wide values
|
||||
@@ -852,6 +1008,7 @@ paths:
|
||||
name: countOnly
|
||||
schema:
|
||||
type: boolean
|
||||
example: countOnly=true
|
||||
- in: query
|
||||
description: Return extra information with the device information
|
||||
name: deviceWithStatus
|
||||
@@ -950,7 +1107,7 @@ paths:
|
||||
format: int64
|
||||
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: Successfully deleted commands for the device.
|
||||
content:
|
||||
application/json:
|
||||
@@ -1001,7 +1158,7 @@ paths:
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: Delete command success
|
||||
content:
|
||||
application/json:
|
||||
@@ -1096,7 +1253,7 @@ paths:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
@@ -1165,6 +1322,11 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- in: query
|
||||
name: validateOnly
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
requestBody:
|
||||
description: Information used to create the new device
|
||||
content:
|
||||
@@ -1224,7 +1386,7 @@ paths:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
@@ -1319,7 +1481,7 @@ paths:
|
||||
format: int64
|
||||
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: Successfully deleted logs for the device.
|
||||
content:
|
||||
application/json:
|
||||
@@ -1416,7 +1578,7 @@ paths:
|
||||
required: false
|
||||
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: Successfully deleted health checks for the device.
|
||||
content:
|
||||
application/json:
|
||||
@@ -1463,7 +1625,7 @@ paths:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: List of logs for this device
|
||||
content:
|
||||
application/json:
|
||||
@@ -1568,7 +1730,7 @@ paths:
|
||||
required: false
|
||||
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: Array of statistics for this device
|
||||
content:
|
||||
application/json:
|
||||
@@ -1837,7 +1999,7 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/eventrequest:
|
||||
/device/{serialNumber}/eventqueue:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
@@ -1863,6 +2025,32 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/device/{serialNumber}/telemetry:
|
||||
post:
|
||||
tags:
|
||||
- Commands
|
||||
summary: Request a telemetry stream
|
||||
operationId: eventTelemetryStreamRequest
|
||||
parameters:
|
||||
- in: path
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
requestBody:
|
||||
description: Message request details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TelemetryStreamRequest'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/TelemetryStreamResponse'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/ouis:
|
||||
get:
|
||||
tags:
|
||||
@@ -1956,7 +2144,7 @@ paths:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
@@ -2033,7 +2221,7 @@ paths:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
@@ -2059,7 +2247,6 @@ paths:
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
##
|
||||
#########################################################################################
|
||||
|
||||
/system:
|
||||
post:
|
||||
tags:
|
||||
@@ -2071,14 +2258,22 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SystemCommandDetails'
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemCommandSetLogLevel'
|
||||
- $ref: '#/components/schemas/SystemCommandReload'
|
||||
- $ref: '#/components/schemas/SystemCommandGetLogLevels'
|
||||
- $ref: '#/components/schemas/SystemCommandGetLogLevelNames'
|
||||
- $ref: '#/components/schemas/SystemCommandGetSubsystemNames'
|
||||
responses:
|
||||
200:
|
||||
description: Successfull command execution
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SystemCommandResults'
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemGetLogLevelsResult'
|
||||
- $ref: '#/components/schemas/SystemCommandGetLogLevelNamesResult'
|
||||
- $ref: '#/components/schemas/SystemGetSubSystemNemesResult'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
@@ -2095,8 +2290,7 @@ paths:
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- version
|
||||
- times
|
||||
- info
|
||||
required: true
|
||||
|
||||
responses:
|
||||
@@ -2105,7 +2299,8 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TagValuePair'
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/SystemInfoResults'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
@@ -4,12 +4,12 @@
|
||||
# address of one of your interfaces
|
||||
#
|
||||
ucentral.websocket.host.0.backlog = 500
|
||||
ucentral.websocket.host.0.rootca = $UCENTRALGW_ROOT/certs/root.pem
|
||||
ucentral.websocket.host.0.issuer = $UCENTRALGW_ROOT/certs/issuer.pem
|
||||
ucentral.websocket.host.0.cert = $UCENTRALGW_ROOT/certs/websocket-cert.pem
|
||||
ucentral.websocket.host.0.key = $UCENTRALGW_ROOT/certs/websocket-key.pem
|
||||
ucentral.websocket.host.0.clientcas = $UCENTRALGW_ROOT/certs/clientcas.pem
|
||||
ucentral.websocket.host.0.cas = $UCENTRALGW_ROOT/certs/cas
|
||||
ucentral.websocket.host.0.rootca = $OWGW_ROOT/certs/root.pem
|
||||
ucentral.websocket.host.0.issuer = $OWGW_ROOT/certs/issuer.pem
|
||||
ucentral.websocket.host.0.cert = $OWGW_ROOT/certs/websocket-cert.pem
|
||||
ucentral.websocket.host.0.key = $OWGW_ROOT/certs/websocket-key.pem
|
||||
ucentral.websocket.host.0.clientcas = $OWGW_ROOT/certs/clientcas.pem
|
||||
ucentral.websocket.host.0.cas = $OWGW_ROOT/certs/cas
|
||||
ucentral.websocket.host.0.address = *
|
||||
ucentral.websocket.host.0.port = 15002
|
||||
ucentral.websocket.host.0.security = strict
|
||||
@@ -19,60 +19,61 @@ ucentral.websocket.maxreactors = 20
|
||||
#
|
||||
# REST API access
|
||||
#
|
||||
ucentral.restapi.host.0.backlog = 100
|
||||
ucentral.restapi.host.0.security = relaxed
|
||||
ucentral.restapi.host.0.rootca = $UCENTRALGW_ROOT/certs/restapi-ca.pem
|
||||
ucentral.restapi.host.0.address = *
|
||||
ucentral.restapi.host.0.port = 16002
|
||||
ucentral.restapi.host.0.cert = $UCENTRALGW_ROOT/certs/restapi-cert.pem
|
||||
ucentral.restapi.host.0.key = $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.restapi.host.0.key.password = mypassword
|
||||
openwifi.restapi.host.0.backlog = 100
|
||||
openwifi.restapi.host.0.security = relaxed
|
||||
openwifi.restapi.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.restapi.host.0.address = *
|
||||
openwifi.restapi.host.0.port = 16002
|
||||
openwifi.restapi.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.restapi.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.restapi.host.0.key.password = mypassword
|
||||
|
||||
ucentral.internal.restapi.host.0.backlog = 100
|
||||
ucentral.internal.restapi.host.0.security = relaxed
|
||||
ucentral.internal.restapi.host.0.rootca = $UCENTRALGW_ROOT/certs/restapi-ca.pem
|
||||
ucentral.internal.restapi.host.0.address = *
|
||||
ucentral.internal.restapi.host.0.port = 17002
|
||||
ucentral.internal.restapi.host.0.cert = $UCENTRALGW_ROOT/certs/restapi-cert.pem
|
||||
ucentral.internal.restapi.host.0.key = $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.internal.restapi.host.0.key.password = mypassword
|
||||
openwifi.internal.restapi.host.0.backlog = 100
|
||||
openwifi.internal.restapi.host.0.security = relaxed
|
||||
openwifi.internal.restapi.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.internal.restapi.host.0.address = *
|
||||
openwifi.internal.restapi.host.0.port = 17002
|
||||
openwifi.internal.restapi.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.internal.restapi.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.internal.restapi.host.0.key.password = mypassword
|
||||
|
||||
#
|
||||
# Used to upload files to the service.
|
||||
# You should replace the 'name' vaalue with the IP address of your gateway or an FQDN
|
||||
# that your devices can reach
|
||||
#
|
||||
ucentral.fileuploader.host.0.backlog = 100
|
||||
ucentral.fileuploader.host.0.rootca = $UCENTRALGW_ROOT/certs/restapi-ca.pem
|
||||
ucentral.fileuploader.host.0.security = relaxed
|
||||
ucentral.fileuploader.host.0.address = *
|
||||
ucentral.fileuploader.host.0.name = ucentral.dpaas.arilia.com
|
||||
ucentral.fileuploader.host.0.port = 16003
|
||||
ucentral.fileuploader.host.0.cert = $UCENTRALGW_ROOT/certs/restapi-cert.pem
|
||||
ucentral.fileuploader.host.0.key = $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.fileuploader.host.0.key.password = mypassword
|
||||
ucentral.fileuploader.path = $UCENTRALGW_ROOT/uploads
|
||||
ucentral.fileuploader.maxsize = 10000
|
||||
openwifi.fileuploader.host.0.backlog = 100
|
||||
openwifi.fileuploader.host.0.rootca = $OWGW_ROOT/certs/restapi-ca.pem
|
||||
openwifi.fileuploader.host.0.security = relaxed
|
||||
openwifi.fileuploader.host.0.address = *
|
||||
openwifi.fileuploader.host.0.name = ucentral.dpaas.arilia.com
|
||||
openwifi.fileuploader.host.0.port = 16003
|
||||
openwifi.fileuploader.host.0.cert = $OWGW_ROOT/certs/restapi-cert.pem
|
||||
openwifi.fileuploader.host.0.key = $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.fileuploader.host.0.key.password = mypassword
|
||||
openwifi.fileuploader.path = $OWGW_ROOT/uploads
|
||||
openwifi.fileuploader.maxsize = 10000
|
||||
openwifi.fileuploader.uri = https://ucentral.dpaas.arilia.com:16003
|
||||
|
||||
#
|
||||
# Generic section that all microservices must have
|
||||
#
|
||||
ucentral.service.key = $UCENTRALGW_ROOT/certs/restapi-key.pem
|
||||
ucentral.service.key.password = mypassword
|
||||
ucentral.system.data = $UCENTRALGW_ROOT/data
|
||||
ucentral.system.debug = true
|
||||
ucentral.system.uri.private = https://localhost:17002
|
||||
ucentral.system.uri.public = https://local.dpaas.arilia.com:16002
|
||||
ucentral.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
ucentral.system.commandchannel = /tmp/app.ucentralgw
|
||||
openwifi.service.key = $OWGW_ROOT/certs/restapi-key.pem
|
||||
openwifi.service.key.password = mypassword
|
||||
openwifi.system.data = $OWGW_ROOT/data
|
||||
openwifi.system.debug = true
|
||||
openwifi.system.uri.private = https://localhost:17002
|
||||
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16002
|
||||
openwifi.system.uri.ui = https://ucentral-ui.arilia.com
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralgw
|
||||
|
||||
#
|
||||
# Gateway Microservice Specific Section
|
||||
#
|
||||
ucentral.autoprovisioning = true
|
||||
ucentral.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
ucentral.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
|
||||
ucentral.devicetypes.2 = IOT:esp32
|
||||
openwifi.autoprovisioning = true
|
||||
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2 = IOT:esp32
|
||||
oui.download.uri = https://linuxnet.ca/ieee/oui.txt
|
||||
firmware.autoupdate.policy.default = auto
|
||||
|
||||
@@ -98,13 +99,12 @@ alb.port = 16102
|
||||
#
|
||||
# Kafka
|
||||
#
|
||||
ucentral.kafka.group.id = gateway
|
||||
ucentral.kafka.client.id = gateway1
|
||||
ucentral.kafka.enable = true
|
||||
# ucentral.kafka.brokerlist = a1.arilia.com:9092
|
||||
ucentral.kafka.brokerlist = debfarm1-node-c.arilia.com:9092
|
||||
ucentral.kafka.auto.commit = false
|
||||
ucentral.kafka.queue.buffering.max.ms = 50
|
||||
openwifi.kafka.group.id = gateway
|
||||
openwifi.kafka.client.id = gateway1
|
||||
openwifi.kafka.enable = true
|
||||
openwifi.kafka.brokerlist = a1.arilia.com:9092
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
|
||||
#
|
||||
# This section select which form of persistence you need
|
||||
@@ -164,7 +164,7 @@ logging.channels.c1.formatter = f1
|
||||
|
||||
# This is where the logs will be written. This path MUST exist
|
||||
logging.channels.c2.class = FileChannel
|
||||
logging.channels.c2.path = $UCENTRALGW_ROOT/logs/log
|
||||
logging.channels.c2.path = $OWGW_ROOT/logs/log
|
||||
logging.channels.c2.formatter.class = PatternFormatter
|
||||
logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
|
||||
logging.channels.c2.rotation = 20 M
|
||||
189
owgw.properties.tmpl
Normal file
189
owgw.properties.tmpl
Normal file
@@ -0,0 +1,189 @@
|
||||
#
|
||||
# uCentral protocol server for devices. This is where you point
|
||||
# all your devices. You can replace the * for address by the specific
|
||||
# address of one of your interfaces
|
||||
#
|
||||
ucentral.websocket.host.0.backlog = 500
|
||||
ucentral.websocket.host.0.rootca = ${WEBSOCKET_HOST_ROOTCA}
|
||||
ucentral.websocket.host.0.issuer = ${WEBSOCKET_HOST_ISSUER}
|
||||
ucentral.websocket.host.0.cert = ${WEBSOCKET_HOST_CERT}
|
||||
ucentral.websocket.host.0.key = ${WEBSOCKET_HOST_KEY}
|
||||
ucentral.websocket.host.0.clientcas = ${WEBSOCKET_HOST_CLIENTCAS}
|
||||
ucentral.websocket.host.0.cas = ${WEBSOCKET_HOST_CAS}
|
||||
ucentral.websocket.host.0.address = *
|
||||
ucentral.websocket.host.0.port = ${WEBSOCKET_HOST_PORT}
|
||||
ucentral.websocket.host.0.security = strict
|
||||
ucentral.websocket.host.0.key.password = ${WEBSOCKET_HOST_KEY_PASSWORD}
|
||||
ucentral.websocket.maxreactors = 20
|
||||
|
||||
#
|
||||
# REST API access
|
||||
#
|
||||
openwifi.restapi.host.0.backlog = 100
|
||||
openwifi.restapi.host.0.security = relaxed
|
||||
openwifi.restapi.host.0.rootca = ${RESTAPI_HOST_ROOTCA}
|
||||
openwifi.restapi.host.0.address = *
|
||||
openwifi.restapi.host.0.port = ${RESTAPI_HOST_PORT}
|
||||
openwifi.restapi.host.0.cert = ${RESTAPI_HOST_CERT}
|
||||
openwifi.restapi.host.0.key = ${RESTAPI_HOST_KEY}
|
||||
openwifi.restapi.host.0.key.password = ${RESTAPI_HOST_KEY_PASSWORD}
|
||||
|
||||
openwifi.internal.restapi.host.0.backlog = 100
|
||||
openwifi.internal.restapi.host.0.security = relaxed
|
||||
openwifi.internal.restapi.host.0.rootca = ${INTERNAL_RESTAPI_HOST_ROOTCA}
|
||||
openwifi.internal.restapi.host.0.address = *
|
||||
openwifi.internal.restapi.host.0.port = ${INTERNAL_RESTAPI_HOST_PORT}
|
||||
openwifi.internal.restapi.host.0.cert = ${INTERNAL_RESTAPI_HOST_CERT}
|
||||
openwifi.internal.restapi.host.0.key = ${INTERNAL_RESTAPI_HOST_KEY}
|
||||
openwifi.internal.restapi.host.0.key.password = ${INTERNAL_RESTAPI_HOST_KEY_PASSWORD}
|
||||
|
||||
#
|
||||
# Used to upload files to the service.
|
||||
# You should replace the 'name' vaalue with the IP address of your gateway or an FQDN
|
||||
# that your devices can reach
|
||||
#
|
||||
openwifi.fileuploader.host.0.backlog = 100
|
||||
openwifi.fileuploader.host.0.rootca = ${FILEUPLOADER_HOST_ROOTCA}
|
||||
openwifi.fileuploader.host.0.security = relaxed
|
||||
openwifi.fileuploader.host.0.address = *
|
||||
openwifi.fileuploader.host.0.name = ${FILEUPLOADER_HOST_NAME}
|
||||
openwifi.fileuploader.host.0.port = ${FILEUPLOADER_HOST_PORT}
|
||||
openwifi.fileuploader.host.0.cert = ${FILEUPLOADER_HOST_CERT}
|
||||
openwifi.fileuploader.host.0.key = ${FILEUPLOADER_HOST_KEY}
|
||||
openwifi.fileuploader.host.0.key.password = ${FILEUPLOADER_HOST_KEY_PASSWORD}
|
||||
openwifi.fileuploader.path = ${FILEUPLOADER_PATH}
|
||||
openwifi.fileuploader.uri = ${FILEUPLOADER_URI}
|
||||
openwifi.fileuploader.maxsize = 10000
|
||||
|
||||
#
|
||||
# Generic section that all microservices must have
|
||||
#
|
||||
openwifi.service.key = ${SERVICE_KEY}
|
||||
openwifi.service.key.password = ${SERVICE_KEY_PASSWORD}
|
||||
openwifi.system.data = ${SYSTEM_DATA}
|
||||
openwifi.system.debug = true
|
||||
openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
|
||||
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
|
||||
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
|
||||
openwifi.system.commandchannel = /tmp/app.ucentralgw
|
||||
|
||||
#
|
||||
# Gateway Microservice Specific Section
|
||||
#
|
||||
openwifi.autoprovisioning = true
|
||||
openwifi.devicetypes.0 = AP:linksys_ea8300,edgecore_eap101,linksys_e8450-ubi
|
||||
openwifi.devicetypes.1 = SWITCH:edgecore_ecs4100-12ph
|
||||
openwifi.devicetypes.2 = IOT:esp32
|
||||
oui.download.uri = https://linuxnet.ca/ieee/oui.txt
|
||||
firmware.autoupdate.policy.default = auto
|
||||
|
||||
#
|
||||
# rtty
|
||||
#
|
||||
rtty.enabled = ${RTTY_ENABLED}
|
||||
rtty.server = ${RTTY_SERVER}
|
||||
rtty.port = ${RTTY_PORT}
|
||||
rtty.token = ${RTTY_TOKEN}
|
||||
rtty.timeout = ${RTTY_TIMEOUT}
|
||||
rtty.viewport = ${RTTY_VIEWPORT}
|
||||
|
||||
#############################
|
||||
# Generic information for all micro services
|
||||
#############################
|
||||
#
|
||||
# NLB Support
|
||||
#
|
||||
alb.enable = true
|
||||
alb.port = 16102
|
||||
|
||||
#
|
||||
# Kafka
|
||||
#
|
||||
openwifi.kafka.group.id = gateway
|
||||
openwifi.kafka.client.id = gateway1
|
||||
openwifi.kafka.enable = ${KAFKA_ENABLE}
|
||||
openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST}
|
||||
openwifi.kafka.auto.commit = false
|
||||
openwifi.kafka.queue.buffering.max.ms = 50
|
||||
|
||||
#
|
||||
# This section select which form of persistence you need
|
||||
# Only one selected at a time. If you select multiple, this service will die if a horrible
|
||||
# death and might make your beer flat.
|
||||
#
|
||||
storage.type = ${STORAGE_TYPE}
|
||||
|
||||
storage.type.sqlite.db = devices.db
|
||||
storage.type.sqlite.idletime = 120
|
||||
storage.type.sqlite.maxsessions = 128
|
||||
|
||||
storage.type.postgresql.maxsessions = 64
|
||||
storage.type.postgresql.idletime = 60
|
||||
storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST}
|
||||
storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME}
|
||||
storage.type.postgresql.password = ${STORAGE_TYPE_POSTGRESQL_PASSWORD}
|
||||
storage.type.postgresql.database = ${STORAGE_TYPE_POSTGRESQL_DATABASE}
|
||||
storage.type.postgresql.port = ${STORAGE_TYPE_POSTGRESQL_PORT}
|
||||
storage.type.postgresql.connectiontimeout = 60
|
||||
|
||||
storage.type.mysql.maxsessions = 64
|
||||
storage.type.mysql.idletime = 60
|
||||
storage.type.mysql.host = ${STORAGE_TYPE_MYSQL_HOST}
|
||||
storage.type.mysql.username = ${STORAGE_TYPE_MYSQL_USERNAME}
|
||||
storage.type.mysql.password = ${STORAGE_TYPE_MYSQL_PASSWORD}
|
||||
storage.type.mysql.database = ${STORAGE_TYPE_MYSQL_DATABASE}
|
||||
storage.type.mysql.port = ${STORAGE_TYPE_MYSQL_PORT}
|
||||
storage.type.mysql.connectiontimeout = 60
|
||||
|
||||
archiver.enabled = true
|
||||
archiver.schedule = 03:00
|
||||
archiver.db.0.name = healthchecks
|
||||
archiver.db.0.keep = 7
|
||||
archiver.db.1.name = statistics
|
||||
archiver.db.1.keep = 7
|
||||
archiver.db.2.name = devicelogs
|
||||
archiver.db.2.keep = 7
|
||||
archiver.db.3.name = commandlist
|
||||
archiver.db.3.keep = 7
|
||||
|
||||
########################################################################
|
||||
########################################################################
|
||||
#
|
||||
# Logging: please leave as is for now.
|
||||
#
|
||||
########################################################################
|
||||
|
||||
logging.formatters.f1.class = PatternFormatter
|
||||
logging.formatters.f1.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
|
||||
logging.formatters.f1.times = UTC
|
||||
logging.channels.c1.class = ConsoleChannel
|
||||
logging.channels.c1.formatter = f1
|
||||
|
||||
# This is where the logs will be written. This path MUST exist
|
||||
logging.channels.c2.class = FileChannel
|
||||
logging.channels.c2.path = $UCENTRALGW_ROOT/logs/log
|
||||
logging.channels.c2.formatter.class = PatternFormatter
|
||||
logging.channels.c2.formatter.pattern = %Y-%m-%d %H:%M:%S %s: [%p] %t
|
||||
logging.channels.c2.rotation = 20 M
|
||||
logging.channels.c2.archive = timestamp
|
||||
logging.channels.c2.purgeCount = 20
|
||||
logging.channels.c3.class = ConsoleChannel
|
||||
logging.channels.c3.pattern = %s: [%p] %t
|
||||
|
||||
# External Channel
|
||||
logging.loggers.root.channel = c1
|
||||
logging.loggers.root.level = debug
|
||||
|
||||
# Inline Channel with PatternFormatter
|
||||
# logging.loggers.l1.name = logger1
|
||||
# logging.loggers.l1.channel.class = ConsoleChannel
|
||||
# logging.loggers.l1.channel.pattern = %s: [%p] %t
|
||||
# logging.loggers.l1.level = information
|
||||
# SplitterChannel
|
||||
# logging.channels.splitter.class = SplitterChannel
|
||||
# logging.channels.splitter.channels = l1,l2
|
||||
# logging.loggers.l2.name = logger2
|
||||
# logging.loggers.l2.channel = splitter
|
||||
|
||||
|
||||
|
||||
22
owgw.service
Normal file
22
owgw.service
Normal file
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=OpenWiFi Gateway Service
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment="OWGW_ROOT=/home/admin/dev/wlan-cloud-ucentralgw"
|
||||
ExecStart=/home/admin/dev/wlan-cloud-ucentralgw/cmake-build/owgw
|
||||
WorkingDirectory=/home/admin/dev/wlan-cloud-ucentralgw
|
||||
# ExecReload=/bin/kill -s HUP $MAINPID
|
||||
User=admin
|
||||
# TimeoutSec=0
|
||||
RestartSec=2
|
||||
Restart=always
|
||||
StartLimitBurst=3
|
||||
# KillMode=process
|
||||
LimitNOFILE=500000
|
||||
LimitNPROC=500000
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
export UCENTRALGW_CONFIG=`pwd`
|
||||
export UCENTRALGW_ROOT=`pwd`
|
||||
export OWGW_CONFIG=`pwd`
|
||||
export OWGW_ROOT=`pwd`
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-06-04.
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALGW_ALBHEALTHCHECKSERVER_H
|
||||
@@ -20,18 +24,18 @@
|
||||
#include "Daemon.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class ALBRequestHandler: public Poco::Net::HTTPRequestHandler
|
||||
/// Return a HTML document with the current date and time.
|
||||
{
|
||||
public:
|
||||
ALBRequestHandler(Poco::Logger & L)
|
||||
explicit ALBRequestHandler(Poco::Logger & L)
|
||||
: Logger_(L)
|
||||
{
|
||||
}
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response)
|
||||
void handleRequest(Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override
|
||||
{
|
||||
Logger_.information(Poco::format("ALB-REQUEST(%s): New ALB request.",Request.clientAddress().toString()));
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
@@ -83,7 +87,7 @@ namespace uCentral {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() {
|
||||
int Start() override {
|
||||
if(Daemon()->ConfigGetBool("alb.enable",false)) {
|
||||
Port_ = (int)Daemon()->ConfigGetInt("alb.port",15015);
|
||||
Socket_ = std::make_unique<Poco::Net::ServerSocket>(Port_);
|
||||
@@ -95,7 +99,7 @@ namespace uCentral {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
void Stop() override {
|
||||
if(Server_)
|
||||
Server_->stop();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-06-30.
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "AuthClient.h"
|
||||
@@ -8,7 +13,7 @@
|
||||
#include "Daemon.h"
|
||||
#include "OpenAPIRequest.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class AuthClient * AuthClient::instance_ = nullptr;
|
||||
|
||||
int AuthClient::Start() {
|
||||
@@ -20,7 +25,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void AuthClient::RemovedCachedToken(const std::string &Token) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
UserCache_.erase(Token);
|
||||
}
|
||||
|
||||
@@ -29,7 +34,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
bool AuthClient::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo ) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto User = UserCache_.find(SessionToken);
|
||||
if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) {
|
||||
@@ -38,7 +43,7 @@ namespace uCentral {
|
||||
} else {
|
||||
Types::StringPairVec QueryData;
|
||||
QueryData.push_back(std::make_pair("token",SessionToken));
|
||||
OpenAPIRequestGet Req(uSERVICE_SECURITY,
|
||||
OpenAPIRequestGet Req( uSERVICE_SECURITY,
|
||||
"/api/v1/validateToken",
|
||||
QueryData,
|
||||
5000);
|
||||
@@ -56,4 +61,33 @@ namespace uCentral {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthClient::IsTokenAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
auto User = UserCache_.find(SessionToken);
|
||||
if(User != UserCache_.end() && !IsTokenExpired(User->second.webtoken)) {
|
||||
UInfo = User->second;
|
||||
return true;
|
||||
} else {
|
||||
Types::StringPairVec QueryData;
|
||||
QueryData.push_back(std::make_pair("token",SessionToken));
|
||||
OpenAPIRequestGet Req(uSERVICE_SECURITY,
|
||||
"/api/v1/validateToken",
|
||||
QueryData,
|
||||
5000);
|
||||
Poco::JSON::Object::Ptr Response;
|
||||
if(Req.Do(Response)==Poco::Net::HTTPResponse::HTTP_OK) {
|
||||
if(Response->has("tokenInfo") && Response->has("userInfo")) {
|
||||
SecurityObjects::UserInfoAndPolicy P;
|
||||
P.from_json(Response);
|
||||
UserCache_[SessionToken] = P;
|
||||
UInfo = P;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,9 @@
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class AuthClient : public SubSystemServer {
|
||||
class AuthClient : public SubSystemServer {
|
||||
public:
|
||||
explicit AuthClient() noexcept:
|
||||
SubSystemServer("Authentication", "AUTH-CLNT", "authentication")
|
||||
@@ -31,12 +31,12 @@ namespace uCentral {
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo );
|
||||
bool IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string &SessionToken, OpenWifi::SecurityObjects::UserInfoAndPolicy & UInfo );
|
||||
void RemovedCachedToken(const std::string &Token);
|
||||
|
||||
bool IsTokenAuthorized(const std::string &Token, SecurityObjects::UserInfoAndPolicy & UInfo);
|
||||
private:
|
||||
static AuthClient *instance_;
|
||||
SecurityObjects::UserInfoCache UserCache_;
|
||||
OpenWifi::SecurityObjects::UserInfoCache UserCache_;
|
||||
};
|
||||
|
||||
inline AuthClient * AuthClient() { return AuthClient::instance(); }
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/File.h"
|
||||
|
||||
namespace uCentral::Config {
|
||||
namespace OpenWifi::Config {
|
||||
|
||||
static std::string DefaultConfiguration;
|
||||
|
||||
@@ -232,7 +232,7 @@ namespace uCentral::Config {
|
||||
}
|
||||
catch ( const Poco::Exception & E )
|
||||
{
|
||||
uCentral::Daemon::instance()->logger().warning(Poco::format("%s: Failed with: %s", std::string(__func__) , E.displayText()));
|
||||
Daemon::instance()->logger().warning(Poco::format("%s: Failed with: %s", std::string(__func__) , E.displayText()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <string>
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
namespace uCentral::Config {
|
||||
namespace OpenWifi::Config {
|
||||
|
||||
class Config {
|
||||
public:
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
#include "CommandChannel.h"
|
||||
#include "AuthClient.h"
|
||||
#include "CommandManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "FileUploader.h"
|
||||
#include "RESTAPI_server.h"
|
||||
#include "StorageService.h"
|
||||
#include "WebSocketServer.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
class CommandChannel * CommandChannel::instance_ = nullptr;
|
||||
|
||||
std::string CommandChannel::ProcessCommand(const std::string &Command) {
|
||||
std::vector<std::string> Tokens{};
|
||||
std::string Result{"OK"};
|
||||
|
||||
|
||||
try {
|
||||
size_t pos, old_pos = 0 ;
|
||||
|
||||
Logger_.notice(Poco::format("COMMAND: %s",Command));
|
||||
|
||||
while((pos = Command.find(' ', old_pos)) != std::string::npos) {
|
||||
Tokens.push_back(Command.substr(old_pos,pos-old_pos));
|
||||
old_pos = pos + 1 ;
|
||||
}
|
||||
|
||||
Tokens.push_back(Command.substr(old_pos));
|
||||
boost::algorithm::to_lower(Tokens[0]);
|
||||
boost::algorithm::to_lower(Tokens[1]);
|
||||
|
||||
if(Tokens[0]=="set") {
|
||||
if(Tokens[1]=="loglevel") {
|
||||
if(!Daemon()->SetSubsystemLogLevel(Tokens[3],Tokens[2]))
|
||||
Result = "ERROR: Invalid: set logLevel subsystem name:" + Tokens[3];
|
||||
}
|
||||
} else if(Tokens[0]=="get") {
|
||||
if(Tokens[1]=="loglevel") {
|
||||
std::cout << "LogLevels:" << std::endl;
|
||||
std::cout << " Auth: " << AuthClient()->Logger().getLevel() << std::endl;
|
||||
std::cout << " uFileUploader: " << FileUploader()->Logger().getLevel() << std::endl;
|
||||
std::cout << " WebSocket: " << WebSocketServer()->Logger().getLevel() << std::endl;
|
||||
std::cout << " Storage: " << Storage()->Logger().getLevel() << std::endl;
|
||||
std::cout << " RESTAPI: " << RESTAPI_server()->Logger().getLevel() << std::endl;
|
||||
std::cout << " CommandManager: " << Logger_.getLevel() << std::endl;
|
||||
std::cout << " DeviceRegistry: " << DeviceRegistry()->Logger().getLevel() << std::endl;
|
||||
} else if (Tokens[1]=="stats") {
|
||||
|
||||
} else {
|
||||
Result = "ERROR: Invalid: get command:" + Tokens[1];
|
||||
}
|
||||
} else if(Tokens[0]=="restart") {
|
||||
Logger_.information("RESTART...");
|
||||
} else if(Tokens[0]=="stop") {
|
||||
Logger_.information("STOP...");
|
||||
} else if(Tokens[0]=="stats") {
|
||||
Logger_.information("STATS...");
|
||||
} else {
|
||||
Result = "ERROR: Invalid command: " + Tokens[0];
|
||||
}
|
||||
Logger_.notice(Poco::format("COMMAND-RESULT: %s",Result));
|
||||
}
|
||||
catch ( const Poco::Exception & E) {
|
||||
Logger_.warning(Poco::format("COMMAND: Poco exception %s in performing command.",E.displayText()));
|
||||
}
|
||||
catch ( const std::exception & E) {
|
||||
Logger_.warning(Poco::format("COMMAND: std::exception %s in performing command.",std::string(E.what())));
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
/// This class handles all client connections.
|
||||
class UnixSocketServerConnection: public Poco::Net::TCPServerConnection
|
||||
{
|
||||
public:
|
||||
explicit UnixSocketServerConnection(const Poco::Net::StreamSocket & S, Poco::Logger & Logger):
|
||||
TCPServerConnection(S),
|
||||
Logger_(Logger)
|
||||
{
|
||||
}
|
||||
|
||||
void run() override
|
||||
{
|
||||
try
|
||||
{
|
||||
std::string Message;
|
||||
std::vector<char> buffer(1024);
|
||||
int n = 1;
|
||||
while (n > 0)
|
||||
{
|
||||
n = socket().receiveBytes(&buffer[0], (int)buffer.size());
|
||||
buffer[n] = '\0';
|
||||
Message += &buffer[0];
|
||||
Logger_.information(Poco::format("COMMAND-CHANNEL: %s",Message));
|
||||
if(buffer.size() > n && !Message.empty())
|
||||
{
|
||||
CommandChannel()->ProcessCommand(Message);
|
||||
Message.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Exception & E)
|
||||
{
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
};
|
||||
|
||||
class UnixSocketServerConnectionFactory: public Poco::Net::TCPServerConnectionFactory
|
||||
{
|
||||
public:
|
||||
explicit UnixSocketServerConnectionFactory() :
|
||||
Logger_(CommandChannel()->Logger())
|
||||
{
|
||||
}
|
||||
|
||||
Poco::Net::TCPServerConnection* createConnection(const Poco::Net::StreamSocket& socket) override
|
||||
{
|
||||
return new UnixSocketServerConnection(socket,Logger_);
|
||||
}
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
};
|
||||
|
||||
CommandChannel::CommandChannel() noexcept:
|
||||
SubSystemServer("CommandChannel", "COMMAND-CHANNEL", "commandchannel")
|
||||
{
|
||||
}
|
||||
|
||||
void CommandChannel::Stop() {
|
||||
Logger_.notice("Stopping...");
|
||||
Srv_->stop();
|
||||
}
|
||||
|
||||
int CommandChannel::Start() {
|
||||
Poco::File F(Daemon()->ConfigPath("ucentral.system.commandchannel","/tmp/app.ucentralgw"));
|
||||
try {
|
||||
if (F.exists())
|
||||
F.remove();
|
||||
} catch (const Poco::Exception &E ) {
|
||||
|
||||
}
|
||||
SocketFile_ = std::make_unique<Poco::File>(F);
|
||||
UnixSocket_ = std::make_unique<Poco::Net::SocketAddress>(Poco::Net::SocketAddress::UNIX_LOCAL, SocketFile_->path());
|
||||
Svs_ = std::make_unique<Poco::Net::ServerSocket>(*UnixSocket_);
|
||||
Srv_ = std::make_unique<Poco::Net::TCPServer>(new UnixSocketServerConnectionFactory, *Svs_);
|
||||
Srv_->start();
|
||||
Logger_.notice("Starting...");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALGW_COMMANDCHANNEL_H
|
||||
#define UCENTRALGW_COMMANDCHANNEL_H
|
||||
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
#include "Poco/File.h"
|
||||
#include "Poco/Net/Socket.h"
|
||||
#include "Poco/Net/SocketAddress.h"
|
||||
#include "Poco/Net/TCPServer.h"
|
||||
#include "Poco/Net/TCPServerConnection.h"
|
||||
#include "Poco/Net/TCPServerConnectionFactory.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/Net/ServerSocket.h"
|
||||
|
||||
namespace uCentral {
|
||||
|
||||
class CommandChannel : public SubSystemServer {
|
||||
public:
|
||||
static CommandChannel *instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new CommandChannel;
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
std::string ProcessCommand(const std::string &Command);
|
||||
|
||||
private:
|
||||
static CommandChannel * instance_;
|
||||
std::unique_ptr<Poco::File> SocketFile_;
|
||||
std::unique_ptr<Poco::Net::SocketAddress> UnixSocket_;
|
||||
std::unique_ptr<Poco::Net::ServerSocket> Svs_;
|
||||
std::unique_ptr<Poco::Net::TCPServer> Srv_;
|
||||
|
||||
CommandChannel() noexcept;
|
||||
};
|
||||
|
||||
inline CommandChannel * CommandChannel() { return CommandChannel::instance(); }
|
||||
} //namespace
|
||||
|
||||
#endif // UCENTRALGW_COMMANDCHANNEL_H
|
||||
@@ -18,29 +18,38 @@
|
||||
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class CommandManager * CommandManager::instance_ = nullptr;
|
||||
|
||||
CommandManager::CommandManager() noexcept:
|
||||
SubSystemServer("CommandManager", "CMD_MGR", "command.manager")
|
||||
{
|
||||
}
|
||||
|
||||
void CommandManager::run() {
|
||||
Running_ = true;
|
||||
while(Running_)
|
||||
{
|
||||
Poco::Thread::trySleep(10000);
|
||||
Poco::Thread::trySleep(30000);
|
||||
if(!Running_)
|
||||
break;
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
|
||||
if(Storage()->GetReadyToExecuteCommands(0,1000,Commands))
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if(Storage()->GetReadyToExecuteCommands(1,200,Commands))
|
||||
{
|
||||
for(auto & Cmd: Commands)
|
||||
{
|
||||
if(!SendCommand(Cmd)) {
|
||||
if(!Running_)
|
||||
break;
|
||||
|
||||
uint64_t RPC_Id;
|
||||
Poco::JSON::Parser P;
|
||||
|
||||
auto Params = P.parse(Cmd.Details).extract<Poco::JSON::Object::Ptr>();
|
||||
if(SendCommand( Cmd.SerialNumber,
|
||||
Cmd.Command,
|
||||
*Params,
|
||||
Cmd.UUID,
|
||||
RPC_Id)) {
|
||||
Storage()->SetCommandExecuted(Cmd.UUID);
|
||||
Logger_.information(Poco::format("Sent command '%s' to '%s'",Cmd.Command,Cmd.SerialNumber));
|
||||
} else {
|
||||
Logger_.information(Poco::format("Failed to send command '%s' to %s",Cmd.Command,Cmd.SerialNumber));
|
||||
}
|
||||
}
|
||||
@@ -68,105 +77,85 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void CommandManager::Janitor() {
|
||||
SubMutexGuard G(SubMutex);
|
||||
std::lock_guard G(Mutex_);
|
||||
uint64_t Now = time(nullptr);
|
||||
for(auto i = Age_.begin(); i!= Age_.end();)
|
||||
if((Now-i->first)>300)
|
||||
Age_.erase(i++);
|
||||
Logger_.information("Janitor starting.");
|
||||
for(auto i=OutStandingRequests_.begin();i!=OutStandingRequests_.end();) {
|
||||
if((Now-i->second.Submitted)>120)
|
||||
i = OutStandingRequests_.erase(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
Logger_.information("Janitor finished.");
|
||||
}
|
||||
|
||||
bool CommandManager::SendCommand(const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
std::shared_ptr<std::promise<Poco::JSON::Object::Ptr>> Promise,
|
||||
const std::string &UUID) {
|
||||
bool CommandManager::GetCommand(uint64_t Id, const std::string &SerialNumber, CommandTag &T) {
|
||||
std::lock_guard G(Mutex_);
|
||||
CommandTagIndex TI{.Id=Id,.SerialNumber=SerialNumber};
|
||||
auto Hint=OutStandingRequests_.find(TI);
|
||||
if(Hint==OutStandingRequests_.end() || Hint->second.Completed==0)
|
||||
return false;
|
||||
T = Hint->second;
|
||||
OutStandingRequests_.erase(Hint);
|
||||
return true;
|
||||
}
|
||||
|
||||
SubMutexGuard G(SubMutex);
|
||||
bool CommandManager::SendCommand( const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
uint64_t & Id,
|
||||
bool oneway_rpc) {
|
||||
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, Id_);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method );
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
std::stringstream ToSend;
|
||||
std::unique_lock G(Mutex_);
|
||||
if(oneway_rpc)
|
||||
Id = 1;
|
||||
else
|
||||
Id = ++Id_;
|
||||
Poco::JSON::Object CompleteRPC;
|
||||
CompleteRPC.set(uCentralProtocol::JSONRPC, uCentralProtocol::JSONRPC_VERSION);
|
||||
CompleteRPC.set(uCentralProtocol::ID, Id);
|
||||
CompleteRPC.set(uCentralProtocol::METHOD, Method);
|
||||
CompleteRPC.set(uCentralProtocol::PARAMS, Params);
|
||||
Poco::JSON::Stringifier::stringify(CompleteRPC, ToSend);
|
||||
|
||||
OutStandingRequests_[Id_] = std::make_pair(std::move(Promise),UUID);
|
||||
Age_[Id_] = time(nullptr);
|
||||
Id_++;
|
||||
Logger_.information(
|
||||
Poco::format("(%s): Sending command '%s', ID: %lu", SerialNumber, Method, Id));
|
||||
CommandTagIndex Idx{.Id = Id, .SerialNumber = SerialNumber};
|
||||
CommandTag Tag;
|
||||
Tag.UUID = UUID;
|
||||
Tag.Submitted = std::time(nullptr);
|
||||
Tag.Completed = 0;
|
||||
Tag.Result = Poco::makeShared<Poco::JSON::Object>();
|
||||
OutStandingRequests_[Idx] = Tag;
|
||||
G.unlock();
|
||||
return DeviceRegistry()->SendFrame(SerialNumber, ToSend.str());
|
||||
}
|
||||
|
||||
bool CommandManager::SendCommand(GWObjects::CommandDetails & Command) {
|
||||
SubMutexGuard G(SubMutex);
|
||||
|
||||
Logger_.debug(Poco::format("Sending command to %s",Command.SerialNumber));
|
||||
try {
|
||||
Poco::JSON::Object Obj;
|
||||
|
||||
Obj.set(uCentralProtocol::JSONRPC,uCentralProtocol::JSONRPC_VERSION);
|
||||
Obj.set(uCentralProtocol::ID,Id_);
|
||||
Obj.set(uCentralProtocol::METHOD, Command.Custom ? uCentralProtocol::PERFORM : Command.Command );
|
||||
|
||||
bool FullCommand = true;
|
||||
if(Command.Command==uCentralProtocol::REQUEST)
|
||||
FullCommand = false;
|
||||
|
||||
// the params section was composed earlier... just include it here
|
||||
Poco::JSON::Parser parser;
|
||||
auto ParsedMessage = parser.parse(Command.Details);
|
||||
const auto & ParamsObj = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
|
||||
Obj.set(uCentralProtocol::PARAMS,ParamsObj);
|
||||
std::stringstream ToSend;
|
||||
Poco::JSON::Stringifier::stringify(Obj,ToSend);
|
||||
|
||||
if(DeviceRegistry()->SendFrame(Command.SerialNumber, ToSend.str())) {
|
||||
Storage()->SetCommandExecuted(Command.UUID);
|
||||
OutStandingRequests_[Id_] = std::make_pair(nullptr,Command.UUID);
|
||||
Age_[Id_] = time(nullptr);
|
||||
return true;
|
||||
} else {
|
||||
|
||||
}
|
||||
Id_++;
|
||||
}
|
||||
catch( const Poco::Exception & E )
|
||||
{
|
||||
Logger_.warning(Poco::format("COMMAND(%s): Exception while sending a command.",Command.SerialNumber));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CommandManager::PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj) {
|
||||
|
||||
if(!Obj->has(uCentralProtocol::ID)){
|
||||
Logger_.error("Invalid RPC response.");
|
||||
Logger_.error(Poco::format("(%s): Invalid RPC response.",SerialNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
SubMutexGuard G(SubMutex);
|
||||
|
||||
uint64_t ID = Obj->get(uCentralProtocol::ID);
|
||||
auto RPC = OutStandingRequests_.find(ID);
|
||||
Age_.erase(ID);
|
||||
if(RPC != OutStandingRequests_.end()) {
|
||||
if(RPC->second.first.use_count() > 1) {
|
||||
try {
|
||||
RPC->second.first->set_value(std::move(Obj));
|
||||
} catch (...) {
|
||||
Logger_.error(Poco::format("COMPLETING-RPC(%Lu): future was lost", ID));
|
||||
Storage()->CommandCompleted(RPC->second.second, Obj, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Storage()->CommandCompleted(RPC->second.second, Obj, true);
|
||||
}
|
||||
OutStandingRequests_.erase(RPC);
|
||||
} else {
|
||||
Logger_.warning(Poco::format("OUTDATED-RPC(%lu): Nothing waiting for this RPC.",ID));
|
||||
if(ID<2) {
|
||||
Logger_.error(Poco::format("(%s): Ignoring RPC response.",SerialNumber));
|
||||
return;
|
||||
}
|
||||
std::unique_lock G(Mutex_);
|
||||
auto Idx = CommandTagIndex{.Id = ID, .SerialNumber = SerialNumber};
|
||||
auto RPC = OutStandingRequests_.find(Idx);
|
||||
if (RPC == OutStandingRequests_.end()) {
|
||||
Logger_.warning(Poco::format("(%s): Outdated RPC %lu", SerialNumber, ID));
|
||||
return;
|
||||
}
|
||||
RPC->second.Completed = std::time(nullptr);
|
||||
RPC->second.Result = Obj;
|
||||
Logger_.information(Poco::format("(%s): Received RPC answer %lu", SerialNumber, ID));
|
||||
G.unlock();
|
||||
Storage()->CommandCompleted(RPC->second.UUID, Obj, true);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -22,7 +22,33 @@
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
struct CommandTagIndex {
|
||||
uint64_t Id=0;
|
||||
std::string SerialNumber;
|
||||
};
|
||||
|
||||
inline bool operator <(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id<rhs.Id)
|
||||
return true;
|
||||
if(lhs.Id>rhs.Id)
|
||||
return false;
|
||||
return lhs.SerialNumber<rhs.SerialNumber;
|
||||
}
|
||||
|
||||
inline bool operator ==(const CommandTagIndex& lhs, const CommandTagIndex& rhs) {
|
||||
if(lhs.Id == rhs.Id && lhs.SerialNumber == rhs.SerialNumber)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct CommandTag {
|
||||
std::string UUID;
|
||||
Poco::JSON::Object::Ptr Result;
|
||||
uint64_t Submitted=0;
|
||||
uint64_t Completed=0;
|
||||
};
|
||||
|
||||
class CommandManager : public SubSystemServer, Poco::Runnable {
|
||||
public:
|
||||
@@ -31,34 +57,35 @@ namespace uCentral {
|
||||
void WakeUp();
|
||||
void PostCommandResult(const std::string &SerialNumber, Poco::JSON::Object::Ptr Obj);
|
||||
bool SendCommand( const std::string &SerialNumber,
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
std::shared_ptr<std::promise<Poco::JSON::Object::Ptr>> Promise,
|
||||
const std::string &UUID);
|
||||
bool SendCommand( const std::string & SerialNumber,
|
||||
const std::string & Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string & UUID);
|
||||
bool SendCommand(GWObjects::CommandDetails & Command);
|
||||
const std::string &Method,
|
||||
const Poco::JSON::Object &Params,
|
||||
const std::string &UUID,
|
||||
uint64_t & Id,
|
||||
bool oneway_rpc=false);
|
||||
void Janitor();
|
||||
void run() override;
|
||||
|
||||
bool GetCommand(uint64_t Id, const std::string & SerialNumber, CommandTag &T);
|
||||
|
||||
static CommandManager *instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new CommandManager;
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
inline bool Running() const { return Running_; }
|
||||
|
||||
private:
|
||||
static CommandManager * instance_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
uint64_t Id_=1;
|
||||
std::map< uint64_t , std::pair< std::shared_ptr<std::promise<Poco::JSON::Object::Ptr>>, std::string> > OutStandingRequests_;
|
||||
std::map< uint64_t , uint64_t > Age_;
|
||||
std::atomic_bool Running_ = false;
|
||||
Poco::Thread ManagerThread;
|
||||
uint64_t Id_=2; // do not start @1. We ignore ID=1 & 0 is illegal..
|
||||
std::map<CommandTagIndex,CommandTag> OutStandingRequests_;
|
||||
|
||||
CommandManager() noexcept;
|
||||
CommandManager() noexcept:
|
||||
SubSystemServer("CommandManager", "CMD-MGR", "command.manager")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline CommandManager * CommandManager() { return CommandManager::instance(); }
|
||||
|
||||
9
src/ConfigurationCache.cpp
Normal file
9
src/ConfigurationCache.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-21.
|
||||
//
|
||||
|
||||
#include "ConfigurationCache.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class ConfigurationCache * ConfigurationCache::instance_ = nullptr;
|
||||
}
|
||||
44
src/ConfigurationCache.h
Normal file
44
src/ConfigurationCache.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-21.
|
||||
//
|
||||
|
||||
#ifndef OWGW_CONFIGURATIONCACHE_H
|
||||
#define OWGW_CONFIGURATIONCACHE_H
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
namespace OpenWifi {
|
||||
class ConfigurationCache {
|
||||
public:
|
||||
|
||||
static ConfigurationCache &instance() {
|
||||
if(instance_== nullptr)
|
||||
instance_ = new ConfigurationCache;
|
||||
return *instance_;
|
||||
}
|
||||
|
||||
inline uint64_t CurrentConfig(const std::string &SerialNumber) {
|
||||
std::lock_guard G(Mutex_);
|
||||
const auto Hint = Cache_.find(SerialNumber);
|
||||
if(Hint==end(Cache_))
|
||||
return 0;
|
||||
return Hint->second;
|
||||
}
|
||||
|
||||
void Add(const std::string &SerialNumber, uint64_t Id) {
|
||||
std::lock_guard G(Mutex_);
|
||||
Cache_[SerialNumber]=Id;
|
||||
}
|
||||
|
||||
private:
|
||||
static ConfigurationCache *instance_;
|
||||
std::mutex Mutex_;
|
||||
std::map<std::string,uint64_t> Cache_;
|
||||
};
|
||||
|
||||
inline uint64_t GetCurrentConfigurationID(const std::string &S) { return ConfigurationCache::instance().CurrentConfig(S); }
|
||||
inline void SetCurrentConfigurationID(const std::string &S, uint64_t ID) { ConfigurationCache::instance().Add(S,ID); }
|
||||
}
|
||||
#endif // OWGW_CONFIGURATIONCACHE_H
|
||||
2215
src/ConfigurationValidator.cpp
Normal file
2215
src/ConfigurationValidator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
70
src/ConfigurationValidator.h
Normal file
70
src/ConfigurationValidator.h
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-14.
|
||||
//
|
||||
|
||||
#ifndef OWPROV_CONFIGURATIONVALIDATOR_H
|
||||
#define OWPROV_CONFIGURATIONVALIDATOR_H
|
||||
|
||||
#include <nlohmann/json-schema.hpp>
|
||||
#include "Poco/Logger.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_schema::json_validator;
|
||||
|
||||
namespace OpenWifi {
|
||||
class ConfigurationValidator : public SubSystemServer {
|
||||
public:
|
||||
|
||||
static ConfigurationValidator *instance() {
|
||||
if(instance_== nullptr)
|
||||
instance_ = new ConfigurationValidator;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
bool Validate(const std::string &C);
|
||||
static void my_format_checker(const std::string &format, const std::string &value)
|
||||
{
|
||||
/*
|
||||
"format": "uc-mac"
|
||||
"format": "uc-timeout",
|
||||
"format": "uc-cidr4",
|
||||
"format": "uc-cidr6",
|
||||
"uc-format": "cidr",
|
||||
"format": "fqdn",
|
||||
"format": "uc-host",
|
||||
"format": "uri"
|
||||
"format": "hostname"
|
||||
"format": "uc-base64"
|
||||
|
||||
|
||||
if (format == "something") {
|
||||
return;
|
||||
if (!check_value_for_something(value))
|
||||
throw std::invalid_argument("value is not a good something");
|
||||
} else
|
||||
throw std::logic_error("Don't know how to validate " + format);
|
||||
*/
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
|
||||
private:
|
||||
static ConfigurationValidator * instance_;
|
||||
bool Initialized_=false;
|
||||
bool Working_=false;
|
||||
void Init();
|
||||
std::unique_ptr<json_validator> Validator_=std::make_unique<json_validator>(nullptr, my_format_checker);
|
||||
|
||||
ConfigurationValidator():
|
||||
SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") {
|
||||
}
|
||||
};
|
||||
|
||||
inline ConfigurationValidator * ConfigurationValidator() { return ConfigurationValidator::instance(); }
|
||||
inline bool ValidateUCentralConfiguration(const std::string &C) { return ConfigurationValidator::instance()->Validate(C); }
|
||||
}
|
||||
|
||||
#endif //OWPROV_CONFIGURATIONVALIDATOR_H
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "Daemon.h"
|
||||
|
||||
#include "CommandChannel.h"
|
||||
#include "CommandManager.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "FileUploader.h"
|
||||
@@ -28,8 +27,11 @@
|
||||
#include "RESTAPI_InternalServer.h"
|
||||
#include "AuthClient.h"
|
||||
#include "StorageArchiver.h"
|
||||
#include "SerialNumberCache.h"
|
||||
#include "TelemetryStream.h"
|
||||
#include "ConfigurationValidator.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class Daemon *Daemon::instance_ = nullptr;
|
||||
|
||||
class Daemon *Daemon::instance() {
|
||||
@@ -41,6 +43,8 @@ namespace uCentral {
|
||||
vDAEMON_BUS_TIMER,
|
||||
Types::SubSystemVec{
|
||||
Storage(),
|
||||
SerialNumberCache(),
|
||||
ConfigurationValidator(),
|
||||
AuthClient(),
|
||||
DeviceRegistry(),
|
||||
RESTAPI_server(),
|
||||
@@ -49,8 +53,8 @@ namespace uCentral {
|
||||
CommandManager(),
|
||||
FileUploader(),
|
||||
OUIServer(),
|
||||
CommandChannel(),
|
||||
StorageArchiver(),
|
||||
TelemetryStream()
|
||||
});
|
||||
}
|
||||
return instance_;
|
||||
@@ -59,19 +63,19 @@ namespace uCentral {
|
||||
void Daemon::initialize(Poco::Util::Application &self) {
|
||||
MicroService::initialize(*this);
|
||||
Config::Config::Init();
|
||||
AutoProvisioning_ = config().getBool("ucentral.autoprovisioning",false);
|
||||
AutoProvisioning_ = config().getBool("openwifi.autoprovisioning",false);
|
||||
|
||||
// DeviceTypeIdentifications_
|
||||
Types::StringVec Keys;
|
||||
config().keys("ucentral.devicetypes",Keys);
|
||||
config().keys("openwifi.devicetypes",Keys);
|
||||
for(const auto & i:Keys)
|
||||
{
|
||||
std::string Line = config().getString("ucentral.devicetypes."+i);
|
||||
std::string Line = config().getString("openwifi.devicetypes."+i);
|
||||
auto P1 = Line.find_first_of(':');
|
||||
auto Type = Line.substr(0, P1);
|
||||
auto List = Line.substr(P1+1);
|
||||
|
||||
Types::StringVec Tokens = uCentral::Utils::Split(List);
|
||||
Types::StringVec Tokens = Utils::Split(List);
|
||||
|
||||
auto Entry = DeviceTypeIdentifications_.find(Type);
|
||||
if(DeviceTypeIdentifications_.end() == Entry) {
|
||||
@@ -96,7 +100,7 @@ namespace uCentral {
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
try {
|
||||
auto App = uCentral::Daemon::instance();
|
||||
auto App = OpenWifi::Daemon::instance();
|
||||
auto ExitCode = App->run(argc, argv);
|
||||
delete App;
|
||||
|
||||
|
||||
23
src/Daemon.h
23
src/Daemon.h
@@ -27,31 +27,32 @@
|
||||
|
||||
#include "Dashboard.h"
|
||||
#include "MicroService.h"
|
||||
#include "uCentralTypes.h"
|
||||
#include "OpenWifiTypes.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
static const char * vDAEMON_PROPERTIES_FILENAME = "ucentralgw.properties";
|
||||
static const char * vDAEMON_ROOT_ENV_VAR = "UCENTRALGW_ROOT";
|
||||
static const char * vDAEMON_CONFIG_ENV_VAR = "UCENTRALGW_CONFIG";
|
||||
static const char * vDAEMON_PROPERTIES_FILENAME = "owgw.properties";
|
||||
static const char * vDAEMON_ROOT_ENV_VAR = "OWGW_ROOT";
|
||||
static const char * vDAEMON_CONFIG_ENV_VAR = "OWGW_CONFIG";
|
||||
static const char * vDAEMON_APP_NAME = uSERVICE_GATEWAY.c_str();
|
||||
static const uint64_t vDAEMON_BUS_TIMER = 10000;
|
||||
|
||||
class Daemon : public MicroService {
|
||||
public:
|
||||
explicit Daemon(std::string PropFile,
|
||||
std::string RootEnv,
|
||||
std::string ConfigEnv,
|
||||
std::string AppName,
|
||||
explicit Daemon(const std::string & PropFile,
|
||||
const std::string & RootEnv,
|
||||
const std::string & ConfigEnv,
|
||||
const std::string & AppName,
|
||||
uint64_t BusTimer,
|
||||
Types::SubSystemVec SubSystems) :
|
||||
const Types::SubSystemVec & SubSystems) :
|
||||
MicroService( PropFile, RootEnv, ConfigEnv, AppName, BusTimer, SubSystems) {};
|
||||
|
||||
bool AutoProvisioning() const { return AutoProvisioning_ ; }
|
||||
[[nodiscard]] std::string IdentifyDevice(const std::string & Compatible) const;
|
||||
void initialize(Poco::Util::Application &self);
|
||||
void initialize(Poco::Util::Application &self) override;
|
||||
static Daemon *instance();
|
||||
inline DeviceDashboard & GetDashboard() { return DB_; }
|
||||
Poco::Logger & Log() { return Poco::Logger::get(AppName()); }
|
||||
private:
|
||||
static Daemon *instance_;
|
||||
bool AutoProvisioning_ = false;
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
#include "DeviceRegistry.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
void DeviceDashboard::Create() {
|
||||
uint64_t Now = std::time(nullptr);
|
||||
|
||||
if(LastRun_==0 || (Now-LastRun_)>120) {
|
||||
DB_.reset();
|
||||
Storage()->AnalyzeCommands(DB_.commands);
|
||||
DeviceRegistry()->AnalyzeRegistry(DB_);
|
||||
Storage()->AnalyzeDevices(DB_);
|
||||
LastRun_ = Now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
#ifndef UCENTRALGW_DASHBOARD_H
|
||||
#define UCENTRALGW_DASHBOARD_H
|
||||
|
||||
#include "uCentralTypes.h"
|
||||
#include "OpenWifiTypes.h"
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class DeviceDashboard {
|
||||
public:
|
||||
DeviceDashboard() { DB_.reset(); }
|
||||
void Create();
|
||||
const GWObjects::Dashboard & Report() const { return DB_;}
|
||||
inline void Reset() { LastRun_=0; DB_.reset(); }
|
||||
[[nodiscard]] const GWObjects::Dashboard & Report() const { return DB_;}
|
||||
private:
|
||||
GWObjects::Dashboard DB_;
|
||||
uint64_t LastRun_=0;
|
||||
inline void Reset() { DB_.reset(); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class DeviceRegistry *DeviceRegistry::instance_ = nullptr;
|
||||
|
||||
DeviceRegistry::DeviceRegistry() noexcept:
|
||||
@@ -24,29 +24,29 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
int DeviceRegistry::Start() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger_.notice("Starting ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DeviceRegistry::Stop() {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger_.notice("Stopping ");
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetStatistics(const std::string &SerialNumber, std::string & Statistics) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end()) {
|
||||
Statistics = Device->second->LastStats;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
|
||||
Statistics = Device->second->LastStats;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetStatistics(const std::string &SerialNumber, const std::string &Statistics) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
|
||||
@@ -58,22 +58,18 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetState(const std::string &SerialNumber, GWObjects::ConnectionState & State) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
State = Device->second->Conn_;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if(Device == Devices_.end())
|
||||
return false;
|
||||
|
||||
State = Device->second->Conn_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetState(const std::string & SerialNumber, GWObjects::ConnectionState & State) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
|
||||
if(Device != Devices_.end())
|
||||
{
|
||||
Device->second->Conn_.LastContact = time(nullptr);
|
||||
@@ -82,7 +78,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
bool DeviceRegistry::GetHealthcheck(const std::string &SerialNumber, GWObjects::HealthCheck & CheckData) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device != Devices_.end()) {
|
||||
@@ -93,7 +89,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetHealthcheck(const std::string &SerialNumber, const GWObjects::HealthCheck & CheckData) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
|
||||
@@ -105,7 +101,7 @@ namespace uCentral {
|
||||
|
||||
GWObjects::ConnectionState * DeviceRegistry::Register(const std::string & SerialNumber, WSConnection *Ptr)
|
||||
{
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if( Device == Devices_.end()) {
|
||||
@@ -136,7 +132,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
bool DeviceRegistry::Connected(const std::string & SerialNumber) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
|
||||
@@ -147,7 +143,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void DeviceRegistry::UnRegister(const std::string & SerialNumber, WSConnection *Ptr) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
|
||||
@@ -157,22 +153,19 @@ namespace uCentral {
|
||||
Device->second->Conn_.Connected = false;
|
||||
Device->second->Conn_.VerifiedCertificate = GWObjects::NO_CERTIFICATE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DeviceRegistry::SendFrame(const std::string & SerialNumber, const std::string & Payload) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end() && Device->second->WSConn_!= nullptr) {
|
||||
auto *WSConn =
|
||||
static_cast<WSConnection *>(Device->second->WSConn_);
|
||||
return WSConn->Send(Payload);
|
||||
return Device->second->WSConn_->Send(Payload);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DeviceRegistry::SetPendingUUID(const std::string & SerialNumber, uint64_t PendingUUID) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Device = Devices_.find(SerialNumber);
|
||||
if(Device!=Devices_.end()) {
|
||||
Device->second->Conn_.PendingUUID = PendingUUID;
|
||||
@@ -207,7 +200,7 @@ namespace uCentral {
|
||||
if( T==100) return "100%";
|
||||
if( T>90) return ">90%";
|
||||
if( T>60) return ">60%";
|
||||
return "<60%%>";
|
||||
return "<60%";
|
||||
}
|
||||
|
||||
std::string ComputeUpTimeTag(uint64_t T) {
|
||||
@@ -237,7 +230,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
bool DeviceRegistry::AnalyzeRegistry(GWObjects::Dashboard &D) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
for(auto const &[SerialNumber,Connection]:Devices_) {
|
||||
Types::UpdateCountedMap(D.status, Connection->Conn_.Connected ? "connected" : "not connected");
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
// class uCentral::WebSocket::WSConnection;
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class WSConnection;
|
||||
class DeviceRegistry : public SubSystemServer {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class FileUploader *FileUploader::instance_ = nullptr;
|
||||
|
||||
static const std::string URI_BASE{"/v1/upload/"};
|
||||
@@ -34,16 +34,23 @@ namespace uCentral {
|
||||
int FileUploader::Start() {
|
||||
Logger_.notice("Starting.");
|
||||
|
||||
Poco::File UploadsDir(Daemon()->ConfigPath("openwifi.fileuploader.path","/tmp"));
|
||||
Path_ = UploadsDir.path();
|
||||
if(!UploadsDir.exists()) {
|
||||
try {
|
||||
UploadsDir.createDirectory();
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
Path_ = "/tmp";
|
||||
}
|
||||
}
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
std::string l{"Starting: " +
|
||||
Svr.Address() + ":" + std::to_string(Svr.Port()) +
|
||||
" key:" + Svr.KeyFile() +
|
||||
" cert:" + Svr.CertFile()};
|
||||
|
||||
Logger_.information(l);
|
||||
|
||||
Path_ = Daemon()->ConfigPath("ucentral.fileuploader.path","/tmp");
|
||||
|
||||
auto Sock{Svr.CreateSecureSocket(Logger_)};
|
||||
|
||||
Svr.LogCert(Logger_);
|
||||
@@ -55,24 +62,40 @@ namespace uCentral {
|
||||
Params->setMaxQueued(100);
|
||||
|
||||
if(FullName_.empty()) {
|
||||
FullName_ = "https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
Logger_.information(Poco::format("Uploader URI base is '%s'", FullName_));
|
||||
std::string TmpName = Daemon()->ConfigGetString("openwifi.fileuploader.uri","");
|
||||
if(TmpName.empty()) {
|
||||
FullName_ =
|
||||
"https://" + Svr.Name() + ":" + std::to_string(Svr.Port()) + URI_BASE;
|
||||
} else {
|
||||
FullName_ = TmpName + URI_BASE ;
|
||||
}
|
||||
Logger_.information(Poco::format("Uploader URI base is '%s'", FullName_));
|
||||
}
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new FileUpLoaderRequestHandlerFactory(Logger_), Pool_, Sock, Params);
|
||||
NewServer->start();
|
||||
Servers_.push_back(std::move(NewServer));
|
||||
}
|
||||
|
||||
MaxSize_ = 1000 * Daemon()->ConfigGetInt("openwifi.fileuploader.maxsize", 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FileUploader::reinitialize(Poco::Util::Application &self) {
|
||||
Daemon()->LoadConfigurationFile();
|
||||
Logger_.information("Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
const std::string & FileUploader::FullName() {
|
||||
return FullName_;
|
||||
}
|
||||
|
||||
// if you pass in an empty UUID, it will just clean the list and not add it.
|
||||
bool FileUploader::AddUUID( const std::string & UUID) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
uint64_t Now = time(nullptr) ;
|
||||
|
||||
@@ -91,13 +114,13 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
bool FileUploader::ValidRequest(const std::string &UUID) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
return OutStandingUploads_.find(UUID)!=OutStandingUploads_.end();
|
||||
}
|
||||
|
||||
void FileUploader::RemoveRequest(const std::string &UUID) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
OutStandingUploads_.erase(UUID);
|
||||
}
|
||||
|
||||
@@ -112,35 +135,49 @@ namespace uCentral {
|
||||
|
||||
void handlePart(const Poco::Net::MessageHeader& Header, std::istream& Stream) override
|
||||
{
|
||||
FileType_ = Header.get("Content-Type", "(unspecified)");
|
||||
if (Header.has("Content-Disposition"))
|
||||
{
|
||||
std::string Disposition;
|
||||
Poco::Net::NameValueCollection Parameters;
|
||||
Poco::Net::MessageHeader::splitParameters(Header["Content-Disposition"], Disposition, Parameters);
|
||||
Name_ = Parameters.get("name", "(unnamed)");
|
||||
}
|
||||
try {
|
||||
Name_ = "(unnamed)";
|
||||
if (Header.has("Content-Disposition")) {
|
||||
std::string Disposition;
|
||||
Poco::Net::NameValueCollection Parameters;
|
||||
Poco::Net::MessageHeader::splitParameters(Header["Content-Disposition"],
|
||||
Disposition, Parameters);
|
||||
Name_ = Parameters.get("filename", "(unnamed)");
|
||||
}
|
||||
|
||||
Poco::TemporaryFile TmpFile;
|
||||
std::string FinalFileName = FileUploader()->Path() + "/" + UUID_ ;
|
||||
Logger_.information(Poco::format("FILE-UPLOADER: uploading trace for %s",UUID_));
|
||||
std::string FinalFileName = FileUploader()->Path() + "/" + UUID_;
|
||||
|
||||
Poco::CountingInputStream InputStream(Stream);
|
||||
std::ofstream OutputStream(TmpFile.path(), std::ofstream::out);
|
||||
Poco::StreamCopier::copyStream(InputStream, OutputStream);
|
||||
Length_ = InputStream.chars();
|
||||
rename(TmpFile.path().c_str(),FinalFileName.c_str());
|
||||
}
|
||||
Logger_.information(Poco::format("FILE-UPLOADER: uploading trace for %s", FinalFileName));
|
||||
Poco::CountingInputStream InputStream(Stream);
|
||||
std::ofstream OutputStream(FinalFileName, std::ofstream::out);
|
||||
Poco::StreamCopier::copyStream(InputStream, OutputStream);
|
||||
|
||||
Poco::File TmpFile(FinalFileName);
|
||||
Length_ = TmpFile.getSize();
|
||||
if (Length_ < FileUploader()->MaxSize()) {
|
||||
Good_=true;
|
||||
} else {
|
||||
TmpFile.remove();
|
||||
Error_ = "File is too large.";
|
||||
}
|
||||
return;
|
||||
} catch (const Poco::Exception &E ) {
|
||||
Logger_.log(E);
|
||||
Error_ = std::string("Upload caused an internal error: ") + E.what() ;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t Length() const { return Length_; }
|
||||
[[nodiscard]] const std::string& Name() const { return Name_; }
|
||||
[[nodiscard]] const std::string& ContentType() const { return FileType_; }
|
||||
[[nodiscard]] bool Good() const { return Good_; }
|
||||
std::string & Error() { return Error_; }
|
||||
|
||||
private:
|
||||
uint64_t Length_=0;
|
||||
std::string FileType_;
|
||||
bool Good_=false;
|
||||
std::string Name_;
|
||||
std::string UUID_;
|
||||
std::string Error_;
|
||||
Poco::Logger & Logger_;
|
||||
};
|
||||
|
||||
@@ -165,14 +202,15 @@ namespace uCentral {
|
||||
Response.setContentType("application/json");
|
||||
|
||||
Poco::JSON::Object Answer;
|
||||
if (!partHandler.Name().empty()) {
|
||||
if (partHandler.Good()) {
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 0);
|
||||
Storage()->AttachFileToCommand(UUID_);
|
||||
} else {
|
||||
Answer.set("filename", UUID_);
|
||||
Answer.set("error", 13);
|
||||
Answer.set("errorText", "File could not be uploaded");
|
||||
Answer.set("errorText", partHandler.Error() );
|
||||
Storage()->CancelWaitFile(UUID_, partHandler.Error() );
|
||||
}
|
||||
std::ostream &ResponseStream = Response.send();
|
||||
Poco::JSON::Stringifier::stringify(Answer, ResponseStream);
|
||||
@@ -193,7 +231,7 @@ namespace uCentral {
|
||||
|
||||
Poco::Net::HTTPRequestHandler *FileUpLoaderRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
|
||||
|
||||
Logger_.debug(Poco::format("REQUEST(%s): %s %s", uCentral::Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
Logger_.debug(Poco::format("REQUEST(%s): %s %s", Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
|
||||
// The UUID should be after the /v1/upload/ part...
|
||||
auto UUIDLocation = Request.getURI().find_first_of(URI_BASE);
|
||||
@@ -219,6 +257,7 @@ namespace uCentral {
|
||||
Logger_.notice("Stopping ");
|
||||
for( const auto & svr : Servers_ )
|
||||
svr->stop();
|
||||
Servers_.clear();
|
||||
}
|
||||
|
||||
} // Namespace
|
||||
@@ -17,12 +17,13 @@
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class FileUploader : public SubSystemServer {
|
||||
public:
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
const std::string & FullName();
|
||||
bool AddUUID( const std::string & UUID);
|
||||
bool ValidRequest(const std::string & UUID);
|
||||
@@ -36,6 +37,8 @@ namespace uCentral {
|
||||
return instance_;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline uint64_t MaxSize() const { return MaxSize_; }
|
||||
|
||||
private:
|
||||
static FileUploader *instance_;
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> Servers_;
|
||||
@@ -43,11 +46,11 @@ namespace uCentral {
|
||||
std::string FullName_;
|
||||
std::map<std::string,uint64_t> OutStandingUploads_;
|
||||
std::string Path_;
|
||||
uint64_t MaxSize_=10000000;
|
||||
|
||||
explicit FileUploader() noexcept:
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "ucentral.fileuploader")
|
||||
SubSystemServer("FileUploader", "FILE-UPLOAD", "openwifi.fileuploader")
|
||||
{
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -12,18 +12,18 @@
|
||||
#include "Daemon.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class KafkaManager *KafkaManager::instance_ = nullptr;
|
||||
|
||||
KafkaManager::KafkaManager() noexcept:
|
||||
SubSystemServer("KafkaManager", "KAFKA-SVR", "ucentral.kafka")
|
||||
SubSystemServer("KafkaManager", "KAFKA-SVR", "openwifi.kafka")
|
||||
{
|
||||
}
|
||||
|
||||
void KafkaManager::initialize(Poco::Util::Application & self) {
|
||||
SubSystemServer::initialize(self);
|
||||
KafkaEnabled_ = Daemon()->ConfigGetBool("ucentral.kafka.enable",false);
|
||||
KafkaEnabled_ = Daemon()->ConfigGetBool("openwifi.kafka.enable",false);
|
||||
}
|
||||
|
||||
#ifdef SMALL_BUILD
|
||||
@@ -55,8 +55,8 @@ namespace uCentral {
|
||||
|
||||
void KafkaManager::ProducerThr() {
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", Daemon()->ConfigGetString("ucentral.kafka.client.id") },
|
||||
{ "metadata.broker.list", Daemon()->ConfigGetString("ucentral.kafka.brokerlist") }
|
||||
{ "client.id", Daemon()->ConfigGetString("openwifi.kafka.client.id") },
|
||||
{ "metadata.broker.list", Daemon()->ConfigGetString("openwifi.kafka.brokerlist") }
|
||||
});
|
||||
SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
|
||||
std::to_string(Daemon()->ID()) +
|
||||
@@ -68,7 +68,7 @@ namespace uCentral {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
try
|
||||
{
|
||||
SubMutexGuard G(ProducerMutex_);
|
||||
std::lock_guard G(ProducerMutex_);
|
||||
auto Num=0;
|
||||
while (!Queue_.empty()) {
|
||||
const auto M = Queue_.front();
|
||||
@@ -96,10 +96,10 @@ namespace uCentral {
|
||||
|
||||
void KafkaManager::ConsumerThr() {
|
||||
cppkafka::Configuration Config({
|
||||
{ "client.id", Daemon()->ConfigGetString("ucentral.kafka.client.id") },
|
||||
{ "metadata.broker.list", Daemon()->ConfigGetString("ucentral.kafka.brokerlist") },
|
||||
{ "group.id", Daemon()->ConfigGetString("ucentral.kafka.group.id") },
|
||||
{ "enable.auto.commit", Daemon()->ConfigGetBool("ucentral.kafka.auto.commit",false) },
|
||||
{ "client.id", Daemon()->ConfigGetString("openwifi.kafka.client.id") },
|
||||
{ "metadata.broker.list", Daemon()->ConfigGetString("openwifi.kafka.brokerlist") },
|
||||
{ "group.id", Daemon()->ConfigGetString("openwifi.kafka.group.id") },
|
||||
{ "enable.auto.commit", Daemon()->ConfigGetBool("openwifi.kafka.auto.commit",false) },
|
||||
{ "auto.offset.reset", "latest" } ,
|
||||
{ "enable.partition.eof", false }
|
||||
});
|
||||
@@ -125,8 +125,8 @@ namespace uCentral {
|
||||
}
|
||||
});
|
||||
|
||||
bool AutoCommit = Daemon()->ConfigGetBool("ucentral.kafka.auto.commit",false);
|
||||
auto BatchSize = Daemon()->ConfigGetInt("ucentral.kafka.consumer.batchsize",20);
|
||||
bool AutoCommit = Daemon()->ConfigGetBool("openwifi.kafka.auto.commit",false);
|
||||
auto BatchSize = Daemon()->ConfigGetInt("openwifi.kafka.consumer.batchsize",20);
|
||||
|
||||
Types::StringVec Topics;
|
||||
for(const auto &i:Notifiers_)
|
||||
@@ -148,7 +148,7 @@ namespace uCentral {
|
||||
Consumer.async_commit(Msg);
|
||||
continue;
|
||||
}
|
||||
SubMutexGuard G(ConsumerMutex_);
|
||||
std::lock_guard G(ConsumerMutex_);
|
||||
auto It = Notifiers_.find(Msg.get_topic());
|
||||
if (It != Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList &FL = It->second;
|
||||
@@ -174,9 +174,9 @@ namespace uCentral {
|
||||
return std::move( SystemInfoWrapper_ + PayLoad + "}");
|
||||
}
|
||||
|
||||
void KafkaManager::PostMessage(std::string topic, std::string key, std::string PayLoad, bool WrapMessage ) {
|
||||
void KafkaManager::PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage ) {
|
||||
if(KafkaEnabled_) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
KMessage M{
|
||||
.Topic = topic,
|
||||
.Key = key,
|
||||
@@ -187,7 +187,7 @@ namespace uCentral {
|
||||
|
||||
int KafkaManager::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
|
||||
if(KafkaEnabled_) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if(It == Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList L;
|
||||
@@ -204,7 +204,7 @@ namespace uCentral {
|
||||
|
||||
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, int Id) {
|
||||
if(KafkaEnabled_) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
auto It = Notifiers_.find(Topic);
|
||||
if(It != Notifiers_.end()) {
|
||||
Types::TopicNotifyFunctionList & L = It->second;
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
#include <thread>
|
||||
|
||||
#include "SubSystemServer.h"
|
||||
#include "uCentralTypes.h"
|
||||
#include "OpenWifiTypes.h"
|
||||
|
||||
#include "cppkafka/cppkafka.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class KafkaManager : public SubSystemServer {
|
||||
public:
|
||||
@@ -41,7 +41,7 @@ namespace uCentral {
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
void PostMessage(std::string topic, std::string key, std::string payload, bool WrapMessage = true);
|
||||
void PostMessage(const std::string &topic, const std::string & key, const std::string &payload, bool WrapMessage = true);
|
||||
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
|
||||
[[nodiscard]] bool Enabled() { return KafkaEnabled_; }
|
||||
int RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction & F);
|
||||
@@ -52,8 +52,8 @@ namespace uCentral {
|
||||
|
||||
private:
|
||||
static KafkaManager *instance_;
|
||||
SubMutex ProducerMutex_;
|
||||
SubMutex ConsumerMutex_;
|
||||
std::mutex ProducerMutex_;
|
||||
std::mutex ConsumerMutex_;
|
||||
bool KafkaEnabled_ = false;
|
||||
std::atomic_bool ProducerRunning_ = false;
|
||||
std::atomic_bool ConsumerRunning_ = false;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#ifndef UCENTRALGW_KAFKA_TOPICS_H
|
||||
#define UCENTRALGW_KAFKA_TOPICS_H
|
||||
|
||||
namespace uCentral::KafkaTopics {
|
||||
namespace OpenWifi::KafkaTopics {
|
||||
static const std::string HEALTHCHECK{"healthcheck"};
|
||||
static const std::string STATE{"state"};
|
||||
static const std::string CONNECTION{"connection"};
|
||||
@@ -13,6 +13,7 @@ namespace uCentral::KafkaTopics {
|
||||
static const std::string ALERTS{"alerts"};
|
||||
static const std::string COMMAND{"command"};
|
||||
static const std::string SERVICE_EVENTS{"service_events"};
|
||||
static const std::string DEVICE_EVENT_QUEUE{"device_event_queue"};
|
||||
|
||||
namespace ServiceEvents {
|
||||
static const std::string EVENT_JOIN{"join"};
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-06-22.
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include <cstdlib>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
@@ -34,7 +39,7 @@
|
||||
#include "AuthClient.h"
|
||||
#endif
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
void MyErrorHandler::exception(const Poco::Exception & E) {
|
||||
Poco::Thread * CurrentThread = Poco::Thread::current();
|
||||
@@ -57,7 +62,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void MicroService::BusMessageReceived(const std::string &Key, const std::string & Message) {
|
||||
SubMutexGuard G(InfraMutex_);
|
||||
std::lock_guard G(InfraMutex_);
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto Object = P.parse(Message).extract<Poco::JSON::Object::Ptr>();
|
||||
@@ -112,13 +117,23 @@ namespace uCentral {
|
||||
} else {
|
||||
logger().error("Bad bus message.");
|
||||
}
|
||||
|
||||
auto i=Services_.begin();
|
||||
auto Now = (uint64_t )std::time(nullptr);
|
||||
for(;i!=Services_.end();) {
|
||||
if((Now - i->second.LastUpdate)>60) {
|
||||
i = Services_.erase(i);
|
||||
} else
|
||||
++i;
|
||||
}
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
logger().log(E);
|
||||
}
|
||||
}
|
||||
|
||||
MicroServiceMetaVec MicroService::GetServices(const std::string & Type) {
|
||||
SubMutexGuard G(InfraMutex_);
|
||||
std::lock_guard G(InfraMutex_);
|
||||
|
||||
auto T = Poco::toLower(Type);
|
||||
MicroServiceMetaVec Res;
|
||||
@@ -130,7 +145,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
MicroServiceMetaVec MicroService::GetServices() {
|
||||
SubMutexGuard G(InfraMutex_);
|
||||
std::lock_guard G(InfraMutex_);
|
||||
|
||||
MicroServiceMetaVec Res;
|
||||
for(const auto &[Id,ServiceRec]:Services_) {
|
||||
@@ -139,6 +154,42 @@ namespace uCentral {
|
||||
return Res;
|
||||
}
|
||||
|
||||
void MicroService::LoadConfigurationFile() {
|
||||
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,".");
|
||||
Poco::Path ConfigFile;
|
||||
|
||||
ConfigFile = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : 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());
|
||||
}
|
||||
|
||||
void MicroService::Reload() {
|
||||
LoadConfigurationFile();
|
||||
LoadMyConfig();
|
||||
}
|
||||
|
||||
void MicroService::LoadMyConfig() {
|
||||
std::string KeyFile = ConfigPath("openwifi.service.key");
|
||||
std::string KeyFilePassword = ConfigPath("openwifi.service.key.password" , "" );
|
||||
AppKey_ = Poco::SharedPtr<Poco::Crypto::RSAKey>(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword));
|
||||
Cipher_ = CipherFactory_.createCipher(*AppKey_);
|
||||
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_ = CreateHash(MyPublicEndPoint_);
|
||||
}
|
||||
|
||||
void MicroService::initialize(Poco::Util::Application &self) {
|
||||
// add the default services
|
||||
SubSystems_.push_back(KafkaManager());
|
||||
@@ -149,22 +200,10 @@ namespace uCentral {
|
||||
Poco::Net::HTTPSStreamFactory::registerFactory();
|
||||
Poco::Net::FTPStreamFactory::registerFactory();
|
||||
Poco::Net::FTPSStreamFactory::registerFactory();
|
||||
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,".");
|
||||
Poco::Path ConfigFile;
|
||||
|
||||
ConfigFile = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
|
||||
LoadConfigurationFile();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static const char * LogFilePathKey = "logging.channels.c2.path";
|
||||
|
||||
loadConfiguration(ConfigFile.toString());
|
||||
static const char * LogFilePathKey = "logging.channels.c2.path";
|
||||
|
||||
if(LogDir_.empty()) {
|
||||
std::string OriginalLogFileValue = ConfigPath(LogFilePathKey);
|
||||
@@ -172,7 +211,8 @@ namespace uCentral {
|
||||
} else {
|
||||
config().setString(LogFilePathKey, LogDir_);
|
||||
}
|
||||
Poco::File DataDir(ConfigPath("ucentral.system.data"));
|
||||
|
||||
Poco::File DataDir(ConfigPath("openwifi.system.data"));
|
||||
DataDir_ = DataDir.path();
|
||||
if(!DataDir.exists()) {
|
||||
try {
|
||||
@@ -181,17 +221,9 @@ namespace uCentral {
|
||||
logger().log(E);
|
||||
}
|
||||
}
|
||||
std::string KeyFile = ConfigPath("ucentral.service.key");
|
||||
std::string KeyFilePassword = ConfigPath("ucentral.service.key.password" , "" );
|
||||
AppKey_ = Poco::SharedPtr<Poco::Crypto::RSAKey>(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword));
|
||||
Cipher_ = CipherFactory_.createCipher(*AppKey_);
|
||||
ID_ = Utils::GetSystemId();
|
||||
if(!DebugMode_)
|
||||
DebugMode_ = ConfigGetBool("ucentral.system.debug",false);
|
||||
MyPrivateEndPoint_ = ConfigGetString("ucentral.system.uri.private");
|
||||
MyPublicEndPoint_ = ConfigGetString("ucentral.system.uri.public");
|
||||
UIURI_ = ConfigGetString("ucentral.system.uri.ui");
|
||||
MyHash_ = CreateHash(MyPublicEndPoint_);
|
||||
|
||||
LoadMyConfig();
|
||||
|
||||
InitializeSubSystemServers();
|
||||
ServerApplication::initialize(self);
|
||||
|
||||
@@ -326,14 +358,23 @@ namespace uCentral {
|
||||
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(i->Name());
|
||||
Result.push_back(Poco::toLower(i->Name()));
|
||||
return Result;
|
||||
}
|
||||
|
||||
Types::StringPairVec MicroService::GetLogLevels() const {
|
||||
Types::StringPairVec MicroService::GetLogLevels() {
|
||||
Types::StringPairVec Result;
|
||||
|
||||
for(auto &i:SubSystems_) {
|
||||
@@ -343,7 +384,7 @@ namespace uCentral {
|
||||
return Result;
|
||||
}
|
||||
|
||||
const Types::StringVec & MicroService::GetLogLevelNames() const {
|
||||
const Types::StringVec & MicroService::GetLogLevelNames() {
|
||||
static Types::StringVec LevelNames{"none", "fatal", "critical", "error", "warning", "notice", "information", "debug", "trace" };
|
||||
return LevelNames;
|
||||
}
|
||||
@@ -417,7 +458,7 @@ namespace uCentral {
|
||||
Poco::Thread::trySleep((unsigned long)Daemon()->DaemonBusTimer());
|
||||
if(!Running_)
|
||||
break;
|
||||
auto Msg = Daemon()->MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
|
||||
Msg = Daemon()->MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,Daemon()->PrivateEndPoint(),Msg, false);
|
||||
}
|
||||
Msg = Daemon()->MakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-06-22.
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALGW_MICROSERVICE_H
|
||||
@@ -24,16 +28,17 @@
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Process.h"
|
||||
|
||||
#include "uCentralTypes.h"
|
||||
#include "OpenWifiTypes.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
static const std::string uSERVICE_SECURITY{"ucentralsec"};
|
||||
static const std::string uSERVICE_GATEWAY{"ucentralgw"};
|
||||
static const std::string uSERVICE_FIRMWARE{ "ucentralfws"};
|
||||
static const std::string uSERVICE_TOPOLOGY{ "ucentraltopo"};
|
||||
static const std::string uSERVICE_PROVISIONING{ "ucentralprov"};
|
||||
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"};
|
||||
|
||||
class MyErrorHandler : public Poco::ErrorHandler {
|
||||
public:
|
||||
@@ -82,9 +87,6 @@ namespace uCentral {
|
||||
DAEMON_APP_NAME(std::move(AppName)),
|
||||
DAEMON_BUS_TIMER(BusTimer),
|
||||
SubSystems_(std::move(Subsystems)) {
|
||||
std::string V{APP_VERSION};
|
||||
std::string B{BUILD_NUMBER};
|
||||
Version_ = V + "(" + B + ")";
|
||||
}
|
||||
|
||||
int main(const ArgVec &args) override;
|
||||
@@ -111,8 +113,8 @@ namespace uCentral {
|
||||
[[nodiscard]] bool Debug() const { return DebugMode_; }
|
||||
[[nodiscard]] uint64_t ID() const { return ID_; }
|
||||
[[nodiscard]] Types::StringVec GetSubSystems() const;
|
||||
[[nodiscard]] Types::StringPairVec GetLogLevels() const;
|
||||
[[nodiscard]] const Types::StringVec & GetLogLevelNames() const;
|
||||
[[nodiscard]] Types::StringPairVec GetLogLevels() ;
|
||||
[[nodiscard]] static const Types::StringVec & GetLogLevelNames();
|
||||
[[nodiscard]] std::string ConfigGetString(const std::string &Key,const std::string & Default);
|
||||
[[nodiscard]] std::string ConfigGetString(const std::string &Key);
|
||||
[[nodiscard]] std::string ConfigPath(const std::string &Key,const std::string & Default);
|
||||
@@ -129,18 +131,26 @@ namespace uCentral {
|
||||
[[nodiscard]] std::string PrivateEndPoint() const { return MyPrivateEndPoint_; };
|
||||
[[nodiscard]] std::string PublicEndPoint() const { return MyPublicEndPoint_; };
|
||||
[[nodiscard]] std::string MakeSystemEventMessage( const std::string & Type ) const ;
|
||||
[[nodiscard]] const Types::SubSystemVec & GetFullSubSystems() { return SubSystems_; }
|
||||
inline uint64_t DaemonBusTimer() const { return DAEMON_BUS_TIMER; };
|
||||
|
||||
void BusMessageReceived( const std::string & Key, const std::string & Message);
|
||||
[[nodiscard]] MicroServiceMetaVec GetServices(const std::string & type);
|
||||
[[nodiscard]] MicroServiceMetaVec GetServices();
|
||||
[[nodiscard]] bool IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
|
||||
[[nodiscard]] const std::string & AppName() { return DAEMON_APP_NAME; }
|
||||
|
||||
void SavePID();
|
||||
inline uint64_t GetPID() { return Poco::Process::id(); };
|
||||
[[nodiscard]] inline const std::string GetPublicAPIEndPoint() const { return MyPublicEndPoint_ + "/api/v1"; };
|
||||
static void SavePID();
|
||||
static inline uint64_t GetPID() { return Poco::Process::id(); };
|
||||
[[nodiscard]] inline const std::string GetPublicAPIEndPoint() { return MyPublicEndPoint_ + "/api/v1"; };
|
||||
[[nodiscard]] inline const std::string & GetUIURI() const { return UIURI_;};
|
||||
|
||||
void Reload(const std::string &Name); // reload a subsystem
|
||||
void Reload(); // reload the daemon itself
|
||||
void LoadMyConfig();
|
||||
|
||||
void LoadConfigurationFile();
|
||||
|
||||
private:
|
||||
bool HelpRequested_ = false;
|
||||
std::string LogDir_;
|
||||
@@ -159,9 +169,9 @@ namespace uCentral {
|
||||
std::string MyPrivateEndPoint_;
|
||||
std::string MyPublicEndPoint_;
|
||||
std::string UIURI_;
|
||||
std::string Version_;
|
||||
std::string Version_{std::string(APP_VERSION) + "("+ BUILD_NUMBER + ")"};
|
||||
BusEventManager BusEventManager_;
|
||||
SubMutex InfraMutex_;
|
||||
std::mutex InfraMutex_;
|
||||
|
||||
std::string DAEMON_PROPERTIES_FILENAME;
|
||||
std::string DAEMON_ROOT_ENV_VAR;
|
||||
|
||||
819
src/NewWebSocketServer.cpp
Normal file
819
src/NewWebSocketServer.cpp
Normal file
@@ -0,0 +1,819 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
#include "Poco/Net/IPAddress.h"
|
||||
#include "Poco/Net/SSLException.h"
|
||||
#include "Poco/Net/HTTPServerSession.h"
|
||||
#include "Poco/Net/HTTPHeaderStream.h"
|
||||
#include "Poco/Net/HTTPServerRequestImpl.h"
|
||||
#include "Poco/JSON/Array.h"
|
||||
#include "Poco/zlib.h"
|
||||
|
||||
#include "CommandManager.h"
|
||||
#include "Daemon.h"
|
||||
#include "KafkaManager.h"
|
||||
#include "Kafka_topics.h"
|
||||
#include "StorageService.h"
|
||||
#include "Utils.h"
|
||||
#include "WebSocketServer.h"
|
||||
#include "uCentralProtocol.h"
|
||||
#include "TelemetryStream.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class WebSocketServer *WebSocketServer::instance_ = nullptr;
|
||||
|
||||
bool WebSocketServer::ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate) {
|
||||
if(IsCertOk()) {
|
||||
Logger_.debug(Poco::format("CERTIFICATE(%s): issuer='%s' cn='%s'", ConnectionId, Certificate.issuerName(),Certificate.commonName()));
|
||||
if(!Certificate.issuedBy(*IssuerCert_)) {
|
||||
Logger_.debug(Poco::format("CERTIFICATE(%s): issuer mismatch. Local='%s' Incoming='%s'", ConnectionId, IssuerCert_->issuerName(), Certificate.issuerName()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int WebSocketServer::Start() {
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
ReactorPool_.Start();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Net::Context::Params P;
|
||||
P.verificationMode = Poco::Net::Context::VERIFY_STRICT;
|
||||
P.certificateFile = Daemon()->ConfigPath("ucentral.websocket.host.0.cert");
|
||||
P.privateKeyFile = Daemon()->ConfigPath("ucentral.websocket.host.0.key");
|
||||
P.loadDefaultCAs = true ;
|
||||
P.caLocation = Daemon()->ConfigPath("ucentral.websocket.host.0.cas");
|
||||
P.verificationDepth = 9 ;
|
||||
P.cipherList = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
|
||||
P.dhUse2048Bits = true;
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6 : Poco::Net::AddressFamily::IPv4));
|
||||
std::cout << __LINE__ << std::endl;
|
||||
Poco::Net::SocketAddress SockAddr(Addr, 15002);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
auto Context = Poco::AutoPtr<Poco::Net::Context>(new Poco::Net::Context(Poco::Net::Context::TLS_SERVER_USE, P));
|
||||
std::cout << __LINE__ << std::endl;
|
||||
auto Params = new Poco::Net::HTTPServerParams;
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
Params->setMaxThreads(50);
|
||||
Params->setMaxQueued(200);
|
||||
Params->setKeepAlive(true);
|
||||
|
||||
std::cout << __LINE__ << std::endl;
|
||||
auto Sock = Poco::Net::SecureServerSocket(SockAddr, 200, Context);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new WebSocketRequestHandlerFactory(ReactorPool_,Logger_), Pool_, Sock, Params);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
NewServer->start();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
WebServers_.push_back(std::move(NewServer));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebSocketServer::Stop() {
|
||||
Logger_.notice("Stopping reactors...");
|
||||
Logger_.information("Stopping ");
|
||||
for( const auto & svr : WebServers_ )
|
||||
svr->stop();
|
||||
ReactorPool_.Stop();
|
||||
}
|
||||
|
||||
void WSConnection::LogException(const Poco::Exception &E) {
|
||||
Logger_.information(Poco::format("EXCEPTION(%s): %s",CId_,E.displayText()));
|
||||
}
|
||||
|
||||
void WSConnection::CompleteStartup() {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
try {
|
||||
Socket_ = *WS_;
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
auto SS = dynamic_cast<Poco::Net::SecureStreamSocketImpl *>(WS_->impl());
|
||||
std::cout << __LINE__ << std::endl;
|
||||
SS->completeHandshake();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
CId_ = Utils::FormatIPv6(SS->peerAddress().toString());
|
||||
std::cout << __LINE__ << std::endl;
|
||||
if (!SS->secure()) {
|
||||
Logger_.error(Poco::format("%s: Connection is NOT secure.", CId_));
|
||||
} else {
|
||||
Logger_.debug(Poco::format("%s: Connection is secure.", CId_));
|
||||
}
|
||||
std::cout << __LINE__ << std::endl;
|
||||
if (SS->havePeerCertificate()) {
|
||||
// Get the cert info...
|
||||
CertValidation_ = GWObjects::VALID_CERTIFICATE;
|
||||
try {
|
||||
Poco::Crypto::X509Certificate PeerCert(SS->peerCertificate());
|
||||
|
||||
if (WebSocketServer()->ValidateCertificate(CId_, PeerCert)) {
|
||||
CN_ = Poco::trim(Poco::toLower(PeerCert.commonName()));
|
||||
CertValidation_ = GWObjects::MISMATCH_SERIAL;
|
||||
Logger_.debug(Poco::format("%s: Valid certificate: CN=%s", CId_, CN_));
|
||||
} else {
|
||||
Logger_.debug(Poco::format("%s: Certificate is not valid", CId_));
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
LogException(E);
|
||||
}
|
||||
std::cout << __LINE__ << std::endl;
|
||||
} else {
|
||||
Logger_.error(Poco::format("%s: No certificates available..", CId_));
|
||||
}
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
WS_->setMaxPayloadSize(BufSize);
|
||||
auto TS = Poco::Timespan(240,0);
|
||||
WS_->setReceiveTimeout(TS);
|
||||
WS_->setNoDelay(true);
|
||||
WS_->setKeepAlive(true);
|
||||
Reactor_.addEventHandler(*WS_,
|
||||
Poco::NObserver<WSConnection, Poco::Net::ReadableNotification>(
|
||||
*this, &WSConnection::OnSocketReadable));
|
||||
Reactor_.addEventHandler(*WS_,
|
||||
Poco::NObserver<WSConnection, Poco::Net::ShutdownNotification>(
|
||||
*this, &WSConnection::OnSocketShutdown));
|
||||
Reactor_.addEventHandler(*WS_,
|
||||
Poco::NObserver<WSConnection, Poco::Net::ErrorNotification>(
|
||||
*this, &WSConnection::OnSocketError));
|
||||
Registered_ = true;
|
||||
Logger_.information(Poco::format("CONNECTION(%s): completed.",CId_));
|
||||
std::cout << __LINE__ << std::endl;
|
||||
return;
|
||||
} catch (const Poco::Exception &E ) {
|
||||
Logger_.error("Exception caught during device connection. Device will have to retry.");
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
|
||||
WSConnection::WSConnection(Poco::SharedPtr<Poco::Net::WebSocket> WS, Poco::Net::SocketReactor& Reactor, Poco::Logger &Logger):
|
||||
WS_(WS), Reactor_(Reactor), Logger_(WebSocketServer()->Logger())
|
||||
{
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
std::thread T([this](){ this->CompleteStartup();});
|
||||
std::cout << __LINE__ << std::endl;
|
||||
T.detach();
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
|
||||
WSConnection::~WSConnection() {
|
||||
DeviceRegistry()->UnRegister(SerialNumber_,this);
|
||||
if(Registered_ && WS_)
|
||||
{
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
Poco::NObserver<WSConnection,
|
||||
Poco::Net::ReadableNotification>(*this,&WSConnection::OnSocketReadable));
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
Poco::NObserver<WSConnection,
|
||||
Poco::Net::ShutdownNotification>(*this,&WSConnection::OnSocketShutdown));
|
||||
Reactor_.removeEventHandler(*WS_,
|
||||
Poco::NObserver<WSConnection,
|
||||
Poco::Net::ErrorNotification>(*this,&WSConnection::OnSocketError));
|
||||
(*WS_).close();
|
||||
Socket_.shutdown();
|
||||
} else if(WS_) {
|
||||
(*WS_).close();
|
||||
Socket_.shutdown();
|
||||
}
|
||||
|
||||
if(KafkaManager()->Enabled() && !SerialNumber_.empty()) {
|
||||
Poco::JSON::Object Disconnect;
|
||||
Poco::JSON::Object Details;
|
||||
Details.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
Details.set(uCentralProtocol::TIMESTAMP,std::time(nullptr));
|
||||
Disconnect.set(uCentralProtocol::DISCONNECTION,Details);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(Disconnect,OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
}
|
||||
|
||||
bool WSConnection::LookForUpgrade(uint64_t UUID) {
|
||||
|
||||
|
||||
// A UUID of zero means ignore updates for that connection.
|
||||
if(UUID==0)
|
||||
return false;
|
||||
|
||||
std::string NewConfig;
|
||||
uint64_t NewConfigUUID = 0 ;
|
||||
|
||||
if (Storage()->ExistingConfiguration(SerialNumber_,UUID, NewConfig, NewConfigUUID)) {
|
||||
|
||||
// Device is already using the latest configuration.
|
||||
if(UUID == NewConfigUUID)
|
||||
return false;
|
||||
|
||||
// if the new config is already pending,
|
||||
if(NewConfigUUID == Conn_->PendingUUID)
|
||||
return false;
|
||||
|
||||
Conn_->PendingUUID = NewConfigUUID;
|
||||
|
||||
Poco::JSON::Parser Parser( new Poco::JSON::ParseHandler);
|
||||
auto ParsedConfig = Parser.parse(NewConfig).extract<Poco::JSON::Object::Ptr>();
|
||||
ParsedConfig->set(uCentralProtocol::UUID,NewConfigUUID);
|
||||
|
||||
// create the command stub...
|
||||
GWObjects::CommandDetails Cmd;
|
||||
Cmd.SerialNumber = SerialNumber_;
|
||||
Cmd.UUID = Daemon()->CreateUUID();
|
||||
Cmd.SubmittedBy = uCentralProtocol::SUBMITTED_BY_SYSTEM;
|
||||
Cmd.Status = uCentralProtocol::PENDING;
|
||||
Cmd.Command = uCentralProtocol::CONFIGURE;
|
||||
|
||||
Poco::JSON::Object Params;
|
||||
Params.set(uCentralProtocol::SERIAL, SerialNumber_);
|
||||
Params.set(uCentralProtocol::UUID, NewConfigUUID);
|
||||
Params.set(uCentralProtocol::WHEN, 0);
|
||||
Params.set(uCentralProtocol::CONFIG, ParsedConfig);
|
||||
|
||||
std::string Log = Poco::format("CFG-UPGRADE(%s):, Current ID: %Lu, newer configuration %Lu.", SerialNumber_, UUID, NewConfigUUID);
|
||||
Storage()->AddLog(SerialNumber_, Conn_->UUID, Log);
|
||||
Logger_.debug(Log);
|
||||
|
||||
uint64_t RPC_Id;
|
||||
CommandManager()->SendCommand(SerialNumber_ , Cmd.Command, Params, Cmd.UUID, RPC_Id);
|
||||
Storage()->AddCommand(SerialNumber_, Cmd, Storage::COMMAND_EXECUTED);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WSConnection::ExtractCompressedData(const std::string & CompressedData, std::string & UnCompressedData)
|
||||
{
|
||||
std::vector<uint8_t> OB = Utils::base64decode(CompressedData);
|
||||
|
||||
unsigned long MaxSize=OB.size()*10;
|
||||
std::vector<char> UncompressedBuffer(MaxSize);
|
||||
unsigned long FinalSize = MaxSize;
|
||||
if(uncompress((Bytef *)&UncompressedBuffer[0], & FinalSize, (Bytef *)&OB[0],OB.size())==Z_OK) {
|
||||
UncompressedBuffer[FinalSize] = 0;
|
||||
UnCompressedData = &UncompressedBuffer[0];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WSConnection::ProcessJSONRPCResult(Poco::JSON::Object::Ptr & Doc) {
|
||||
CommandManager()->PostCommandResult(SerialNumber_, Doc);
|
||||
}
|
||||
|
||||
void WSConnection::ProcessJSONRPCEvent(Poco::JSON::Object::Ptr & Doc) {
|
||||
|
||||
auto Method = Doc->get(uCentralProtocol::METHOD).toString();
|
||||
auto EventType = uCentralProtocol::EventFromString(Method);
|
||||
if(EventType == uCentralProtocol::ET_UNKNOWN) {
|
||||
Logger_.error(Poco::format("ILLEGAL-PROTOCOL(%s): Unknown message type '%s'",Method));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Doc->isObject(uCentralProtocol::PARAMS))
|
||||
{
|
||||
Logger_.warning(Poco::format("MISSING-PARAMS(%s): params must be an object.",CId_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
|
||||
// expand params if necessary
|
||||
auto ParamsObj = Doc->get(uCentralProtocol::PARAMS).extract<Poco::JSON::Object::Ptr>();
|
||||
if(ParamsObj->has(uCentralProtocol::COMPRESS_64))
|
||||
{
|
||||
std::string UncompressedData;
|
||||
if(ExtractCompressedData(ParamsObj->get(uCentralProtocol::COMPRESS_64).toString(),UncompressedData)) {
|
||||
Logger_.debug(Poco::format("EVENT(%s): Found compressed payload expanded to '%s'.",CId_, UncompressedData));
|
||||
Poco::JSON::Parser Parser;
|
||||
ParamsObj = Parser.parse(UncompressedData).extract<Poco::JSON::Object::Ptr>();
|
||||
} else {
|
||||
Logger_.warning(Poco::format("INVALID-COMPRESSED-DATA(%s): Compressed cannot be uncompressed - content must be corrupt..",CId_));
|
||||
Errors_++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(!ParamsObj->has(uCentralProtocol::SERIAL))
|
||||
{
|
||||
Logger_.warning(Poco::format("MISSING-PARAMS(%s): Serial number is missing in message.",CId_));
|
||||
return;
|
||||
}
|
||||
|
||||
auto Serial = Poco::trim(Poco::toLower(ParamsObj->get(uCentralProtocol::SERIAL).toString()));
|
||||
if(!Utils::ValidSerialNumber(Serial)) {
|
||||
Poco::Exception E(Poco::format("ILLEGAL-DEVICE-NAME(%s): device name is illegal and not allowed to connect.",Serial), EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
if(Storage()->IsBlackListed(Serial)) {
|
||||
Poco::Exception E(Poco::format("BLACKLIST(%s): device is blacklisted and not allowed to connect.",Serial), EACCES);
|
||||
E.rethrow();
|
||||
}
|
||||
|
||||
if(Conn_!= nullptr)
|
||||
Conn_->LastContact = std::time(nullptr);
|
||||
|
||||
switch(EventType) {
|
||||
case uCentralProtocol::ET_CONNECT: {
|
||||
if( ParamsObj->has(uCentralProtocol::UUID) &&
|
||||
ParamsObj->has(uCentralProtocol::FIRMWARE) &&
|
||||
ParamsObj->has(uCentralProtocol::CAPABILITIES)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Firmware = ParamsObj->get(uCentralProtocol::FIRMWARE).toString();
|
||||
auto Capabilities = ParamsObj->get(uCentralProtocol::CAPABILITIES).toString();
|
||||
|
||||
Conn_ = DeviceRegistry()->Register(Serial, this);
|
||||
SerialNumber_ = Serial;
|
||||
Conn_->SerialNumber = Serial;
|
||||
Conn_->UUID = UUID;
|
||||
Conn_->Firmware = Firmware;
|
||||
Conn_->PendingUUID = 0;
|
||||
Conn_->LastContact = std::time(nullptr);
|
||||
Conn_->Address = Utils::FormatIPv6(WS_->peerAddress().toString());
|
||||
CId_ = SerialNumber_ + "@" + CId_ ;
|
||||
|
||||
// We need to verify the certificate if we have one
|
||||
if(!CN_.empty() && Utils::SerialNumberMatch(CN_,SerialNumber_)) {
|
||||
CertValidation_ = GWObjects::VERIFIED;
|
||||
Logger_.information(Poco::format("CONNECT(%s): Fully validated and authenticated device..", CId_));
|
||||
} else {
|
||||
if(CN_.empty())
|
||||
Logger_.information(Poco::format("CONNECT(%s): Not authenticated or validated.", CId_));
|
||||
else
|
||||
Logger_.information(Poco::format("CONNECT(%s): Authenticated but not validated. Serial='%s' CN='%s'", CId_, Serial, CN_));
|
||||
}
|
||||
Conn_->VerifiedCertificate = CertValidation_;
|
||||
|
||||
if (Daemon()->AutoProvisioning() && !Storage()->DeviceExists(SerialNumber_)) {
|
||||
Storage()->CreateDefaultDevice(SerialNumber_, Capabilities, Firmware, Compatible_);
|
||||
} else if (Storage()->DeviceExists(SerialNumber_)) {
|
||||
Storage()->UpdateDeviceCapabilities(SerialNumber_, Capabilities, Compatible_);
|
||||
if(!Firmware.empty()) {
|
||||
Storage()->SetConnectInfo(SerialNumber_, Firmware );
|
||||
}
|
||||
}
|
||||
Conn_->Compatible = Compatible_;
|
||||
|
||||
StatsProcessor_ = std::make_unique<StateProcessor>(Conn_);
|
||||
StatsProcessor_->Initialize(Serial);
|
||||
LookForUpgrade(UUID);
|
||||
|
||||
if(KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj,OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_, OS.str());
|
||||
}
|
||||
|
||||
} else {
|
||||
Logger_.warning(Poco::format("CONNECT(%s): Missing one of uuid, firmware, or capabilities",CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_STATE: {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::STATE)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto State = ParamsObj->get(uCentralProtocol::STATE).toString();
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty())
|
||||
Logger_.debug(Poco::format("STATE(%s): UUID=%Lu Updating.", CId_, UUID));
|
||||
else
|
||||
Logger_.debug(Poco::format("STATE(%s): UUID=%Lu Updating for CMD=%s.", CId_,
|
||||
UUID, request_uuid));
|
||||
|
||||
Conn_->UUID = UUID;
|
||||
Storage()->AddStatisticsData(Serial, UUID, State);
|
||||
DeviceRegistry()->SetStatistics(Serial, State);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
Storage()->SetCommandResult(request_uuid, State);
|
||||
}
|
||||
|
||||
if (StatsProcessor_)
|
||||
StatsProcessor_->Add(State);
|
||||
|
||||
if(KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(ParamsObj,OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::STATE, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
Logger_.warning(Poco::format(
|
||||
"STATE(%s): Invalid request. Missing serial, uuid, or state", CId_));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_HEALTHCHECK: {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::SANITY) && ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
auto Sanity = ParamsObj->get(uCentralProtocol::SANITY);
|
||||
auto CheckData = ParamsObj->get(uCentralProtocol::DATA).toString();
|
||||
if (CheckData.empty())
|
||||
CheckData = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
|
||||
std::string request_uuid;
|
||||
if (ParamsObj->has(uCentralProtocol::REQUEST_UUID))
|
||||
request_uuid = ParamsObj->get(uCentralProtocol::REQUEST_UUID).toString();
|
||||
|
||||
if (request_uuid.empty())
|
||||
Logger_.debug(
|
||||
Poco::format("HEALTHCHECK(%s): UUID=%Lu Updating.", CId_, UUID));
|
||||
else
|
||||
Logger_.debug(Poco::format("HEALTHCHECK(%s): UUID=%Lu Updating for CMD=%s.",
|
||||
CId_, UUID, request_uuid));
|
||||
|
||||
Conn_->UUID = UUID;
|
||||
|
||||
GWObjects::HealthCheck Check;
|
||||
|
||||
Check.Recorded = std::time(nullptr);
|
||||
Check.UUID = UUID;
|
||||
Check.Data = CheckData;
|
||||
Check.Sanity = Sanity;
|
||||
|
||||
Storage()->AddHealthCheckData(Serial, Check);
|
||||
|
||||
if (!request_uuid.empty()) {
|
||||
Storage()->SetCommandResult(request_uuid, CheckData);
|
||||
}
|
||||
|
||||
DeviceRegistry()->SetHealthcheck(Serial, Check);
|
||||
if(KafkaManager()->Enabled()) {
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
ParamsObj->set("timestamp",std::time(nullptr));
|
||||
Stringify.condense(ParamsObj,OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::HEALTHCHECK, SerialNumber_, OS.str());
|
||||
}
|
||||
} else {
|
||||
Logger_.warning(Poco::format("HEALTHCHECK(%s): Missing parameter", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_LOG: {
|
||||
if (ParamsObj->has(uCentralProtocol::LOG) && ParamsObj->has(uCentralProtocol::SEVERITY)) {
|
||||
Logger_.debug(Poco::format("LOG(%s): new entry.", CId_));
|
||||
auto Log = ParamsObj->get(uCentralProtocol::LOG).toString();
|
||||
auto Severity = ParamsObj->get(uCentralProtocol::SEVERITY);
|
||||
std::string DataStr = uCentralProtocol::EMPTY_JSON_DOC;
|
||||
if (ParamsObj->has(uCentralProtocol::DATA)) {
|
||||
auto DataObj = ParamsObj->get(uCentralProtocol::DATA);
|
||||
if (DataObj.isStruct())
|
||||
DataStr = DataObj.toString();
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{.Log = Log,
|
||||
.Data = DataStr,
|
||||
.Severity = Severity,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 0,
|
||||
.UUID = Conn_->UUID};
|
||||
|
||||
Storage()->AddLog(Serial, DeviceLog);
|
||||
} else {
|
||||
Logger_.warning(Poco::format("LOG(%s): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_CRASHLOG: {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
|
||||
Logger_.debug(Poco::format("CRASH-LOG(%s): new entry.", CId_));
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
GWObjects::DeviceLog DeviceLog{
|
||||
.Log = LogText,
|
||||
.Data = "",
|
||||
.Severity = GWObjects::DeviceLog::LOG_EMERG,
|
||||
.Recorded = (uint64_t)time(nullptr),
|
||||
.LogType = 1,
|
||||
.UUID = Conn_->UUID};
|
||||
|
||||
Storage()->AddLog(Serial, DeviceLog, true);
|
||||
} else {
|
||||
Logger_.warning(Poco::format("LOG(%s): Missing parameters.", CId_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_PING: {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID)) {
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
Logger_.debug(Poco::format("PING(%s): Current config is %Lu", CId_, UUID));
|
||||
} else {
|
||||
Logger_.warning(Poco::format("PING(%s): Missing parameter.", CId_));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_CFGPENDING: {
|
||||
if (ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::ACTIVE)) {
|
||||
|
||||
uint64_t UUID = ParamsObj->get(uCentralProtocol::UUID);
|
||||
uint64_t Active = ParamsObj->get(uCentralProtocol::ACTIVE);
|
||||
|
||||
Logger_.debug(Poco::format("CFG-PENDING(%s): Active: %Lu Target: %Lu", CId_,
|
||||
Active, UUID));
|
||||
} else {
|
||||
Logger_.warning(Poco::format("CFG-PENDING(%s): Missing some parameters", CId_));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_RECOVERY: {
|
||||
if (ParamsObj->has(uCentralProtocol::SERIAL) && ParamsObj->has(uCentralProtocol::FIRMWARE) &&
|
||||
ParamsObj->has(uCentralProtocol::UUID) && ParamsObj->has(uCentralProtocol::REBOOT) &&
|
||||
ParamsObj->has(uCentralProtocol::LOGLINES)) {
|
||||
|
||||
auto LogLines = ParamsObj->get(uCentralProtocol::LOGLINES);
|
||||
std::string LogText;
|
||||
if (LogLines.isArray()) {
|
||||
auto LogLinesArray = LogLines.extract<Poco::JSON::Array::Ptr>();
|
||||
for (const auto &i : *LogLinesArray)
|
||||
LogText += i.toString() + "\r\n";
|
||||
}
|
||||
|
||||
} else {
|
||||
Logger_.error(Poco::format(
|
||||
"RECOVERY(%s): Recovery missing one of firmware, uuid, loglines, reboot",
|
||||
Serial));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_DEVICEUPDATE: {
|
||||
if (ParamsObj->has("currentPassword")) {
|
||||
auto Password = ParamsObj->get("currentPassword").toString();
|
||||
|
||||
Storage()->SetDevicePassword(Serial, Password);
|
||||
Logger_.error(Poco::format(
|
||||
"DEVICEUPDATE(%s): Device is updating its login password.", Serial));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case uCentralProtocol::ET_TELEMETRY: {
|
||||
std::cout << "Telemetry date..." << std::endl;
|
||||
if(ParamsObj->has("data")) {
|
||||
auto Payload = ParamsObj->get("data").toString();
|
||||
TelemetryStream()->UpdateEndPoint(SerialNumber_, Payload);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// this will never be called but some compilers will complain if we do not have a case for
|
||||
// every single values of an enum
|
||||
case uCentralProtocol::ET_UNKNOWN: {
|
||||
Logger_.error(Poco::format("ILLEGAL-EVENT(%s): Event '%s' unknown", CId_, Method));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WSConnection::OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger_.information(Poco::format("SOCKET-SHUTDOWN(%s): Closing.",CId_));
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WSConnection::OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Logger_.information(Poco::format("SOCKET-ERROR(%s): Closing.",CId_));
|
||||
delete this;
|
||||
}
|
||||
|
||||
void WSConnection::OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
try
|
||||
{
|
||||
ProcessIncomingFrame();
|
||||
}
|
||||
catch (const Poco::Exception & E)
|
||||
{
|
||||
Logger_.log(E);
|
||||
delete this;
|
||||
}
|
||||
catch (const std::exception & E) {
|
||||
std::string W = E.what();
|
||||
Logger_.information(Poco::format("std::exception caught: %s. Connection terminated with %s",W,CId_));
|
||||
delete this;
|
||||
}
|
||||
catch ( ... ) {
|
||||
Logger_.information(Poco::format("Unknown exception for %s. Connection terminated.",CId_));
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
std::string asString(Poco::Buffer<char> & buf ) {
|
||||
if(buf.sizeBytes()>0) {
|
||||
buf.append(0);
|
||||
return buf.begin();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void WSConnection::ProcessIncomingFrame() {
|
||||
|
||||
bool MustDisconnect=false;
|
||||
Poco::Buffer<char> IncomingFrame(0);
|
||||
|
||||
try {
|
||||
int Op,flags;
|
||||
int IncomingSize;
|
||||
IncomingSize = WS_->receiveFrame(IncomingFrame,flags);
|
||||
Op = flags & Poco::Net::WebSocket::FRAME_OP_BITMASK;
|
||||
|
||||
// std::cout << "ID:" << CId_ << " Size=" << IncomingSize << " Flags=" << flags << " Op=" << Op << std::endl;
|
||||
|
||||
if (IncomingSize == 0 && flags == 0 && Op == 0) {
|
||||
Logger_.information(Poco::format("DISCONNECT(%s): device has disconnected.", CId_));
|
||||
MustDisconnect = true;
|
||||
} else {
|
||||
switch (Op) {
|
||||
case Poco::Net::WebSocket::FRAME_OP_PING: {
|
||||
Logger_.debug(Poco::format("WS-PING(%s): received. PONG sent back.", CId_));
|
||||
WS_->sendFrame("", 0,
|
||||
(int)Poco::Net::WebSocket::FRAME_OP_PONG |
|
||||
(int)Poco::Net::WebSocket::FRAME_FLAG_FIN);
|
||||
if (KafkaManager()->Enabled() && Conn_) {
|
||||
Poco::JSON::Object PingObject;
|
||||
Poco::JSON::Object PingDetails;
|
||||
PingDetails.set(uCentralProtocol::FIRMWARE, Conn_->Firmware);
|
||||
PingDetails.set(uCentralProtocol::SERIALNUMBER, SerialNumber_);
|
||||
PingDetails.set(uCentralProtocol::COMPATIBLE, Compatible_);
|
||||
PingObject.set(uCentralProtocol::PING,PingDetails);
|
||||
Poco::JSON::Stringifier Stringify;
|
||||
std::ostringstream OS;
|
||||
Stringify.condense(PingObject, OS);
|
||||
KafkaManager()->PostMessage(KafkaTopics::CONNECTION, SerialNumber_,
|
||||
OS.str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_PONG: {
|
||||
Logger_.debug(Poco::format("PONG(%s): received and ignored.",CId_));
|
||||
}
|
||||
break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_TEXT: {
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.debug(Poco::format("FRAME(%s): Frame received (length=%d, flags=0x%x). Msg=%s",
|
||||
CId_, IncomingSize, unsigned(flags),IncomingMessageStr));
|
||||
|
||||
Poco::JSON::Parser parser;
|
||||
auto ParsedMessage = parser.parse(IncomingMessageStr);
|
||||
auto IncomingJSON = ParsedMessage.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if (IncomingJSON->has(uCentralProtocol::JSONRPC)) {
|
||||
if(IncomingJSON->has(uCentralProtocol::METHOD) &&
|
||||
IncomingJSON->has(uCentralProtocol::PARAMS)) {
|
||||
ProcessJSONRPCEvent(IncomingJSON);
|
||||
} else if (IncomingJSON->has(uCentralProtocol::RESULT) &&
|
||||
IncomingJSON->has(uCentralProtocol::ID)) {
|
||||
Logger_.debug(Poco::format("RPC-RESULT(%s): payload: %s",CId_,IncomingMessageStr));
|
||||
ProcessJSONRPCResult(IncomingJSON);
|
||||
} else {
|
||||
Logger_.warning(Poco::format(
|
||||
"INVALID-PAYLOAD(%s): Payload is not JSON-RPC 2.0: %s", CId_,
|
||||
IncomingMessageStr));
|
||||
}
|
||||
} else {
|
||||
Logger_.error(Poco::format("FRAME(%s): illegal transaction header, missing 'jsonrpc'",CId_));
|
||||
Errors_++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Poco::Net::WebSocket::FRAME_OP_CLOSE: {
|
||||
Logger_.warning(Poco::format("CLOSE(%s): Device is closing its connection.",CId_));
|
||||
MustDisconnect = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
Logger_.warning(Poco::format("UNKNOWN(%s): unknownWS Frame operation: %s",CId_, std::to_string(Op)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (Conn_ != nullptr) {
|
||||
Conn_->RX += IncomingSize;
|
||||
Conn_->MessageCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const Poco::Net::ConnectionResetException & E)
|
||||
{
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning(Poco::format("%s(%s): Caught a ConnectionResetException: %s, Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(),IncomingMessageStr));
|
||||
MustDisconnect= true;
|
||||
}
|
||||
catch (const Poco::JSON::JSONException & E)
|
||||
{
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning(Poco::format("%s(%s): Caught a JSONException: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
}
|
||||
catch (const Poco::Net::WebSocketException & E)
|
||||
{
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning(Poco::format("%s(%s): Caught a websocket exception: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException & E)
|
||||
{
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning(Poco::format("%s(%s): Caught a SSLConnectionUnexpectedlyClosedException: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
catch (const Poco::Net::SSLException & E)
|
||||
{
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning(Poco::format("%s(%s): Caught a SSL exception: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
catch (const Poco::Net::NetException & E) {
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning( Poco::format("%s(%s): Caught a NetException: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
catch (const Poco::IOException & E) {
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning( Poco::format("%s(%s): Caught a IOException: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
catch (const Poco::Exception &E) {
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning( Poco::format("%s(%s): Caught a more generic Poco exception: %s. Message: %s",
|
||||
std::string(__func__), CId_, E.displayText(), IncomingMessageStr ));
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
catch (const std::exception & E) {
|
||||
std::string IncomingMessageStr = asString(IncomingFrame);
|
||||
Logger_.warning( Poco::format("%s(%s): Caught a std::exception: %s. Message: %s",
|
||||
std::string{__func__}, CId_, std::string{E.what()}, IncomingMessageStr) );
|
||||
MustDisconnect = true ;
|
||||
}
|
||||
|
||||
if(!MustDisconnect && Errors_<10)
|
||||
return;
|
||||
|
||||
if(Errors_>10) {
|
||||
Logger_.information(Poco::format("DISCONNECTING(%s): Too many errors",CId_));
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
bool WSConnection::Send(const std::string &Payload) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
auto BytesSent = WS_->sendFrame(Payload.c_str(),(int)Payload.size());
|
||||
if(Conn_)
|
||||
Conn_->TX += BytesSent;
|
||||
return BytesSent == Payload.size();
|
||||
}
|
||||
|
||||
} //namespace
|
||||
192
src/NewWebSocketServer.h
Normal file
192
src/NewWebSocketServer.h
Normal file
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRAL_UCENTRALWEBSOCKETSERVER_H
|
||||
#define UCENTRAL_UCENTRALWEBSOCKETSERVER_H
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
|
||||
#include "DeviceRegistry.h"
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
#include "StateProcessor.h"
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
#include "Poco/AutoPtr.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/DynamicAny.h"
|
||||
#include "Poco/Net/SocketReactor.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/NObserver.h"
|
||||
#include "Poco/Net/SocketAcceptor.h"
|
||||
#include "Poco/Net/SocketNotification.h"
|
||||
#include "Poco/Net/StreamSocket.h"
|
||||
#include "Poco/Net/SecureStreamSocket.h"
|
||||
#include "Poco/Net/SecureStreamSocketImpl.h"
|
||||
#include "Poco/Net/ParallelSocketAcceptor.h"
|
||||
#include "Poco/Environment.h"
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPRequestHandler.h"
|
||||
#include "Poco/Net/HTTPServer.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class ReactorPool {
|
||||
public:
|
||||
ReactorPool( unsigned int NumberOfThreads = Poco::Environment::processorCount() )
|
||||
: NumberOfThreads_(NumberOfThreads)
|
||||
{
|
||||
}
|
||||
|
||||
void Start() {
|
||||
for(auto i=0;i<NumberOfThreads_;++i) {
|
||||
auto NewReactor = std::make_unique<Poco::Net::SocketReactor>();
|
||||
auto NewThread = std::make_unique<Poco::Thread>();
|
||||
NewThread->start(*NewReactor);
|
||||
Reactors_.emplace_back( std::move(NewReactor));
|
||||
Threads_.emplace_back( std::move(NewThread));
|
||||
}
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
for(auto &i:Reactors_)
|
||||
i->stop();
|
||||
for(auto &i:Threads_) {
|
||||
i->join();
|
||||
}
|
||||
}
|
||||
|
||||
Poco::Net::SocketReactor & NextReactor() {
|
||||
NextReactor_ ++;
|
||||
NextReactor_ %= NumberOfThreads_;
|
||||
return *Reactors_[NextReactor_];
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int NumberOfThreads_;
|
||||
unsigned int NextReactor_=0;
|
||||
std::vector<std::unique_ptr<Poco::Net::SocketReactor>> Reactors_;
|
||||
std::vector<std::unique_ptr<Poco::Thread>> Threads_;
|
||||
};
|
||||
|
||||
class WSConnection {
|
||||
static constexpr int BufSize = 64000;
|
||||
public:
|
||||
WSConnection(Poco::SharedPtr<Poco::Net::WebSocket> WS, Poco::Net::SocketReactor& Reactor, Poco::Logger &Logger);
|
||||
~WSConnection();
|
||||
|
||||
void ProcessJSONRPCEvent(Poco::JSON::Object::Ptr & Doc);
|
||||
void ProcessJSONRPCResult(Poco::JSON::Object::Ptr & Doc);
|
||||
void ProcessIncomingFrame();
|
||||
bool Send(const std::string &Payload);
|
||||
void OnSocketReadable(const Poco::AutoPtr<Poco::Net::ReadableNotification>& pNf);
|
||||
void OnSocketShutdown(const Poco::AutoPtr<Poco::Net::ShutdownNotification>& pNf);
|
||||
void OnSocketError(const Poco::AutoPtr<Poco::Net::ErrorNotification>& pNf);
|
||||
bool LookForUpgrade(uint64_t UUID);
|
||||
static bool ExtractCompressedData(const std::string & CompressedData, std::string & UnCompressedData);
|
||||
void LogException(const Poco::Exception &E);
|
||||
[[nodiscard]] GWObjects::CertificateValidation CertificateValidation() const { return CertValidation_; };
|
||||
private:
|
||||
std::recursive_mutex Mutex_;
|
||||
Poco::SharedPtr<Poco::Net::WebSocket> WS_;
|
||||
Poco::Net::SocketReactor & Reactor_;
|
||||
Poco::Logger &Logger_;
|
||||
Poco::Net::StreamSocket Socket_;
|
||||
std::string SerialNumber_;
|
||||
std::string Compatible_;
|
||||
GWObjects::ConnectionState * Conn_ = nullptr;
|
||||
bool Registered_ = false ;
|
||||
std::string CId_;
|
||||
std::string CN_;
|
||||
GWObjects::CertificateValidation CertValidation_ = GWObjects::CertificateValidation::NO_CERTIFICATE;
|
||||
uint64_t Errors_=0;
|
||||
std::unique_ptr<StateProcessor> StatsProcessor_;
|
||||
|
||||
void CompleteStartup();
|
||||
};
|
||||
|
||||
class WebSocketRequestHandler : public Poco::Net::HTTPRequestHandler {
|
||||
public:
|
||||
explicit WebSocketRequestHandler(ReactorPool &Pool, Poco::Logger &Logger) :
|
||||
Pool_(Pool), Logger_(Logger) {}
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest & Request, Poco::Net::HTTPServerResponse & Response) final {
|
||||
try {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
auto WS = Poco::SharedPtr<Poco::Net::WebSocket>(new Poco::Net::WebSocket(Request, Response));
|
||||
std::cout << __LINE__ << std::endl;
|
||||
new WSConnection(WS, Pool_.NextReactor(), Logger_);
|
||||
std::cout << __LINE__ << std::endl;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
std::cout << E.what() << " " << E.name() << " " << E.displayText() << std::endl;
|
||||
} catch (...) {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
}
|
||||
private:
|
||||
ReactorPool &Pool_;
|
||||
Poco::Logger &Logger_;
|
||||
};
|
||||
|
||||
|
||||
class WebSocketRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
explicit WebSocketRequestHandlerFactory(ReactorPool & Pool, Poco::Logger & Logger) :
|
||||
Pool_(Pool),
|
||||
Logger_(Logger)
|
||||
{}
|
||||
|
||||
inline Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest & Request) final {
|
||||
std::cout << __LINE__ << std::endl;
|
||||
return new WebSocketRequestHandler(Pool_,Logger_);
|
||||
}
|
||||
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
ReactorPool & Pool_;
|
||||
};
|
||||
|
||||
|
||||
class WebSocketServer : public SubSystemServer {
|
||||
public:
|
||||
static WebSocketServer *instance() {
|
||||
if (instance_ == nullptr) {
|
||||
instance_ = new WebSocketServer;
|
||||
}
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
bool IsCertOk() { return IssuerCert_!= nullptr; }
|
||||
const Poco::Crypto::X509Certificate & Certificate() const { return *IssuerCert_; }
|
||||
bool ValidateCertificate(const std::string & ConnectionId, const Poco::Crypto::X509Certificate & Certificate);
|
||||
|
||||
private:
|
||||
static WebSocketServer *instance_;
|
||||
std::unique_ptr<Poco::Crypto::X509Certificate> IssuerCert_;
|
||||
ReactorPool ReactorPool_;
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> WebServers_;
|
||||
Poco::ThreadPool Pool_;
|
||||
|
||||
WebSocketServer() noexcept: SubSystemServer("WebSocketServer", "WS-SVR", "nano")
|
||||
{
|
||||
std::cout << __LINE__ << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
inline WebSocketServer * WebSocketServer() { return WebSocketServer::instance(); }
|
||||
|
||||
} //namespace
|
||||
|
||||
#endif //UCENTRAL_UCENTRALWEBSOCKETSERVER_H
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class OUIServer * OUIServer::instance_;
|
||||
|
||||
int OUIServer::Start() {
|
||||
@@ -38,6 +38,13 @@ namespace uCentral {
|
||||
Updater.detach();
|
||||
}
|
||||
|
||||
void OUIServer::reinitialize(Poco::Util::Application &self) {
|
||||
Daemon()->LoadConfigurationFile();
|
||||
Logger_.information("Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
bool OUIServer::GetFile(const std::string &FileName) {
|
||||
try {
|
||||
std::unique_ptr<std::istream> pStr(
|
||||
@@ -102,7 +109,7 @@ namespace uCentral {
|
||||
|
||||
OUIMap TmpOUIs;
|
||||
if(GetFile(LatestOUIFileName) && ProcessFile(LatestOUIFileName, TmpOUIs)) {
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
LastUpdate_ = time(nullptr);
|
||||
Poco::File F1(CurrentOUIFileName);
|
||||
@@ -114,7 +121,7 @@ namespace uCentral {
|
||||
} else if(OUIs_.empty()) {
|
||||
if(ProcessFile(CurrentOUIFileName, TmpOUIs)) {
|
||||
LastUpdate_ = time(nullptr);
|
||||
SubMutexGuard G(Mutex_);
|
||||
std::lock_guard G(Mutex_);
|
||||
OUIs_ = std::move(TmpOUIs);
|
||||
}
|
||||
}
|
||||
@@ -122,7 +129,7 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
std::string OUIServer::GetManufacturer(const std::string &MAC) {
|
||||
SubMutexGuard Guard(Mutex_);
|
||||
std::lock_guard Guard(Mutex_);
|
||||
auto Manufacturer = OUIs_.find(Utils::SerialNumberToOUI(MAC));
|
||||
if(Manufacturer != OUIs_.end())
|
||||
return Manufacturer->second;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class OUIServer : public SubSystemServer {
|
||||
public:
|
||||
@@ -23,6 +23,9 @@ namespace uCentral {
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
|
||||
void Update();
|
||||
void UpdateImpl();
|
||||
[[nodiscard]] std::string GetManufacturer(const std::string &MAC);
|
||||
|
||||
@@ -1,30 +1,33 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-01.
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "OpenAPIRequest.h"
|
||||
|
||||
#include "Poco/Net/HTTPSClientSession.h"
|
||||
#include <Poco/Net/HTTPClientSession.h>
|
||||
#include <Poco/Net/HTTPRequest.h>
|
||||
#include <Poco/Net/HTTPResponse.h>
|
||||
#include <Poco/StreamCopier.h>
|
||||
#include <Poco/JSON/Parser.h>
|
||||
#include <Poco/Path.h>
|
||||
#include <Poco/URI.h>
|
||||
#include <Poco/Exception.h>
|
||||
#include "Utils.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
OpenAPIRequestGet::OpenAPIRequestGet( const std::string & ServiceType,
|
||||
const std::string & EndPoint,
|
||||
OpenAPIRequestGet::OpenAPIRequestGet( std::string ServiceType,
|
||||
std::string EndPoint,
|
||||
Types::StringPairVec & QueryData,
|
||||
uint64_t msTimeout):
|
||||
Type_(ServiceType),
|
||||
EndPoint_(EndPoint),
|
||||
Type_(std::move(ServiceType)),
|
||||
EndPoint_(std::move(EndPoint)),
|
||||
QueryData_(QueryData),
|
||||
msTimeout_(msTimeout) {
|
||||
|
||||
@@ -32,7 +35,7 @@ namespace uCentral {
|
||||
|
||||
int OpenAPIRequestGet::Do(Poco::JSON::Object::Ptr &ResponseObject) {
|
||||
try {
|
||||
auto Services = Daemon()->GetServices(Type_);
|
||||
auto Services = Daemon()->GetServices(Type_);
|
||||
for(auto const &Svc:Services) {
|
||||
Poco::URI URI(Svc.PrivateEndPoint);
|
||||
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
|
||||
@@ -42,7 +45,7 @@ namespace uCentral {
|
||||
URI.addQueryParameter(qp.first, qp.second);
|
||||
|
||||
std::string Path(URI.getPathAndQuery());
|
||||
Session.setTimeout(Poco::Timespan(5, 0));
|
||||
Session.setTimeout(Poco::Timespan(msTimeout_/1000, msTimeout_ % 1000));
|
||||
|
||||
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Path,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-01.
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALGW_OPENAPIREQUEST_H
|
||||
@@ -7,14 +11,14 @@
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
|
||||
#include "uCentralTypes.h"
|
||||
#include "OpenWifiTypes.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class OpenAPIRequestGet {
|
||||
public:
|
||||
explicit OpenAPIRequestGet( const std::string & Type,
|
||||
const std::string & EndPoint,
|
||||
explicit OpenAPIRequestGet( std::string Type,
|
||||
std::string EndPoint,
|
||||
Types::StringPairVec & QueryData,
|
||||
uint64_t msTimeout);
|
||||
int Do(Poco::JSON::Object::Ptr &ResponseObject);
|
||||
|
||||
106
src/OpenWifiTypes.h
Normal file
106
src/OpenWifiTypes.h
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// License type: BSD 3-Clause License
|
||||
// License copy: https://github.com/Telecominfraproject/wlan-cloud-ucentralgw/blob/master/LICENSE
|
||||
//
|
||||
// Created by Stephane Bourque on 2021-03-04.
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALGW_UCENTRALTYPES_H
|
||||
#define UCENTRALGW_UCENTRALTYPES_H
|
||||
|
||||
#include "SubSystemServer.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <queue>
|
||||
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "Poco/JSON/Stringifier.h"
|
||||
|
||||
namespace OpenWifi::Types {
|
||||
typedef std::pair<std::string,std::string> StringPair;
|
||||
typedef std::vector<StringPair> StringPairVec;
|
||||
typedef std::queue<StringPair> StringPairQueue;
|
||||
typedef std::vector<std::string> StringVec;
|
||||
typedef std::set<std::string> StringSet;
|
||||
typedef std::vector<SubSystemServer*> SubSystemVec;
|
||||
typedef std::map<std::string,std::set<std::string>> StringMapStringSet;
|
||||
typedef std::function<void(std::string, std::string)> TopicNotifyFunction;
|
||||
typedef std::list<std::pair<TopicNotifyFunction,int>> TopicNotifyFunctionList;
|
||||
typedef std::map<std::string, TopicNotifyFunctionList> NotifyTable;
|
||||
typedef std::map<std::string,uint64_t> CountedMap;
|
||||
|
||||
typedef std::string UUID_t;
|
||||
typedef std::vector<UUID_t> UUIDvec_t;
|
||||
|
||||
inline void UpdateCountedMap(CountedMap &M, const std::string &S, uint64_t Increment=1) {
|
||||
auto it = M.find(S);
|
||||
if(it==M.end())
|
||||
M[S] = Increment;
|
||||
else
|
||||
it->second += Increment;
|
||||
}
|
||||
|
||||
inline std::string to_string( const StringVec &V) {
|
||||
Poco::JSON::Array O;
|
||||
for(const auto &i:V) {
|
||||
O.add(i);
|
||||
}
|
||||
std::stringstream SS;
|
||||
Poco::JSON::Stringifier::stringify(O,SS);
|
||||
return SS.str();
|
||||
}
|
||||
|
||||
inline std::string to_string( const StringPairVec &V) {
|
||||
Poco::JSON::Array O;
|
||||
for(const auto &i:V) {
|
||||
Poco::JSON::Array OO;
|
||||
OO.add(i.first);
|
||||
OO.add(i.second);
|
||||
O.add(OO);
|
||||
}
|
||||
|
||||
std::stringstream SS;
|
||||
Poco::JSON::Stringifier::stringify(O,SS);
|
||||
return SS.str();
|
||||
}
|
||||
|
||||
inline void from_string(const std::string &S, StringPairVec &V) {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto O = P.parse(S).extract<Poco::JSON::Array::Ptr>();
|
||||
|
||||
for(const auto &i:*O) {
|
||||
auto Inner = i.extract<Poco::JSON::Array::Ptr>();
|
||||
for(const auto &j:*Inner) {
|
||||
auto S1 = i[0].toString();
|
||||
auto S2 = i[1].toString();
|
||||
V.push_back(std::make_pair(S1,S2));
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline void from_string(const std::string &S, StringVec &V) {
|
||||
try {
|
||||
Poco::JSON::Parser P;
|
||||
auto O = P.parse(S).extract<Poco::JSON::Array::Ptr>();
|
||||
|
||||
for(auto const &i:*O) {
|
||||
V.push_back(i.toString());
|
||||
}
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // UCENTRALGW_UCENTRALTYPES_H
|
||||
@@ -13,113 +13,77 @@
|
||||
#include "RESTAPI_BlackList.h"
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_BlackList::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
namespace OpenWifi {
|
||||
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
void RESTAPI_BlackList::DoDelete() {
|
||||
auto SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
ParseParameters(Request);
|
||||
|
||||
try {
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE)
|
||||
DoDelete(Request, Response);
|
||||
else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
DoGet(Request, Response);
|
||||
else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
DoPost(Request, Response);
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.error(Poco::format("%s: failed with %s", std::string(__func__), E.displayText()));
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
|
||||
GWObjects::BlackListedDevice D;
|
||||
if(!Storage()->GetBlackListDevice(SerialNumber, D)) {
|
||||
NotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->DeleteBlackListDevice(SerialNumber)) {
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::CouldNotBeDeleted);
|
||||
}
|
||||
|
||||
void RESTAPI_BlackList::DoDelete(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
|
||||
try {
|
||||
auto SerialNumber = GetBinding(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if (!SerialNumber.empty()) {
|
||||
if (Storage()->DeleteBlackListDevice(SerialNumber)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
}
|
||||
return;
|
||||
void RESTAPI_BlackList::DoGet() {
|
||||
std::vector<GWObjects::BlackListedDevice> Devices;
|
||||
Poco::JSON::Array Objects;
|
||||
if (Storage()->GetBlackListDevices(QB_.Offset, QB_.Limit, Devices)) {
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(RESTAPI::Protocol::DEVICES, Objects);
|
||||
ReturnObject(RetObj);
|
||||
}
|
||||
|
||||
void RESTAPI_BlackList::DoGet(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
InitQueryBlock();
|
||||
void RESTAPI_BlackList::DoPost() {
|
||||
auto Obj = ParseStream();
|
||||
if (Obj->has(RESTAPI::Protocol::DEVICES) &&
|
||||
Obj->isArray(RESTAPI::Protocol::DEVICES)) {
|
||||
std::vector<GWObjects::BlackListedDevice> Devices;
|
||||
|
||||
Poco::JSON::Array Objects;
|
||||
if (Storage()->GetBlackListDevices(QB_.Offset, QB_.Limit, Devices)) {
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
auto DeviceArray = Obj->getArray(RESTAPI::Protocol::DEVICES);
|
||||
for (const auto &i : *DeviceArray) {
|
||||
Poco::JSON::Parser pp;
|
||||
auto InnerObj = pp.parse(i).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::DynamicStruct Vars = *InnerObj;
|
||||
if (Vars.contains(RESTAPI::Protocol::SERIALNUMBER) &&
|
||||
Vars.contains(RESTAPI::Protocol::REASON)) {
|
||||
auto SerialNumber = Vars[RESTAPI::Protocol::SERIALNUMBER].toString();
|
||||
auto Reason = Vars[RESTAPI::Protocol::REASON].toString();
|
||||
GWObjects::BlackListedDevice D{.SerialNumber = SerialNumber,
|
||||
.Reason = Reason,
|
||||
.Author = UserInfo_.webtoken.username_,
|
||||
.Created = (uint64_t)time(nullptr)};
|
||||
Devices.push_back(D);
|
||||
}
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::DEVICES, Objects);
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
|
||||
void RESTAPI_BlackList::DoPost(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
try {
|
||||
Poco::JSON::Parser parser;
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
parser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if (Obj->has(uCentral::RESTAPI::Protocol::DEVICES) &&
|
||||
Obj->isArray(uCentral::RESTAPI::Protocol::DEVICES)) {
|
||||
std::vector<GWObjects::BlackListedDevice> Devices;
|
||||
auto DeviceArray = Obj->getArray(uCentral::RESTAPI::Protocol::DEVICES);
|
||||
for (const auto &i : *DeviceArray) {
|
||||
Poco::JSON::Parser pp;
|
||||
auto InnerObj = pp.parse(i).extract<Poco::JSON::Object::Ptr>();
|
||||
Poco::DynamicStruct Vars = *InnerObj;
|
||||
if (Vars.contains(uCentral::RESTAPI::Protocol::SERIALNUMBER) &&
|
||||
Vars.contains(uCentral::RESTAPI::Protocol::REASON)) {
|
||||
auto SerialNumber = Vars[uCentral::RESTAPI::Protocol::SERIALNUMBER].toString();
|
||||
auto Reason = Vars[uCentral::RESTAPI::Protocol::REASON].toString();
|
||||
GWObjects::BlackListedDevice D{.SerialNumber = SerialNumber,
|
||||
.Reason = Reason,
|
||||
.Author = UserInfo_.webtoken.username_,
|
||||
.Created = (uint64_t)time(nullptr)};
|
||||
Devices.push_back(D);
|
||||
}
|
||||
}
|
||||
if (!Devices.empty()) {
|
||||
if (Storage()->AddBlackListDevices(Devices)) {
|
||||
OK(Request, Response);
|
||||
return;
|
||||
}
|
||||
if (!Devices.empty()) {
|
||||
if (Storage()->AddBlackListDevices(Devices)) {
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
} else {
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
@@ -11,23 +11,22 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_BlackList : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_BlackList(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_BlackList(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
|
||||
void DoGet(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
void DoDelete(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
void DoPost(Poco::Net::HTTPServerRequest &request, Poco::Net::HTTPServerResponse &response);
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/blacklist"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final;
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,16 @@
|
||||
#include "RESTAPI_utils.h"
|
||||
#include "Utils.h"
|
||||
|
||||
using uCentral::RESTAPI_utils::field_to_json;
|
||||
using uCentral::RESTAPI_utils::field_from_json;
|
||||
using uCentral::RESTAPI_utils::EmbedDocument;
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
using OpenWifi::RESTAPI_utils::EmbedDocument;
|
||||
|
||||
namespace uCentral::GWObjects {
|
||||
namespace OpenWifi::GWObjects {
|
||||
|
||||
void Device::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
field_to_json(Obj,"deviceType", uCentral::Daemon::instance()->IdentifyDevice(Compatible));
|
||||
field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible));
|
||||
#endif
|
||||
field_to_json(Obj,"macAddress", MACAddress);
|
||||
field_to_json(Obj,"manufacturer", Manufacturer);
|
||||
@@ -57,13 +57,15 @@ namespace uCentral::GWObjects {
|
||||
if (DeviceRegistry()->GetState(SerialNumber, ConState)) {
|
||||
ConState.to_json(Obj);
|
||||
} else {
|
||||
field_to_json(Obj,"ipAddress", "N/A");
|
||||
field_to_json(Obj,"ipAddress", "");
|
||||
field_to_json(Obj,"txBytes", (uint64_t) 0);
|
||||
field_to_json(Obj,"rxBytes", (uint64_t )0);
|
||||
field_to_json(Obj,"messageCount", (uint64_t )0);
|
||||
field_to_json(Obj,"connected", false);
|
||||
field_to_json(Obj,"lastContact", "N/A");
|
||||
field_to_json(Obj,"lastContact", "");
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
|
||||
field_to_json(Obj,"associations_2G", (uint64_t) 0);
|
||||
field_to_json(Obj,"associations_5G", (uint64_t) 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -176,6 +178,9 @@ namespace uCentral::GWObjects {
|
||||
field_to_json(Obj,"connected", Connected);
|
||||
field_to_json(Obj,"firmware", Firmware);
|
||||
field_to_json(Obj,"lastContact", LastContact);
|
||||
field_to_json(Obj,"associations_2G", Associations_2G);
|
||||
field_to_json(Obj,"associations_5G", Associations_5G);
|
||||
|
||||
switch(VerifiedCertificate) {
|
||||
case NO_CERTIFICATE:
|
||||
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break;
|
||||
@@ -216,6 +221,9 @@ namespace uCentral::GWObjects {
|
||||
field_to_json(Obj,"healths",healths);
|
||||
field_to_json(Obj,"certificates",certificates);
|
||||
field_to_json(Obj,"lastContact",lastContact);
|
||||
field_to_json(Obj,"associations",associations);
|
||||
field_to_json(Obj,"snapshot",snapshot);
|
||||
field_to_json(Obj,"numberOfDevices",numberOfDevices);
|
||||
}
|
||||
|
||||
void Dashboard::reset() {
|
||||
@@ -231,6 +239,9 @@ namespace uCentral::GWObjects {
|
||||
healths.clear();
|
||||
certificates.clear();
|
||||
lastContact.clear();
|
||||
associations.clear();
|
||||
numberOfDevices = 0 ;
|
||||
snapshot = std::time(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace uCentral::GWObjects {
|
||||
namespace OpenWifi::GWObjects {
|
||||
|
||||
enum CertificateValidation {
|
||||
NO_CERTIFICATE,
|
||||
@@ -24,10 +24,12 @@ namespace uCentral::GWObjects {
|
||||
struct ConnectionState {
|
||||
uint64_t MessageCount = 0 ;
|
||||
std::string SerialNumber;
|
||||
std::string Address = "N/A";
|
||||
std::string Address;
|
||||
uint64_t UUID = 0 ;
|
||||
uint64_t PendingUUID = 0 ;
|
||||
uint64_t TX = 0, RX = 0;
|
||||
uint64_t Associations_2G=0;
|
||||
uint64_t Associations_5G=0;
|
||||
bool Connected = false;
|
||||
uint64_t LastContact=0;
|
||||
std::string Firmware;
|
||||
@@ -62,6 +64,7 @@ namespace uCentral::GWObjects {
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID;
|
||||
std::string Data;
|
||||
uint64_t Recorded;
|
||||
@@ -69,6 +72,7 @@ namespace uCentral::GWObjects {
|
||||
};
|
||||
|
||||
struct HealthCheck {
|
||||
std::string SerialNumber;
|
||||
uint64_t UUID;
|
||||
std::string Data;
|
||||
uint64_t Recorded;
|
||||
@@ -94,6 +98,7 @@ namespace uCentral::GWObjects {
|
||||
LOG_INFO = 6, /* informational */
|
||||
LOG_DEBUG = 7 /* debug-level messages */
|
||||
};
|
||||
std::string SerialNumber;
|
||||
std::string Log;
|
||||
std::string Data;
|
||||
uint64_t Severity;
|
||||
@@ -159,6 +164,8 @@ namespace uCentral::GWObjects {
|
||||
};
|
||||
|
||||
struct Dashboard {
|
||||
uint64_t snapshot;
|
||||
uint64_t numberOfDevices;
|
||||
Types::CountedMap commands;
|
||||
Types::CountedMap upTimes;
|
||||
Types::CountedMap memoryUsed;
|
||||
@@ -171,6 +178,7 @@ namespace uCentral::GWObjects {
|
||||
Types::CountedMap healths;
|
||||
Types::CountedMap certificates;
|
||||
Types::CountedMap lastContact;
|
||||
Types::CountedMap associations;
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
void reset();
|
||||
};
|
||||
|
||||
5
src/RESTAPI_GenericServer.cpp
Normal file
5
src/RESTAPI_GenericServer.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-15.
|
||||
//
|
||||
|
||||
#include "RESTAPI_GenericServer.h"
|
||||
78
src/RESTAPI_GenericServer.h
Normal file
78
src/RESTAPI_GenericServer.h
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-15.
|
||||
//
|
||||
|
||||
#ifndef OWPROV_RESTAPI_GENERICSERVER_H
|
||||
#define OWPROV_RESTAPI_GENERICSERVER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "Daemon.h"
|
||||
#include "Poco/StringTokenizer.h"
|
||||
#include "Poco/Net/HTTPRequest.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPI_GenericServer {
|
||||
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 = Daemon()->ConfigGetString("apilogging.public.methods","PUT,POST,DELETE");
|
||||
SetFlags(true, Public);
|
||||
std::string Private = Daemon()->ConfigGetString("apilogging.private.methods","PUT,POST,DELETE");
|
||||
SetFlags(false, Private);
|
||||
|
||||
std::string PublicBadTokens = Daemon()->ConfigGetString("apilogging.public.badtokens.methods","");
|
||||
LogBadTokens_[0] = (Poco::icompare(PublicBadTokens,"true")==0);
|
||||
std::string PrivateBadTokens = Daemon()->ConfigGetString("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};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif //OWPROV_RESTAPI_GENERICSERVER_H
|
||||
@@ -18,16 +18,13 @@
|
||||
#include "RESTAPI_ouis.h"
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPI_InternalServer *RESTAPI_InternalServer::instance_ = nullptr;
|
||||
|
||||
RESTAPI_InternalServer::RESTAPI_InternalServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "ucentral.internal.restapi")
|
||||
{
|
||||
}
|
||||
|
||||
int RESTAPI_InternalServer::Start() {
|
||||
Logger_.information("Starting.");
|
||||
Server_.InitLogging();
|
||||
|
||||
for(const auto & Svr: ConfigServersList_) {
|
||||
Logger_.information(Poco::format("Starting: %s:%s Keyfile:%s CertFile: %s", Svr.Address(), std::to_string(Svr.Port()),
|
||||
@@ -43,7 +40,7 @@ namespace uCentral {
|
||||
Params->setMaxQueued(200);
|
||||
Params->setKeepAlive(true);
|
||||
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new InternalRequestHandlerFactory, Pool_, Sock, Params);
|
||||
auto NewServer = std::make_unique<Poco::Net::HTTPServer>(new InternalRequestHandlerFactory(Server_), Pool_, Sock, Params);
|
||||
NewServer->start();
|
||||
RESTServers_.push_back(std::move(NewServer));
|
||||
}
|
||||
@@ -55,12 +52,17 @@ namespace uCentral {
|
||||
Logger_.information("Stopping ");
|
||||
for( const auto & svr : RESTServers_ )
|
||||
svr->stop();
|
||||
RESTServers_.clear();
|
||||
}
|
||||
|
||||
void RESTAPI_InternalServer::reinitialize(Poco::Util::Application &self) {
|
||||
Daemon()->LoadConfigurationFile();
|
||||
Logger_.information("Reinitializing.");
|
||||
Stop();
|
||||
Start();
|
||||
}
|
||||
|
||||
Poco::Net::HTTPRequestHandler *InternalRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest & Request) {
|
||||
|
||||
Logger_.debug(Poco::format("REQUEST(%s): %s %s", uCentral::Utils::FormatIPv6(Request.clientAddress().toString()), Request.getMethod(), Request.getURI()));
|
||||
|
||||
Poco::URI uri(Request.getURI());
|
||||
const auto & Path = uri.getPath();
|
||||
RESTAPIHandler::BindingMap Bindings;
|
||||
@@ -75,6 +77,6 @@ namespace uCentral {
|
||||
RESTAPI_commands,
|
||||
RESTAPI_ouis,
|
||||
RESTAPI_file,
|
||||
RESTAPI_BlackList>(Path,Bindings,Logger_); }
|
||||
RESTAPI_BlackList>(Path,Bindings,Logger_, Server_); }
|
||||
|
||||
}
|
||||
@@ -11,13 +11,13 @@
|
||||
#include "Poco/Net/HTTPRequestHandlerFactory.h"
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include "RESTAPI_GenericServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPI_InternalServer : public SubSystemServer {
|
||||
|
||||
public:
|
||||
RESTAPI_InternalServer() noexcept;
|
||||
|
||||
static RESTAPI_InternalServer *instance() {
|
||||
if (instance_ == nullptr) {
|
||||
@@ -28,23 +28,32 @@ namespace uCentral {
|
||||
|
||||
int Start() override;
|
||||
void Stop() override;
|
||||
void reinitialize(Poco::Util::Application &self) override;
|
||||
|
||||
private:
|
||||
static RESTAPI_InternalServer *instance_;
|
||||
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
|
||||
Poco::ThreadPool Pool_;
|
||||
RESTAPI_GenericServer Server_;
|
||||
|
||||
RESTAPI_InternalServer() noexcept: SubSystemServer("RESTAPIInternalServer", "REST-ISRV", "openwifi.internal.restapi")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
inline RESTAPI_InternalServer * RESTAPI_InternalServer() { return RESTAPI_InternalServer::instance(); };
|
||||
|
||||
class InternalRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
|
||||
public:
|
||||
InternalRequestHandlerFactory() :
|
||||
Logger_(RESTAPI_InternalServer()->Logger()){}
|
||||
explicit InternalRequestHandlerFactory(RESTAPI_GenericServer & Server) :
|
||||
Logger_(RESTAPI_InternalServer()->Logger()),
|
||||
Server_(Server)
|
||||
{}
|
||||
|
||||
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &request) override;
|
||||
private:
|
||||
Poco::Logger & Logger_;
|
||||
RESTAPI_GenericServer & Server_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -13,47 +13,50 @@
|
||||
#include "StorageService.h"
|
||||
#include "DeviceRegistry.h"
|
||||
#include "CommandManager.h"
|
||||
#include "uCentralProtocol.h"
|
||||
|
||||
namespace uCentral::RESTAPI_RPC {
|
||||
void SetCommandAsPending(GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response, RESTAPIHandler *Handler) {
|
||||
if (Storage()->AddCommand(Cmd.SerialNumber, Cmd, Storage::COMMAND_PENDING)) {
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
void SetCommandStatus(GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
RESTAPIHandler *Handler,
|
||||
OpenWifi::Storage::CommandExecutionType Status,
|
||||
Poco::Logger &Logger) {
|
||||
if (Storage()->AddCommand(Cmd.SerialNumber, Cmd, Status)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Cmd.to_json(RetObj);
|
||||
Handler->ReturnObject(Request, RetObj, Response);
|
||||
Handler->ReturnObject(RetObj);
|
||||
return;
|
||||
} else {
|
||||
Handler->ReturnStatus(Request, Response,
|
||||
Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
Handler->ReturnStatus(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitForCommand(GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds D,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler) {
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
int64_t WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger) {
|
||||
|
||||
// if the command should be executed in the future, or if the device is not connected, then we should just add the command to
|
||||
// the DB and let it figure out when to deliver the command.
|
||||
if(Cmd.RunAt || !DeviceRegistry()->Connected(Cmd.SerialNumber)) {
|
||||
SetCommandAsPending(Cmd, Request, Response, Handler);
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
return;
|
||||
} else if(Cmd.RunAt==0 && DeviceRegistry()->Connected(Cmd.SerialNumber)) {
|
||||
auto Promise = std::make_shared<std::promise<Poco::JSON::Object::Ptr>>();
|
||||
std::future<Poco::JSON::Object::Ptr> Future = Promise->get_future();
|
||||
}
|
||||
|
||||
Cmd.Executed = time(nullptr);
|
||||
|
||||
if (CommandManager()->SendCommand(Cmd.SerialNumber, Cmd.Command, Params, Promise, Cmd.UUID)) {
|
||||
auto Status = Future.wait_for(D);
|
||||
if (Status == std::future_status::ready) {
|
||||
auto Answer = Future.get();
|
||||
Cmd.Executed = std::time(nullptr);
|
||||
|
||||
uint64_t RPC_Id=0;
|
||||
if (CommandManager()->SendCommand(Cmd.SerialNumber, Cmd.Command, Params, Cmd.UUID, RPC_Id)) {
|
||||
CommandTag T;
|
||||
while (CommandManager()->Running() && WaitTimeInMs > 0) {
|
||||
if (CommandManager()->GetCommand(RPC_Id, Cmd.SerialNumber, T)) {
|
||||
auto Answer = T.Result;
|
||||
if (Answer->has("result") && Answer->isObject("result")) {
|
||||
auto ResultFields =
|
||||
Answer->get("result").extract<Poco::JSON::Object::Ptr>();
|
||||
@@ -70,63 +73,46 @@ namespace uCentral::RESTAPI_RPC {
|
||||
Cmd.Status = "completed";
|
||||
Cmd.Completed = time(nullptr);
|
||||
|
||||
// Add the completed command to the database...
|
||||
Storage()->AddCommand(Cmd.SerialNumber, Cmd,Storage::COMMAND_COMPLETED);
|
||||
if (Cmd.ErrorCode && Cmd.Command == uCentralProtocol::TRACE) {
|
||||
Cmd.WaitingForFile = 0;
|
||||
Cmd.AttachDate = Cmd.AttachSize = 0;
|
||||
Cmd.AttachType = "";
|
||||
}
|
||||
|
||||
if(ObjectToReturn) {
|
||||
Handler->ReturnObject(Request, *ObjectToReturn, Response);
|
||||
// Add the completed command to the database...
|
||||
Storage()->AddCommand(Cmd.SerialNumber, Cmd,
|
||||
Storage::COMMAND_COMPLETED);
|
||||
|
||||
if (ObjectToReturn) {
|
||||
Handler->ReturnObject(*ObjectToReturn);
|
||||
} else {
|
||||
Poco::JSON::Object O;
|
||||
Cmd.to_json(O);
|
||||
Handler->ReturnObject(Request, O, Response);
|
||||
Handler->ReturnObject(O);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(Poco::format("Invalid response for command '%s'. Missing status.", Cmd.UUID));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommandAsPending(Cmd, Request, Response, Handler);
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_FAILED, Logger);
|
||||
Logger.information(Poco::format("Invalid response for command '%s'. Missing result.", Cmd.UUID));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommandAsPending(Cmd, Request, Response, Handler);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
SetCommandAsPending(Cmd, Request, Response, Handler);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WaitForRPC(GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response, uint64_t Timeout,
|
||||
bool ReturnValue,
|
||||
RESTAPIHandler * Handler) {
|
||||
|
||||
if (DeviceRegistry()->Connected(Cmd.SerialNumber)) {
|
||||
GWObjects::CommandDetails ResCmd;
|
||||
while (Timeout > 0) {
|
||||
Timeout -= 1000;
|
||||
Poco::Thread::sleep(1000);
|
||||
if (Storage()->GetCommand(Cmd.UUID, ResCmd)) {
|
||||
if (ResCmd.Completed) {
|
||||
if (ReturnValue) {
|
||||
Poco::JSON::Object RetObj;
|
||||
ResCmd.to_json(RetObj);
|
||||
Handler->ReturnObject(Request, RetObj, Response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Poco::Thread::trySleep(100);
|
||||
WaitTimeInMs -= 100;
|
||||
}
|
||||
}
|
||||
if(WaitTimeInMs<0)
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_TIMEDOUT, Logger);
|
||||
else
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
} else {
|
||||
SetCommandStatus(Cmd, Request, Response, Handler, Storage::COMMAND_PENDING, Logger);
|
||||
}
|
||||
if (ReturnValue) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Cmd.to_json(RetObj);
|
||||
Handler->ReturnObject(Request, RetObj, Response);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -17,27 +17,25 @@
|
||||
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
#include "RESTAPI_handler.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral::RESTAPI_RPC {
|
||||
namespace OpenWifi::RESTAPI_RPC {
|
||||
|
||||
bool WaitForRPC(GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
uint64_t Timeout,
|
||||
bool ReturnObject,
|
||||
RESTAPIHandler * Handler);
|
||||
|
||||
void WaitForCommand( GWObjects::CommandDetails &Cmd,
|
||||
void WaitForCommand( GWObjects::CommandDetails &Cmd,
|
||||
Poco::JSON::Object & Params,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
std::chrono::milliseconds D,
|
||||
int64_t WaitTimeInMs,
|
||||
Poco::JSON::Object * ObjectToReturn,
|
||||
RESTAPIHandler * Handler);
|
||||
RESTAPIHandler * Handler,
|
||||
Poco::Logger &Logger);
|
||||
|
||||
void SetCommandStatus( GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response, RESTAPIHandler * handler,
|
||||
OpenWifi::Storage::CommandExecutionType Status,
|
||||
Poco::Logger &Logger);
|
||||
|
||||
void SetCommandAsPending(GWObjects::CommandDetails &Cmd,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response, RESTAPIHandler * handler);
|
||||
|
||||
}
|
||||
#endif // UCENTRALGW_RESTAPI_RPC_H
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
#include "RESTAPI_utils.h"
|
||||
|
||||
using uCentral::RESTAPI_utils::field_to_json;
|
||||
using uCentral::RESTAPI_utils::field_from_json;
|
||||
using OpenWifi::RESTAPI_utils::field_to_json;
|
||||
using OpenWifi::RESTAPI_utils::field_from_json;
|
||||
|
||||
namespace uCentral::SecurityObjects {
|
||||
namespace OpenWifi::SecurityObjects {
|
||||
|
||||
void AclTemplate::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"Read",Read_);
|
||||
@@ -303,6 +303,20 @@ namespace uCentral::SecurityObjects {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes) {
|
||||
try {
|
||||
SecurityObjects::NoteInfoVec NIV;
|
||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
|
||||
for(auto const &i:NIV) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UInfo.email, .note=i.note};
|
||||
Notes.push_back(ii);
|
||||
}
|
||||
} catch(...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ProfileAction::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"resource", resource);
|
||||
field_to_json<ResourceAccessType>(Obj,"access", access, ResourceAccessTypeToString);
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#define UCENTRAL_RESTAPI_SECURITYOBJECTS_H
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "uCentralTypes.h"
|
||||
#include "OpenWifiTypes.h"
|
||||
|
||||
namespace uCentral::SecurityObjects {
|
||||
namespace OpenWifi::SecurityObjects {
|
||||
|
||||
struct AclTemplate {
|
||||
bool Read_ = true;
|
||||
@@ -94,6 +94,8 @@ namespace uCentral::SecurityObjects {
|
||||
};
|
||||
typedef std::vector<UserInfo> UserInfoVec;
|
||||
|
||||
bool append_from_json(Poco::JSON::Object::Ptr Obj, const UserInfo &UInfo, NoteInfoVec & Notes);
|
||||
|
||||
struct InternalServiceInfo {
|
||||
std::string privateURI;
|
||||
std::string publicURI;
|
||||
@@ -114,9 +116,9 @@ namespace uCentral::SecurityObjects {
|
||||
struct SystemEndpoint {
|
||||
std::string type;
|
||||
uint64_t id = 0;
|
||||
std::string vendor;
|
||||
std::string vendor{"OpenWiFi"};
|
||||
std::string uri;
|
||||
std::string authenticationType;
|
||||
std::string authenticationType{"internal_v1"};
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
};
|
||||
@@ -158,7 +160,7 @@ namespace uCentral::SecurityObjects {
|
||||
typedef std::vector<ProfileAction> ProfileActionVec;
|
||||
|
||||
struct SecurityProfile {
|
||||
uint64_t id;
|
||||
uint64_t id=0;
|
||||
std::string name;
|
||||
std::string description;
|
||||
ProfileActionVec policy;
|
||||
|
||||
47
src/RESTAPI_TelemetryWebSocket.cpp
Normal file
47
src/RESTAPI_TelemetryWebSocket.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-16.
|
||||
//
|
||||
|
||||
#include "RESTAPI_TelemetryWebSocket.h"
|
||||
#include "Poco/Net/WebSocket.h"
|
||||
#include "TelemetryStream.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_TelemetryWebSocket::DoGet() {
|
||||
// try and upgrade this session to websocket...
|
||||
if (Request->find("Upgrade") != Request->end() &&
|
||||
Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
|
||||
try {
|
||||
Poco::URI U(Request->getURI());
|
||||
std::string UUID, SerialNumber;
|
||||
auto Parameters = U.getQueryParameters();
|
||||
for (const auto &i : Parameters) {
|
||||
if (i.first == "serialNumber") {
|
||||
SerialNumber = i.second;
|
||||
} else if(i.first=="uuid") {
|
||||
UUID = i.second;
|
||||
}
|
||||
}
|
||||
auto WS = Poco::SharedPtr<Poco::Net::WebSocket>( new Poco::Net::WebSocket(*Request, *Response));
|
||||
new TelemetryClient(UUID, SerialNumber, WS, TelemetryStream()->NextReactor(), Logger_);
|
||||
} catch (const Poco::Net::WebSocketException &E) {
|
||||
Logger_.log(E);
|
||||
switch (E.code()) {
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
|
||||
Response->set("Sec-WebSocket-Version", Poco::Net::WebSocket::WEBSOCKET_VERSION);
|
||||
// fallthrough
|
||||
case Poco::Net::WebSocket::WS_ERR_NO_HANDSHAKE:
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
|
||||
case Poco::Net::WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
|
||||
Response->setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Response->setContentLength(0);
|
||||
Response->send();
|
||||
break;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/RESTAPI_TelemetryWebSocket.h
Normal file
28
src/RESTAPI_TelemetryWebSocket.h
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-16.
|
||||
//
|
||||
|
||||
#ifndef OWGW_RESTAPI_TELEMETRYWEBSOCKET_H
|
||||
#define OWGW_RESTAPI_TELEMETRYWEBSOCKET_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_TelemetryWebSocket : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_TelemetryWebSocket(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server, Internal,false) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/ws_telemetry"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final {};
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
private:
|
||||
void Process(const Poco::JSON::Object::Ptr &O, std::string &Answer);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // OWGW_RESTAPI_TELEMETRYWEBSOCKET_H
|
||||
@@ -10,40 +10,40 @@
|
||||
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_command::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
try {
|
||||
ParseParameters(Request);
|
||||
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
auto CommandUUID = GetBinding(uCentral::RESTAPI::Protocol::COMMANDUUID, "");
|
||||
GWObjects::CommandDetails Command;
|
||||
if (Storage()->GetCommand(CommandUUID, Command)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Command.to_json(RetObj);
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
} else
|
||||
NotFound(Request, Response);
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
|
||||
auto CommandUUID = GetBinding(uCentral::RESTAPI::Protocol::COMMANDUUID, "");
|
||||
if (Storage()->DeleteCommand(CommandUUID)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
}
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_command::DoGet() {
|
||||
auto CommandUUID = GetBinding(RESTAPI::Protocol::COMMANDUUID, "");
|
||||
GWObjects::CommandDetails Command;
|
||||
if (Storage()->GetCommand(CommandUUID, Command)) {
|
||||
Poco::JSON::Object RetObj;
|
||||
Command.to_json(RetObj);
|
||||
ReturnObject(RetObj);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.error(Poco::format("%s: failed with %s", std::string(__func__), E.displayText()));
|
||||
NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_command::DoDelete() {
|
||||
auto UUID = GetBinding(RESTAPI::Protocol::COMMANDUUID, "");
|
||||
|
||||
if(UUID.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingUUID);
|
||||
return;
|
||||
}
|
||||
|
||||
GWObjects::CommandDetails C;
|
||||
if(!Storage()->GetCommand(UUID, C)) {
|
||||
NotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->DeleteCommand(UUID)) {
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
|
||||
InternalError();
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
@@ -11,19 +11,22 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_command : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/command/{commandUUID}"};}
|
||||
};
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/command/{commandUUID}"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRAL_RESTAPI_COMMAND_H
|
||||
|
||||
@@ -10,51 +10,42 @@
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "StorageService.h"
|
||||
#include "Utils.h"
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_commands::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_commands::DoGet() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (QB_.Newest) {
|
||||
Storage()->GetNewestCommands(SerialNumber, QB_.Limit, Commands);
|
||||
} else {
|
||||
Storage()->GetCommands(SerialNumber, QB_.StartDate, QB_.EndDate, QB_.Offset, QB_.Limit,
|
||||
Commands);
|
||||
}
|
||||
Poco::JSON::Array ArrayObj;
|
||||
for (const auto &i : Commands) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
ArrayObj.add(Obj);
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(RESTAPI::Protocol::COMMANDS, ArrayObj);
|
||||
ReturnObject(RetObj);
|
||||
}
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
void RESTAPI_commands::DoDelete() {
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
try {
|
||||
ParseParameters(Request);
|
||||
InitQueryBlock();
|
||||
|
||||
auto SerialNumber = GetParameter(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
std::vector<GWObjects::CommandDetails> Commands;
|
||||
if (QB_.Newest) {
|
||||
Storage()->GetNewestCommands(SerialNumber, QB_.Limit, Commands);
|
||||
} else {
|
||||
Storage()->GetCommands(SerialNumber, QB_.StartDate, QB_.EndDate, QB_.Offset,
|
||||
QB_.Limit, Commands);
|
||||
}
|
||||
Poco::JSON::Array ArrayObj;
|
||||
for (const auto &i : Commands) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
ArrayObj.add(Obj);
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::COMMANDS, ArrayObj);
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
return;
|
||||
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
|
||||
if (Storage()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate))
|
||||
OK(Request, Response);
|
||||
else
|
||||
BadRequest(Request, Response);
|
||||
if(SerialNumber.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.error(Poco::format("%s: failed with %s", std::string(__func__), E.displayText()));
|
||||
|
||||
if (Storage()->DeleteCommands(SerialNumber, QB_.StartDate, QB_.EndDate)) {
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
|
||||
InternalError();
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,21 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_commands : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_commands(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_commands(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/commands"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
#endif //UCENTRAL_RESTAPI_COMMANDS_H
|
||||
|
||||
@@ -13,68 +13,72 @@
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_default_configuration::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
std::string Name = GetBinding(uCentral::RESTAPI::Protocol::NAME, "");
|
||||
ParseParameters(Request);
|
||||
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_default_configuration::DoGet() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (Storage()->GetDefaultConfiguration(Name, DefConfig)) {
|
||||
Poco::JSON::Object Obj;
|
||||
DefConfig.to_json(Obj);
|
||||
ReturnObject(Request, Obj, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
ReturnObject(Obj);
|
||||
return;
|
||||
}
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
|
||||
if (Storage()->DeleteDefaultConfiguration(Name)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
}
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
|
||||
Poco::JSON::Parser IncomingParser;
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_default_configuration::DoDelete() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
if(Name.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->DeleteDefaultConfiguration(Name)) {
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::CouldNotBeDeleted);
|
||||
}
|
||||
|
||||
void RESTAPI_default_configuration::DoPost() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
|
||||
if(Name.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
return;
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (!DefConfig.from_json(Obj)) {
|
||||
BadRequest(Request, Response);
|
||||
BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->CreateDefaultConfiguration(Name, DefConfig)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
BadRequest(Request, Response);
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_PUT) {
|
||||
Poco::JSON::Parser IncomingParser;
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
BadRequest(RESTAPI::Errors::RecordNotCreated);
|
||||
}
|
||||
|
||||
void RESTAPI_default_configuration::DoPut() {
|
||||
std::string Name = GetBinding(RESTAPI::Protocol::NAME, "");
|
||||
|
||||
auto Obj = ParseStream();
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
|
||||
GWObjects::DefaultConfiguration DefConfig;
|
||||
if (!DefConfig.from_json(Obj)) {
|
||||
BadRequest(Request, Response);
|
||||
BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->UpdateDefaultConfiguration(Name, DefConfig)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
BadRequest(Request, Response);
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
BadRequest(Request, Response);
|
||||
BadRequest(RESTAPI::Errors::RecordNotUpdated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,19 +11,22 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_default_configuration : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_default_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_default_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/default_configuration/{name}"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final;
|
||||
void DoPut() final;
|
||||
};
|
||||
}
|
||||
#endif //UCENTRAL_RESTAPI_DEFAULT_CONFIGURATION_H
|
||||
|
||||
@@ -13,45 +13,20 @@
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_default_configurations::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_default_configurations::DoGet() {
|
||||
std::vector<GWObjects::DefaultConfiguration> DefConfigs;
|
||||
Storage()->GetDefaultConfigurations(QB_.Offset, QB_.Limit, DefConfigs);
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : DefConfigs) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
}
|
||||
|
||||
try {
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
ParseParameters(Request);
|
||||
InitQueryBlock();
|
||||
|
||||
Logger_.information(
|
||||
Poco::format("DEFAULT_CONFIGURATIONS: from %Lu, limit of %Lu, filter=%s.",
|
||||
(int64_t)QB_.Offset, (int64_t)QB_.Limit, QB_.Filter));
|
||||
RESTAPIHandler::PrintBindings();
|
||||
|
||||
std::vector<GWObjects::DefaultConfiguration> DefConfigs;
|
||||
|
||||
Storage()->GetDefaultConfigurations(QB_.Offset, QB_.Limit, DefConfigs);
|
||||
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : DefConfigs) {
|
||||
Poco::JSON::Object Obj;
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
}
|
||||
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::CONFIGURATIONS, Objects);
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
} else
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.warning(
|
||||
Poco::format("%s: Failed with: %s", std::string(__func__), E.displayText()));
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(RESTAPI::Protocol::CONFIGURATIONS, Objects);
|
||||
ReturnObject(RetObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,17 +11,20 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_default_configurations : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_default_configurations(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_default_configurations(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal){};
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/default_configurations"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final {};
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
#endif //UCENTRAL_RESTAPI_DEFAULT_CONFIGURATIONS_H
|
||||
|
||||
@@ -6,26 +6,11 @@
|
||||
#include "Daemon.h"
|
||||
#include "Dashboard.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_deviceDashboardHandler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
DoGet(Request, Response);
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
}
|
||||
|
||||
void RESTAPI_deviceDashboardHandler::DoGet(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_deviceDashboardHandler::DoGet() {
|
||||
Daemon()->GetDashboard().Create();
|
||||
Poco::JSON::Object Answer;
|
||||
Daemon()->GetDashboard().Report().to_json(Answer);
|
||||
ReturnObject(Request, Answer, Response);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
}
|
||||
@@ -7,19 +7,19 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_deviceDashboardHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_deviceDashboardHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_deviceDashboardHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}, Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS}, Server, Internal) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/deviceDashboard"};}
|
||||
void DoGet(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void DoGet() final;
|
||||
void DoDelete() final {};
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,52 +10,62 @@
|
||||
#define UCENTRAL_RESTAPI_DEVICECOMMANDHANDLER_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
#include "RESTAPI_protocol.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_device_commandHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_device_commandHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_device_commandHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) override;
|
||||
|
||||
void GetCapabilities(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void DeleteCapabilities(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void GetLogs(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void DeleteLogs(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void GetStatistics(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void DeleteStatistics(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void GetStatus(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void ExecuteCommand(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void Configure(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void GetChecks(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void DeleteChecks(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void Upgrade(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void Reboot(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void Factory(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void LEDs(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void Trace(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void MakeRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void WifiScan(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void EventQueue(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void Rtty(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void GetCapabilities();
|
||||
void DeleteCapabilities();
|
||||
void GetLogs();
|
||||
void DeleteLogs();
|
||||
void GetStatistics();
|
||||
void DeleteStatistics();
|
||||
void GetStatus();
|
||||
void ExecuteCommand();
|
||||
void Configure();
|
||||
void GetChecks();
|
||||
void DeleteChecks();
|
||||
void Upgrade();
|
||||
void Reboot();
|
||||
void Factory();
|
||||
void LEDs();
|
||||
void Trace();
|
||||
void MakeRequest();
|
||||
void WifiScan();
|
||||
void EventQueue();
|
||||
void Rtty();
|
||||
void Telemetry();
|
||||
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/device/{serialNumber}/{command}"}; };
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final;
|
||||
void DoPut() final {};
|
||||
|
||||
inline bool ValidateParameters() {
|
||||
Command_ = GetBinding(RESTAPI::Protocol::COMMAND, "");
|
||||
if (Command_.empty()) {
|
||||
return false;
|
||||
}
|
||||
SerialNumber_ = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if (SerialNumber_.empty()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string SerialNumber_;
|
||||
std::string SerialNumber_, Command_;
|
||||
};
|
||||
}
|
||||
#endif //UCENTRAL_RESTAPI_DEVICECOMMANDHANDLER_H
|
||||
|
||||
@@ -11,94 +11,162 @@
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "StorageService.h"
|
||||
#include "Utils.h"
|
||||
#include "ConfigurationValidator.h"
|
||||
#include "ConfigurationCache.h"
|
||||
#include "CentralConfig.h"
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_device_handler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_device_handler::DoGet() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
if(SerialNumber.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
ParseParameters(Request);
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
std::string SerialNumber = GetBinding(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
GWObjects::Device Device;
|
||||
|
||||
if (Storage()->GetDevice(SerialNumber, Device)) {
|
||||
Poco::JSON::Object Obj;
|
||||
Device.to_json(Obj);
|
||||
ReturnObject(Request, Obj, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
ReturnObject(Obj);
|
||||
return;
|
||||
}
|
||||
NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_device_handler::DoDelete() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
return;
|
||||
}
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
|
||||
std::string SerialNumber = GetBinding(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if (Storage()->DeleteDevice(SerialNumber)) {
|
||||
OK(Request, Response);
|
||||
} else {
|
||||
NotFound(Request, Response);
|
||||
}
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
|
||||
std::string SerialNumber = GetBinding(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
Poco::JSON::Parser IncomingParser;
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
GWObjects::Device Device;
|
||||
if (!Device.from_json(Obj)) {
|
||||
BadRequest(Request, Response);
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure the username is filled for the notes.
|
||||
for(auto &i:Device.Notes)
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
|
||||
if (!uCentral::Utils::ValidSerialNumber(Device.SerialNumber)) {
|
||||
Logger_.warning(Poco::format("CREATE-DEVICE(%s): Illegal name.", Device.SerialNumber));
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
Device.Print();
|
||||
|
||||
Device.UUID = time(nullptr);
|
||||
if (Storage()->CreateDevice(Device)) {
|
||||
Poco::JSON::Object DevObj;
|
||||
Device.to_json(DevObj);
|
||||
ReturnObject(Request, DevObj, Response);
|
||||
} else {
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_PUT) {
|
||||
std::string SerialNumber = GetBinding(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
Poco::JSON::Parser IncomingParser;
|
||||
Poco::JSON::Object::Ptr Obj =
|
||||
IncomingParser.parse(Request.stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
GWObjects::Device Device;
|
||||
if (!Device.from_json(Obj)) {
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto &i:Device.Notes)
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
|
||||
if (Storage()->UpdateDevice(Device)) {
|
||||
Poco::JSON::Object DevObj;
|
||||
Device.to_json(DevObj);
|
||||
ReturnObject(Request, DevObj, Response);
|
||||
} else {
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
} else {
|
||||
BadRequest(Request, Response);
|
||||
NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
void RESTAPI_device_handler::DoPost() {
|
||||
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
if(SerialNumber.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string Arg;
|
||||
if(HasParameter("validateOnly",Arg) && Arg=="true") {
|
||||
auto Body = ParseStream();
|
||||
if(!Body->has("configuration")) {
|
||||
BadRequest("Must have 'configuration' element.");
|
||||
return;
|
||||
}
|
||||
auto Config=Body->get("configuration").toString();
|
||||
Poco::JSON::Object Answer;
|
||||
auto Res = ValidateUCentralConfiguration(Config);
|
||||
Answer.set("valid",Res);
|
||||
ReturnObject(Answer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Utils::ValidSerialNumber(SerialNumber)) {
|
||||
Logger_.warning(Poco::format("CREATE-DEVICE(%s): Illegal serial number.", SerialNumber));
|
||||
BadRequest( RESTAPI::Errors::InvalidSerialNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
GWObjects::Device Device;
|
||||
if (!Device.from_json(Obj)) {
|
||||
BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
return;
|
||||
}
|
||||
|
||||
if(SerialNumber!=Device.SerialNumber) {
|
||||
BadRequest(RESTAPI::Errors::SerialNumberMismatch);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Device.Configuration.empty() || (!Device.Configuration.empty() && !ValidateUCentralConfiguration(Device.Configuration))) {
|
||||
BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto &i:Device.Notes)
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
|
||||
Config::Config NewConfig(Device.Configuration);
|
||||
Device.UUID = std::time(nullptr);
|
||||
NewConfig.SetUUID(Device.UUID);
|
||||
Device.Configuration = NewConfig.get();
|
||||
|
||||
Poco::toLowerInPlace(Device.SerialNumber);
|
||||
|
||||
if (Storage()->CreateDevice(Device)) {
|
||||
SetCurrentConfigurationID(SerialNumber, Device.UUID);
|
||||
Poco::JSON::Object DevObj;
|
||||
Device.to_json(DevObj);
|
||||
ReturnObject(DevObj);
|
||||
return;
|
||||
}
|
||||
InternalError(RESTAPI::Errors::RecordNotCreated);
|
||||
}
|
||||
|
||||
void RESTAPI_device_handler::DoPut() {
|
||||
std::string SerialNumber = GetBinding(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
if(SerialNumber.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingSerialNumber);
|
||||
return;
|
||||
}
|
||||
|
||||
auto Obj = ParseStream();
|
||||
GWObjects::Device NewDevice;
|
||||
if (!NewDevice.from_json(Obj)) {
|
||||
BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
return;
|
||||
}
|
||||
|
||||
GWObjects::Device Existing;
|
||||
if(!Storage()->GetDevice(SerialNumber, Existing)) {
|
||||
NotFound();
|
||||
return;
|
||||
}
|
||||
|
||||
if(!NewDevice.Configuration.empty()) {
|
||||
if (!ValidateUCentralConfiguration(NewDevice.Configuration)) {
|
||||
BadRequest(RESTAPI::Errors::ConfigBlockInvalid);
|
||||
return;
|
||||
}
|
||||
Config::Config NewConfig(NewDevice.Configuration);
|
||||
uint64_t NewConfigUUID = std::time(nullptr);
|
||||
NewConfig.SetUUID(NewConfigUUID);
|
||||
Existing.Configuration = NewConfig.get();
|
||||
Existing.UUID = NewConfigUUID;
|
||||
}
|
||||
|
||||
AssignIfPresent(Obj, "venue", Existing.Venue);
|
||||
AssignIfPresent(Obj, "owner", Existing.Owner);
|
||||
AssignIfPresent(Obj, "location", Existing.Location);
|
||||
|
||||
for(auto &i:NewDevice.Notes) {
|
||||
i.createdBy = UserInfo_.userinfo.email;
|
||||
Existing.Notes.push_back(i);
|
||||
}
|
||||
|
||||
Existing.LastConfigurationChange = std::time(nullptr);
|
||||
if (Storage()->UpdateDevice(Existing)) {
|
||||
SetCurrentConfigurationID(SerialNumber, Existing.UUID);
|
||||
Poco::JSON::Object DevObj;
|
||||
NewDevice.to_json(DevObj);
|
||||
ReturnObject(DevObj);
|
||||
return;
|
||||
}
|
||||
InternalError(RESTAPI::Errors::RecordNotUpdated);
|
||||
}
|
||||
}
|
||||
@@ -10,23 +10,25 @@
|
||||
#define UCENTRAL_RESTAPI_DEVICEHANDLER_H
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
#include "Poco/Net/HTTPServerRequest.h"
|
||||
#include "Poco/Net/HTTPServerResponse.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_device_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_device_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_device_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_GET, Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT, Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/device/{serialNumber}"}; };
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final;
|
||||
void DoPut() final;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,93 +16,66 @@
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_devices_handler::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_devices_handler::DoGet() {
|
||||
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
try {
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
ParseParameters(Request);
|
||||
InitQueryBlock();
|
||||
auto serialOnly = GetBoolParameter(uCentral::RESTAPI::Protocol::SERIALONLY, false);
|
||||
auto countOnly = GetBoolParameter(uCentral::RESTAPI::Protocol::COUNTONLY, false);
|
||||
auto deviceWithStatus =
|
||||
GetBoolParameter(uCentral::RESTAPI::Protocol::DEVICEWITHSTATUS, false);
|
||||
|
||||
Logger_.debug(Poco::format("DEVICES: from %Lu, limit of %Lu, filter='%s'.",
|
||||
(uint64_t)QB_.Offset, (uint64_t)QB_.Limit, QB_.Filter));
|
||||
|
||||
RESTAPIHandler::PrintBindings();
|
||||
|
||||
Poco::JSON::Object RetObj;
|
||||
|
||||
if (!QB_.Select.empty()) {
|
||||
|
||||
Poco::JSON::Array Objects;
|
||||
std::vector<std::string> Numbers = uCentral::Utils::Split(QB_.Select);
|
||||
for (auto &i : Numbers) {
|
||||
GWObjects::Device D;
|
||||
if (Storage()->GetDevice(i, D)) {
|
||||
Poco::JSON::Object Obj;
|
||||
if (deviceWithStatus)
|
||||
D.to_json_with_status(Obj);
|
||||
else
|
||||
D.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
} else {
|
||||
Logger_.error(
|
||||
Poco::format("DEVICE(%s): device in select cannot be found.", i));
|
||||
}
|
||||
}
|
||||
auto serialOnly = GetBoolParameter(RESTAPI::Protocol::SERIALONLY, false);
|
||||
auto deviceWithStatus = GetBoolParameter(RESTAPI::Protocol::DEVICEWITHSTATUS, false);
|
||||
|
||||
Poco::JSON::Object RetObj;
|
||||
if (!QB_.Select.empty()) {
|
||||
Poco::JSON::Array Objects;
|
||||
std::vector<std::string> Numbers = Utils::Split(QB_.Select);
|
||||
for (auto &i : Numbers) {
|
||||
GWObjects::Device D;
|
||||
if (Storage()->GetDevice(i, D)) {
|
||||
Poco::JSON::Object Obj;
|
||||
if (deviceWithStatus)
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::DEVICESWITHSTATUS, Objects);
|
||||
D.to_json_with_status(Obj);
|
||||
else
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::DEVICES, Objects);
|
||||
|
||||
} else if (countOnly == true) {
|
||||
uint64_t Count = 0;
|
||||
if (Storage()->GetDeviceCount(Count)) {
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::COUNT, Count);
|
||||
}
|
||||
} else if (serialOnly) {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
Storage()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : SerialNumbers) {
|
||||
Objects.add(i);
|
||||
}
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::SERIALNUMBERS, Objects);
|
||||
D.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
} else {
|
||||
std::vector<GWObjects::Device> Devices;
|
||||
Storage()->GetDevices(QB_.Offset, QB_.Limit, Devices);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
if (deviceWithStatus)
|
||||
i.to_json_with_status(Obj);
|
||||
else
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
}
|
||||
if (deviceWithStatus)
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::DEVICESWITHSTATUS, Objects);
|
||||
else
|
||||
RetObj.set(uCentral::RESTAPI::Protocol::DEVICES, Objects);
|
||||
Logger_.error(
|
||||
Poco::format("DEVICE(%s): device in select cannot be found.", i));
|
||||
}
|
||||
ReturnObject(Request, RetObj, Response);
|
||||
}
|
||||
if (deviceWithStatus)
|
||||
RetObj.set(RESTAPI::Protocol::DEVICESWITHSTATUS, Objects);
|
||||
else
|
||||
RetObj.set(RESTAPI::Protocol::DEVICES, Objects);
|
||||
|
||||
} else if (QB_.CountOnly == true) {
|
||||
uint64_t Count = 0;
|
||||
if (Storage()->GetDeviceCount(Count)) {
|
||||
ReturnCountOnly(Count);
|
||||
return;
|
||||
}
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.warning(
|
||||
Poco::format("%s: Failed with: %s", std::string(__func__), E.displayText()));
|
||||
} else if (serialOnly) {
|
||||
std::vector<std::string> SerialNumbers;
|
||||
Storage()->GetDeviceSerialNumbers(QB_.Offset, QB_.Limit, SerialNumbers);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : SerialNumbers) {
|
||||
Objects.add(i);
|
||||
}
|
||||
RetObj.set(RESTAPI::Protocol::SERIALNUMBERS, Objects);
|
||||
} else {
|
||||
std::vector<GWObjects::Device> Devices;
|
||||
Storage()->GetDevices(QB_.Offset, QB_.Limit, Devices);
|
||||
Poco::JSON::Array Objects;
|
||||
for (const auto &i : Devices) {
|
||||
Poco::JSON::Object Obj;
|
||||
if (deviceWithStatus)
|
||||
i.to_json_with_status(Obj);
|
||||
else
|
||||
i.to_json(Obj);
|
||||
Objects.add(Obj);
|
||||
}
|
||||
if (deviceWithStatus)
|
||||
RetObj.set(RESTAPI::Protocol::DEVICESWITHSTATUS, Objects);
|
||||
else
|
||||
RetObj.set(RESTAPI::Protocol::DEVICES, Objects);
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
ReturnObject(RetObj);
|
||||
}
|
||||
}
|
||||
@@ -11,17 +11,20 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_devices_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_devices_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_devices_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal){};
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/devices"}; };
|
||||
void DoGet() final;
|
||||
void DoDelete() final {};
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
55
src/RESTAPI_errors.h
Normal file
55
src/RESTAPI_errors.h
Normal file
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-09-12.
|
||||
//
|
||||
|
||||
#ifndef OWPROV_RESTAPI_ERRORS_H
|
||||
#define OWPROV_RESTAPI_ERRORS_H
|
||||
|
||||
namespace OpenWifi::RESTAPI::Errors {
|
||||
static const std::string MissingUUID{"Missing UUID."};
|
||||
static const std::string MissingSerialNumber{"Missing Serial Number."};
|
||||
static const std::string InternalError{"Internal error. Please try later."};
|
||||
static const std::string InvalidJSONDocument{"Invalid JSON document."};
|
||||
static const std::string UnsupportedHTTPMethod{"Unsupported HTTP Method"};
|
||||
static const std::string StillInUse{"Element still in use."};
|
||||
static const std::string CouldNotBeDeleted{"Element could not be deleted."};
|
||||
static const std::string NameMustBeSet{"The name property must be set."};
|
||||
static const std::string ConfigBlockInvalid{"Configuration block type invalid."};
|
||||
static const std::string UnknownId{"Unknown management policy."};
|
||||
static const std::string InvalidDeviceTypes{"Unknown or invalid device type(s)."};
|
||||
static const std::string RecordNotCreated{"Record could not be created."};
|
||||
static const std::string RecordNotUpdated{"Record could not be updated."};
|
||||
static const std::string UnknownManagementPolicyUUID{"Unknown management policy UUID."};
|
||||
static const std::string CannotDeleteRoot{"Root Entity cannot be removed, only modified."};
|
||||
static const std::string MustCreateRootFirst{"Root entity must be created first."};
|
||||
static const std::string ParentUUIDMustExist{"Parent UUID must exist."};
|
||||
static const std::string ConfigurationMustExist{"Configuration must exist."};
|
||||
static const std::string MissingOrInvalidParameters{"Invalid or missing parameters."};
|
||||
static const std::string UnknownSerialNumber{"Unknown Serial Number."};
|
||||
static const std::string InvalidSerialNumber{"Invalid Serial Number."};
|
||||
static const std::string SerialNumberExists{"Serial Number already exists."};
|
||||
static const std::string ValidNonRootUUID{"Must be a non-root, and valid UUID."};
|
||||
static const std::string VenueMustExist{"Venue does not exist."};
|
||||
static const std::string NotBoth{"You cannot specify both Entity and Venue"};
|
||||
static const std::string EntityMustExist{"Entity must exist."};
|
||||
static const std::string ParentOrEntityMustBeSet{"Parent or Entity must be set."};
|
||||
static const std::string ContactMustExist{"Contact must exist."};
|
||||
static const std::string LocationMustExist{"Location must exist."};
|
||||
static const std::string OnlyWSSupported{"This endpoint only supports WebSocket."};
|
||||
static const std::string SerialNumberMismatch{"Serial Number mismatch."};
|
||||
static const std::string InvalidCommand{"Invalid command."};
|
||||
static const std::string NoRecordsDeleted{"No records deleted."};
|
||||
static const std::string DeviceNotConnected{"Device is not currently connected."};
|
||||
static const std::string CannotCreateWS{"Telemetry system could not create WS endpoint. Please try again."};
|
||||
static const std::string BothDeviceTypeRevision{"Both deviceType and revision must be set."};
|
||||
static const std::string IdOrSerialEmpty{"SerialNumber and Id must not be empty."};
|
||||
static const std::string MissingUserID{"Missing user ID."};
|
||||
static const std::string IdMustBe0{"To create a user, you must set the ID to 0"};
|
||||
static const std::string InvalidUserRole{"Invalid userRole."};
|
||||
static const std::string InvalidEmailAddress{"Invalid email address."};
|
||||
static const std::string InvalidPassword{"Invalid password."};
|
||||
static const std::string PasswordRejected{"Password was rejected. This maybe an old password."};
|
||||
static const std::string InvalidIPRanges{"Invalid IP range specifications."};
|
||||
}
|
||||
|
||||
#endif //OWPROV_RESTAPI_ERRORS_H
|
||||
@@ -14,53 +14,37 @@
|
||||
|
||||
#include <fstream>
|
||||
#include "RESTAPI_protocol.h"
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
namespace uCentral {
|
||||
void RESTAPI_file::handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (!ContinueProcessing(Request, Response))
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_file::DoGet() {
|
||||
auto UUID = GetBinding(RESTAPI::Protocol::FILEUUID, "");
|
||||
auto SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
// does the file exist
|
||||
Poco::File DownloadFile(FileUploader()->Path() + "/" + UUID);
|
||||
|
||||
std::string FileType;
|
||||
if (!Storage()->GetAttachedFile(UUID, SerialNumber, DownloadFile.path(), FileType)) {
|
||||
NotFound();
|
||||
return;
|
||||
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
|
||||
try {
|
||||
ParseParameters(Request);
|
||||
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||
auto UUID = GetBinding(uCentral::RESTAPI::Protocol::FILEUUID, "");
|
||||
auto SerialNumber = GetParameter(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
|
||||
// does the file exist
|
||||
Poco::File DownloadFile(FileUploader()->Path() + "/" + UUID);
|
||||
|
||||
std::string FileType;
|
||||
if (!Storage()->GetAttachedFile(UUID, SerialNumber, DownloadFile.path(),
|
||||
FileType)) {
|
||||
NotFound(Request, Response);
|
||||
return;
|
||||
}
|
||||
SendFile(DownloadFile, UUID, Request, Response);
|
||||
DownloadFile.remove();
|
||||
return;
|
||||
|
||||
} else if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {
|
||||
auto UUID = GetBinding(uCentral::RESTAPI::Protocol::FILEUUID, "");
|
||||
|
||||
if (UUID.empty()) {
|
||||
BadRequest(Request, Response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->RemoveAttachedFile(UUID))
|
||||
OK(Request, Response);
|
||||
else
|
||||
NotFound(Request, Response);
|
||||
}
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.error(Poco::format("%s: failed with %s", std::string(__func__), E.displayText()));
|
||||
}
|
||||
BadRequest(Request, Response);
|
||||
SendFile(DownloadFile, UUID);
|
||||
DownloadFile.remove();
|
||||
}
|
||||
|
||||
void RESTAPI_file::DoDelete() {
|
||||
auto UUID = GetBinding(RESTAPI::Protocol::FILEUUID, "");
|
||||
|
||||
if (UUID.empty()) {
|
||||
BadRequest(RESTAPI::Errors::MissingUUID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storage()->RemoveAttachedFile(UUID)) {
|
||||
OK();
|
||||
return;
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::CouldNotBeDeleted);
|
||||
}
|
||||
}
|
||||
@@ -11,18 +11,21 @@
|
||||
|
||||
#include "RESTAPI_handler.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_file : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_file(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, bool Internal)
|
||||
RESTAPI_file(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) override;
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/file/{uuid}"};}
|
||||
void DoGet() final;
|
||||
void DoDelete() final;
|
||||
void DoPost() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <future>
|
||||
@@ -16,6 +17,8 @@
|
||||
#include "Poco/URI.h"
|
||||
#include "Poco/Net/OAuth20Credentials.h"
|
||||
|
||||
#include "RESTAPI_errors.h"
|
||||
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
#include "AuthService.h"
|
||||
#else
|
||||
@@ -27,22 +30,53 @@
|
||||
#include "Utils.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPIHandler::handleRequest(Poco::Net::HTTPServerRequest &RequestIn,
|
||||
Poco::Net::HTTPServerResponse &ResponseIn) {
|
||||
try {
|
||||
Request = &RequestIn;
|
||||
Response = &ResponseIn;
|
||||
|
||||
if (!ContinueProcessing())
|
||||
return;
|
||||
|
||||
if (AlwaysAuthorize_ && !IsAuthorized())
|
||||
return;
|
||||
|
||||
ParseParameters();
|
||||
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
|
||||
DoGet();
|
||||
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
DoPost();
|
||||
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE)
|
||||
DoDelete();
|
||||
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_PUT)
|
||||
DoPut();
|
||||
else
|
||||
BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
|
||||
return;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
BadRequest(RESTAPI::Errors::InternalError);
|
||||
}
|
||||
}
|
||||
|
||||
const Poco::JSON::Object::Ptr &RESTAPIHandler::ParseStream() {
|
||||
return IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>();
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::ParseBindings(const std::string & Request, const std::list<const char *> & EndPoints, BindingMap &bindings) {
|
||||
std::string Param, Value;
|
||||
|
||||
bindings.clear();
|
||||
std::vector<std::string> PathItems = uCentral::Utils::Split(Request, '/');
|
||||
std::vector<std::string> PathItems = Utils::Split(Request, '/');
|
||||
|
||||
for(const auto &EndPoint:EndPoints) {
|
||||
std::vector<std::string> ParamItems = uCentral::Utils::Split(EndPoint, '/');
|
||||
std::vector<std::string> ParamItems = Utils::Split(EndPoint, '/');
|
||||
if (PathItems.size() != ParamItems.size())
|
||||
continue;
|
||||
|
||||
bool Matched = true;
|
||||
for (auto i = 0; i != PathItems.size() && Matched; i++) {
|
||||
// std::cout << "PATH:" << PathItems[i] << " ENDPOINT:" << ParamItems[i] << std::endl;
|
||||
if (PathItems[i] != ParamItems[i]) {
|
||||
if (ParamItems[i][0] == '{') {
|
||||
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
|
||||
@@ -59,14 +93,14 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
void RESTAPIHandler::PrintBindings() {
|
||||
for (auto &[key, value] : Bindings_)
|
||||
for (const auto &[key, value] : Bindings_)
|
||||
std::cout << "Key = " << key << " Value= " << value << std::endl;
|
||||
}
|
||||
|
||||
void RESTAPIHandler::ParseParameters(Poco::Net::HTTPServerRequest &request) {
|
||||
|
||||
Poco::URI uri(request.getURI());
|
||||
void RESTAPIHandler::ParseParameters() {
|
||||
Poco::URI uri(Request->getURI());
|
||||
Parameters_ = uri.getQueryParameters();
|
||||
InitQueryBlock();
|
||||
}
|
||||
|
||||
static bool is_number(const std::string &s) {
|
||||
@@ -80,35 +114,40 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
uint64_t RESTAPIHandler::GetParameter(const std::string &Name, const uint64_t Default) {
|
||||
|
||||
for (const auto &i : Parameters_) {
|
||||
if (i.first == Name) {
|
||||
if (!is_number(i.second))
|
||||
return Default;
|
||||
return std::stoi(i.second);
|
||||
}
|
||||
}
|
||||
return Default;
|
||||
auto Hint = std::find_if(Parameters_.begin(),Parameters_.end(),[Name](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);
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::GetBoolParameter(const std::string &Name, bool Default) {
|
||||
|
||||
for (const auto &i : Parameters_) {
|
||||
if (i.first == Name) {
|
||||
if (!is_bool(i.second))
|
||||
return Default;
|
||||
return i.second == "true";
|
||||
}
|
||||
}
|
||||
return Default;
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](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";
|
||||
}
|
||||
|
||||
std::string RESTAPIHandler::GetParameter(const std::string &Name, const std::string &Default) {
|
||||
for (const auto &i : Parameters_) {
|
||||
if (i.first == Name)
|
||||
return i.second;
|
||||
}
|
||||
return Default;
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==end(Parameters_))
|
||||
return Default;
|
||||
return Hint->second;
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::HasParameter(const std::string &Name, std::string &Value) {
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](const std::pair<std::string,std::string> &S){ return S.first==Name; });
|
||||
if(Hint==end(Parameters_))
|
||||
return false;
|
||||
Value = Hint->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::HasParameter(const std::string &Name, uint64_t & Value) {
|
||||
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[Name](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;
|
||||
}
|
||||
|
||||
const std::string &RESTAPIHandler::GetBinding(const std::string &Name, const std::string &Default) {
|
||||
@@ -130,202 +169,225 @@ namespace uCentral {
|
||||
return Return;
|
||||
}
|
||||
|
||||
void RESTAPIHandler::AddCORS(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
auto Origin = Request.find("Origin");
|
||||
if (Origin != Request.end()) {
|
||||
Response.set("Access-Control-Allow-Origin", Origin->second);
|
||||
Response.set("Vary", "Origin");
|
||||
} else {
|
||||
Response.set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
Response.set("Access-Control-Allow-Headers", "*");
|
||||
Response.set("Access-Control-Allow-Methods", MakeList(Methods_));
|
||||
Response.set("Access-Control-Max-Age", "86400");
|
||||
bool RESTAPIHandler::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;
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SetCommonHeaders(Poco::Net::HTTPServerResponse &Response, bool CloseConnection) {
|
||||
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("application/json");
|
||||
bool RESTAPIHandler::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;
|
||||
}
|
||||
|
||||
void RESTAPIHandler::AddCORS() {
|
||||
auto Origin = Request->find("Origin");
|
||||
if (Origin != Request->end()) {
|
||||
Response->set("Access-Control-Allow-Origin", Origin->second);
|
||||
Response->set("Vary", "Origin");
|
||||
} else {
|
||||
Response->set("Access-Control-Allow-Origin", "*");
|
||||
}
|
||||
Response->set("Access-Control-Allow-Headers", "*");
|
||||
Response->set("Access-Control-Allow-Methods", MakeList(Methods_));
|
||||
Response->set("Access-Control-Max-Age", "86400");
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SetCommonHeaders(bool CloseConnection) {
|
||||
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
|
||||
Response->setChunkedTransferEncoding(true);
|
||||
Response->setContentType("application/json");
|
||||
if(CloseConnection) {
|
||||
Response.set("Connection", "close");
|
||||
Response.setKeepAlive(false);
|
||||
Response->set("Connection", "close");
|
||||
Response->setKeepAlive(false);
|
||||
} else {
|
||||
Response.setKeepAlive(true);
|
||||
Response.set("Connection", "Keep-Alive");
|
||||
Response.set("Keep-Alive", "timeout=5, max=1000");
|
||||
Response->setKeepAlive(true);
|
||||
Response->set("Connection", "Keep-Alive");
|
||||
Response->set("Keep-Alive", "timeout=5, max=1000");
|
||||
}
|
||||
}
|
||||
|
||||
void RESTAPIHandler::ProcessOptions(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
AddCORS(Request, Response);
|
||||
SetCommonHeaders(Response);
|
||||
Response.setContentLength(0);
|
||||
Response.set("Access-Control-Allow-Credentials", "true");
|
||||
Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
|
||||
Response.set("Vary", "Origin, Access-Control-Request-Headers, Access-Control-Request-Method");
|
||||
/* std::cout << "RESPONSE:" << std::endl;
|
||||
for(const auto &[f,s]:Response)
|
||||
std::cout << "First: " << f << " second:" << s << std::endl;
|
||||
*/
|
||||
Response.send();
|
||||
void RESTAPIHandler::ProcessOptions() {
|
||||
AddCORS();
|
||||
SetCommonHeaders();
|
||||
Response->setContentLength(0);
|
||||
Response->set("Access-Control-Allow-Credentials", "true");
|
||||
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
|
||||
Response->set("Vary", "Origin, Access-Control-Request-Headers, Access-Control-Request-Method");
|
||||
Response->send();
|
||||
}
|
||||
|
||||
void RESTAPIHandler::PrepareResponse(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
Poco::Net::HTTPResponse::HTTPStatus Status,
|
||||
void RESTAPIHandler::PrepareResponse( Poco::Net::HTTPResponse::HTTPStatus Status,
|
||||
bool CloseConnection) {
|
||||
Response.setStatus(Status);
|
||||
AddCORS(Request, Response);
|
||||
SetCommonHeaders(Response, CloseConnection);
|
||||
Response->setStatus(Status);
|
||||
AddCORS();
|
||||
SetCommonHeaders(CloseConnection);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::BadRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
const std::string & Reason) {
|
||||
PrepareResponse(Request, Response, Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
void RESTAPIHandler::BadRequest(const std::string & Reason) {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",500);
|
||||
ErrorObject.set("ErrorDetails",Request.getMethod());
|
||||
ErrorObject.set("ErrorCode",400);
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
ErrorObject.set("ErrorDescription",Reason.empty() ? "Command is missing parameters or wrong values." : Reason) ;
|
||||
std::ostream &Answer = Response.send();
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::UnAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
const std::string & Reason) {
|
||||
PrepareResponse(Request, Response, Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
|
||||
void RESTAPIHandler::InternalError(const std::string & Reason) {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",500);
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
ErrorObject.set("ErrorDescription",Reason.empty() ? "Please try later or review the data submitted." : Reason) ;
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::UnAuthorized(const std::string & Reason) {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",403);
|
||||
ErrorObject.set("ErrorDetails",Request.getMethod());
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
ErrorObject.set("ErrorDescription",Reason.empty() ? "No access allowed." : Reason) ;
|
||||
std::ostream &Answer = Response.send();
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::NotFound(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
PrepareResponse(Request, Response, Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||
void RESTAPIHandler::NotFound() {
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||
Poco::JSON::Object ErrorObject;
|
||||
ErrorObject.set("ErrorCode",404);
|
||||
ErrorObject.set("ErrorDetails",Request.getMethod());
|
||||
ErrorObject.set("ErrorDetails",Request->getMethod());
|
||||
ErrorObject.set("ErrorDescription","This resource does not exist.");
|
||||
std::ostream &Answer = Response.send();
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
Logger_.debug(Poco::format("RES-NOTFOUND: User='%s' Method='%s' Path='%s",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
|
||||
void RESTAPIHandler::OK(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
PrepareResponse(Request, Response);
|
||||
if( Request.getMethod()==Poco::Net::HTTPRequest::HTTP_DELETE ||
|
||||
Request.getMethod()==Poco::Net::HTTPRequest::HTTP_OPTIONS) {
|
||||
Response.send();
|
||||
void RESTAPIHandler::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("Operation", Request->getMethod());
|
||||
ErrorObject.set("Details", "Command completed.");
|
||||
std::ostream &Answer = Response.send();
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
|
||||
}
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SendFile(Poco::File & File, const std::string & UUID, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
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", "private");
|
||||
Response.set("Pragma", "private");
|
||||
Response.set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response.set("Content-Length", std::to_string(File.getSize()));
|
||||
AddCORS(Request, Response);
|
||||
Response.sendFile(File.path(),"application/octet-stream");
|
||||
void RESTAPIHandler::SendFile(Poco::File & File, const std::string & UUID) {
|
||||
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", "private");
|
||||
Response->set("Pragma", "private");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->set("Content-Length", std::to_string(File.getSize()));
|
||||
AddCORS();
|
||||
Response->sendFile(File.path(),"application/octet-stream");
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SendFile(Poco::File & File, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
void RESTAPIHandler::SendFile(Poco::File & File) {
|
||||
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("Content-Transfer-Encoding","binary");
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
}
|
||||
Response.set("Cache-Control", "private");
|
||||
Response.set("Pragma", "private");
|
||||
Response.set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
AddCORS(Request, Response);
|
||||
Response.sendFile(File.path(),MT.ContentType);
|
||||
Response->set("Cache-Control", "private");
|
||||
Response->set("Pragma", "private");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
AddCORS();
|
||||
Response->sendFile(File.path(),MT.ContentType);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SendFile(Poco::TemporaryFile &TempAvatar, const std::string &Type, const std::string & Name, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response) {
|
||||
void RESTAPIHandler::SendFile(Poco::TemporaryFile &TempAvatar, const std::string &Type, const std::string & Name) {
|
||||
auto MT = Utils::FindMediaType(Name);
|
||||
if(MT.Encoding==Utils::BINARY) {
|
||||
Response.set("Content-Transfer-Encoding","binary");
|
||||
Response.set("Accept-Ranges", "bytes");
|
||||
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", "private");
|
||||
Response.set("Pragma", "private");
|
||||
Response.set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
AddCORS(Request, Response);
|
||||
Response.sendFile(TempAvatar.path(),MT.ContentType);
|
||||
Response->set("Content-Disposition", "attachment; filename=" + Name );
|
||||
Response->set("Accept-Ranges", "bytes");
|
||||
Response->set("Cache-Control", "private");
|
||||
Response->set("Pragma", "private");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
AddCORS();
|
||||
Response->sendFile(TempAvatar.path(),MT.ContentType);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::SendHTMLFileBack(Poco::File & File,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response ,
|
||||
const Types::StringPairVec & FormVars) {
|
||||
Response.set("Pragma", "private");
|
||||
Response.set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response.set("Content-Length", std::to_string(File.getSize()));
|
||||
AddCORS(Request, Response);
|
||||
Response->set("Pragma", "private");
|
||||
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
|
||||
Response->set("Content-Length", std::to_string(File.getSize()));
|
||||
AddCORS();
|
||||
auto FormContent = Utils::LoadFile(File.path());
|
||||
Utils::ReplaceVariables(FormContent, FormVars);
|
||||
Response.setChunkedTransferEncoding(true);
|
||||
Response.setContentType("text/html");
|
||||
std::ostream& ostr = Response.send();
|
||||
Response->setChunkedTransferEncoding(true);
|
||||
Response->setContentType("text/html");
|
||||
std::ostream& ostr = Response->send();
|
||||
ostr << FormContent;
|
||||
}
|
||||
|
||||
void RESTAPIHandler::ReturnStatus(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
Poco::Net::HTTPResponse::HTTPStatus Status,
|
||||
bool CloseConnection) {
|
||||
PrepareResponse(Request, Response, Status, CloseConnection);
|
||||
void RESTAPIHandler::ReturnStatus(Poco::Net::HTTPResponse::HTTPStatus Status, bool CloseConnection) {
|
||||
PrepareResponse(Status, CloseConnection);
|
||||
if(Status == Poco::Net::HTTPResponse::HTTP_NO_CONTENT) {
|
||||
Response.setContentLength(0);
|
||||
Response.erase("Content-Type");
|
||||
Response.setChunkedTransferEncoding(false);
|
||||
Response->setContentLength(0);
|
||||
Response->erase("Content-Type");
|
||||
Response->setChunkedTransferEncoding(false);
|
||||
}
|
||||
Response.send();
|
||||
Response->send();
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::ContinueProcessing(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
if (Request.getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
|
||||
ProcessOptions(Request, Response);
|
||||
bool RESTAPIHandler::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(Request, Response);
|
||||
} else if (std::find(Methods_.begin(), Methods_.end(), Request->getMethod()) == Methods_.end()) {
|
||||
BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
bool RESTAPIHandler::IsAuthorized() {
|
||||
if(Internal_) {
|
||||
return Daemon()->IsValidAPIKEY(Request);
|
||||
auto Allowed = Daemon()->IsValidAPIKEY(*Request);
|
||||
if(!Allowed) {
|
||||
if(Server_.LogBadTokens(false)) {
|
||||
Logger_.debug(Poco::format("I-REQ-DENIED(%s): Method='%s' Path='%s",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
Request->getMethod(), Request->getURI()));
|
||||
}
|
||||
} else {
|
||||
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(Poco::format("I-REQ-ALLOWED(%s): User='%s' Method='%s' Path='%s",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()), Id,
|
||||
Request->getMethod(), Request->getURI()));
|
||||
}
|
||||
}
|
||||
return Allowed;
|
||||
} else {
|
||||
if (SessionToken_.empty()) {
|
||||
try {
|
||||
Poco::Net::OAuth20Credentials Auth(Request);
|
||||
|
||||
Poco::Net::OAuth20Credentials Auth(*Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
SessionToken_ = Auth.getBearerToken();
|
||||
}
|
||||
@@ -334,48 +396,63 @@ namespace uCentral {
|
||||
}
|
||||
}
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
if (AuthService()->IsAuthorized(Request, SessionToken_, UserInfo_)) {
|
||||
if (AuthService()->IsAuthorized(*Request, SessionToken_, UserInfo_)) {
|
||||
#else
|
||||
if (AuthClient()->IsAuthorized(Request, SessionToken_, UserInfo_)) {
|
||||
if (AuthClient()->IsAuthorized(*Request, SessionToken_, UserInfo_)) {
|
||||
#endif
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
UserInfo_.userinfo.email,
|
||||
Request->clientAddress().toString(),
|
||||
Request->getMethod(),
|
||||
Request->getURI()));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
UnAuthorized(Request, Response);
|
||||
if(Server_.LogBadTokens(true)) {
|
||||
Logger_.debug(Poco::format("X-REQ-DENIED(%s): Method='%s' Path='%s",
|
||||
Utils::FormatIPv6(Request->clientAddress().toString()),
|
||||
Request->getMethod(), Request->getURI()));
|
||||
}
|
||||
UnAuthorized();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool RESTAPIHandler::ValidateAPIKey(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
auto Key = Request.get("X-API-KEY", "");
|
||||
|
||||
if (Key.empty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
void RESTAPIHandler::ReturnObject(Poco::Net::HTTPServerRequest &Request, Poco::JSON::Object &Object,
|
||||
Poco::Net::HTTPServerResponse &Response) {
|
||||
PrepareResponse(Request, Response);
|
||||
std::ostream &Answer = Response.send();
|
||||
void RESTAPIHandler::ReturnObject(Poco::JSON::Object &Object) {
|
||||
PrepareResponse();
|
||||
std::ostream &Answer = Response->send();
|
||||
Poco::JSON::Stringifier::stringify(Object, Answer);
|
||||
}
|
||||
|
||||
void RESTAPIHandler::InitQueryBlock() {
|
||||
QB_.SerialNumber = GetParameter(uCentral::RESTAPI::Protocol::SERIALNUMBER, "");
|
||||
QB_.StartDate = GetParameter(uCentral::RESTAPI::Protocol::STARTDATE, 0);
|
||||
QB_.EndDate = GetParameter(uCentral::RESTAPI::Protocol::ENDDATE, 0);
|
||||
QB_.Offset = GetParameter(uCentral::RESTAPI::Protocol::OFFSET, 0);
|
||||
QB_.Limit = GetParameter(uCentral::RESTAPI::Protocol::LIMIT, 100);
|
||||
QB_.Filter = GetParameter(uCentral::RESTAPI::Protocol::FILTER, "");
|
||||
QB_.Select = GetParameter(uCentral::RESTAPI::Protocol::SELECT, "");
|
||||
QB_.Lifetime = GetBoolParameter(uCentral::RESTAPI::Protocol::LIFETIME,false);
|
||||
QB_.LogType = GetParameter(uCentral::RESTAPI::Protocol::LOGTYPE,0);
|
||||
QB_.LastOnly = GetBoolParameter(uCentral::RESTAPI::Protocol::LASTONLY,false);
|
||||
QB_.Newest = GetBoolParameter(uCentral::RESTAPI::Protocol::NEWEST,false);
|
||||
void RESTAPIHandler::ReturnCountOnly(uint64_t Count) {
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set("count", Count);
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
bool RESTAPIHandler::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, 1);
|
||||
QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100);
|
||||
QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, "");
|
||||
QB_.Select = GetParameter(RESTAPI::Protocol::SELECT, "");
|
||||
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);
|
||||
|
||||
if(QB_.Offset<1)
|
||||
QB_.Offset=1;
|
||||
return true;
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t RESTAPIHandler::Get(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, uint64_t Default){
|
||||
@@ -397,8 +474,6 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
[[nodiscard]] uint64_t RESTAPIHandler::GetWhen(const Poco::JSON::Object::Ptr &Obj) {
|
||||
return RESTAPIHandler::Get(uCentral::RESTAPI::Protocol::WHEN, Obj);
|
||||
return RESTAPIHandler::Get(RESTAPI::Protocol::WHEN, Obj);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -25,8 +25,10 @@
|
||||
#include "Poco/NullStream.h"
|
||||
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
#include "RESTAPI_utils.h"
|
||||
#include "RESTAPI_GenericServer.h"
|
||||
|
||||
namespace uCentral {
|
||||
namespace OpenWifi {
|
||||
|
||||
class RESTAPI_PartHandler: public Poco::Net::PartHandler
|
||||
{
|
||||
@@ -86,66 +88,78 @@ namespace uCentral {
|
||||
struct QueryBlock {
|
||||
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
|
||||
std::string SerialNumber, Filter, Select;
|
||||
bool Lifetime=false, LastOnly=false, Newest=false;
|
||||
bool Lifetime=false, LastOnly=false, Newest=false, CountOnly=false;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, std::string> BindingMap;
|
||||
|
||||
RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector<std::string> Methods, bool Internal=false)
|
||||
: Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), Internal_(Internal) {}
|
||||
RESTAPIHandler(BindingMap map, Poco::Logger &l, std::vector<std::string> Methods, RESTAPI_GenericServer & Server, bool Internal=false, bool AlwaysAuthorize=true)
|
||||
: Bindings_(std::move(map)), Logger_(l), Methods_(std::move(Methods)), Server_(Server), Internal_(Internal), AlwaysAuthorize_(AlwaysAuthorize) {}
|
||||
|
||||
static bool ParseBindings(const std::string & Request, const std::list<const char *> & EndPoints, BindingMap &Keys);
|
||||
void PrintBindings();
|
||||
void ParseParameters(Poco::Net::HTTPServerRequest &request);
|
||||
void ParseParameters();
|
||||
|
||||
void AddCORS(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &response);
|
||||
void SetCommonHeaders(Poco::Net::HTTPServerResponse &response, bool CloseConnection=false);
|
||||
void ProcessOptions(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &response);
|
||||
void AddCORS();
|
||||
void SetCommonHeaders(bool CloseConnection=false);
|
||||
void ProcessOptions();
|
||||
void
|
||||
PrepareResponse(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &response,
|
||||
Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK,
|
||||
PrepareResponse(Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK,
|
||||
bool CloseConnection = false);
|
||||
bool ContinueProcessing(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
|
||||
bool IsAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
/* bool ValidateAPIKey(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response); */
|
||||
bool ContinueProcessing();
|
||||
bool IsAuthorized();
|
||||
|
||||
uint64_t GetParameter(const std::string &Name, uint64_t Default);
|
||||
std::string GetParameter(const std::string &Name, const std::string &Default);
|
||||
bool GetBoolParameter(const std::string &Name, bool Default);
|
||||
|
||||
void BadRequest(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response, const std::string &Reason = "");
|
||||
void UnAuthorized(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response, const std::string &Reason = "");
|
||||
void ReturnObject(Poco::Net::HTTPServerRequest &Request, Poco::JSON::Object &Object,
|
||||
Poco::Net::HTTPServerResponse &Response);
|
||||
void NotFound(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void OK(Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void ReturnStatus(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response,
|
||||
Poco::Net::HTTPResponse::HTTPStatus Status,
|
||||
void BadRequest(const std::string &Reason );
|
||||
void InternalError(const std::string &Reason = "");
|
||||
void UnAuthorized(const std::string &Reason = "");
|
||||
void ReturnObject(Poco::JSON::Object &Object);
|
||||
void NotFound();
|
||||
void OK();
|
||||
void ReturnStatus(Poco::Net::HTTPResponse::HTTPStatus Status,
|
||||
bool CloseConnection=false);
|
||||
void SendFile(Poco::File & File, const std::string & UUID,
|
||||
Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void SendFile(Poco::File & File, const std::string & UUID);
|
||||
void SendHTMLFileBack(Poco::File & File,
|
||||
Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response ,
|
||||
const Types::StringPairVec & FormVars);
|
||||
void SendFile(Poco::TemporaryFile &TempAvatar, const std::string &Type, const std::string & Name, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void SendFile(Poco::TemporaryFile &TempAvatar, const std::string &Type, const std::string & Name);
|
||||
|
||||
void SendFile(Poco::File & File, Poco::Net::HTTPServerRequest &Request, Poco::Net::HTTPServerResponse &Response);
|
||||
void SendFile(Poco::File & File);
|
||||
|
||||
const std::string &GetBinding(const std::string &Name, const std::string &Default);
|
||||
void InitQueryBlock();
|
||||
bool InitQueryBlock();
|
||||
|
||||
void ReturnCountOnly(uint64_t Count);
|
||||
|
||||
[[nodiscard]] static uint64_t Get(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, uint64_t Default=0);
|
||||
[[nodiscard]] static std::string GetS(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, const std::string & Default="");
|
||||
[[nodiscard]] static bool GetB(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, bool Default=false);
|
||||
[[nodiscard]] static uint64_t GetWhen(const Poco::JSON::Object::Ptr &Obj);
|
||||
bool HasParameter(const std::string &QueryParameter, std::string &Value);
|
||||
bool HasParameter(const std::string &QueryParameter, uint64_t & Value);
|
||||
|
||||
static bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, std::string &Value);
|
||||
static bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, uint64_t &Value);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Poco::Logger & Logger() { return Logger_; }
|
||||
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &request,
|
||||
Poco::Net::HTTPServerResponse &response) final;
|
||||
|
||||
virtual void DoGet() = 0 ;
|
||||
virtual void DoDelete() = 0 ;
|
||||
virtual void DoPost() = 0 ;
|
||||
virtual void DoPut() = 0 ;
|
||||
|
||||
const Poco::JSON::Object::Ptr & ParseStream();
|
||||
|
||||
protected:
|
||||
BindingMap Bindings_;
|
||||
@@ -156,19 +170,23 @@ namespace uCentral {
|
||||
std::vector<std::string> Methods_;
|
||||
QueryBlock QB_;
|
||||
bool Internal_=false;
|
||||
bool QueryBlockInitialized_=false;
|
||||
Poco::Net::HTTPServerRequest *Request= nullptr;
|
||||
Poco::Net::HTTPServerResponse *Response= nullptr;
|
||||
bool AlwaysAuthorize_=true;
|
||||
Poco::JSON::Parser IncomingParser_;
|
||||
RESTAPI_GenericServer & Server_;
|
||||
};
|
||||
|
||||
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L)
|
||||
: RESTAPIHandler(bindings, L, std::vector<std::string>{}) {}
|
||||
void handleRequest(Poco::Net::HTTPServerRequest &Request,
|
||||
Poco::Net::HTTPServerResponse &Response) override {
|
||||
if (!IsAuthorized(Request, Response))
|
||||
return;
|
||||
BadRequest(Request, Response);
|
||||
}
|
||||
};
|
||||
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server)
|
||||
: RESTAPIHandler(bindings, L, std::vector<std::string>{}, Server) {}
|
||||
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*)
|
||||
@@ -182,30 +200,30 @@ namespace uCentral {
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger ) {
|
||||
RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger, RESTAPI_GenericServer & Server) {
|
||||
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, false);
|
||||
return new T(Bindings, Logger, Server, false);
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
return new RESTAPI_UnknownRequestHandler(Bindings,Logger);
|
||||
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server);
|
||||
} else {
|
||||
return RESTAPI_Router<Args...>(RequestedPath, Bindings, Logger);
|
||||
return RESTAPI_Router<Args...>(RequestedPath, Bindings, Logger, Server);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger) {
|
||||
RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings, Poco::Logger & Logger, RESTAPI_GenericServer & Server) {
|
||||
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, true);
|
||||
return new T(Bindings, Logger, Server, true);
|
||||
}
|
||||
|
||||
if constexpr (sizeof...(Args) == 0) {
|
||||
return new RESTAPI_UnknownRequestHandler(Bindings,Logger);
|
||||
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server);
|
||||
} else {
|
||||
return RESTAPI_Router_I<Args...>(RequestedPath, Bindings, Logger);
|
||||
return RESTAPI_Router_I<Args...>(RequestedPath, Bindings, Logger, Server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user