Compare commits

..

178 Commits

Author SHA1 Message Date
TIP Automation User
b14cc814e4 Chg: update image tag in helm values to v2.8.0-RC2 2022-12-16 14:52:07 +00:00
Stephane Bourque
cdf71c2c99 Merge pull request #49 from Telecominfraproject/main
https://telecominfraproject.atlassian.net/browse/WIFI-11974
2022-12-14 20:56:10 -08:00
Stephane Bourque
56592fc350 Merge pull request #48 from Telecominfraproject/WIFI-11974
https://telecominfraproject.atlassian.net/browse/WIFI-11974
2022-12-14 11:47:58 -08:00
stephb9959
ee0123fae5 https://telecominfraproject.atlassian.net/browse/WIFI-11974
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-14 11:47:13 -08:00
TIP Automation User
28ccd71880 Chg: update image tag in helm values to v2.8.0-RC1 2022-12-13 23:08:55 +00:00
stephb9959
bbc83cd0a1 Merge remote-tracking branch 'origin/main' 2022-12-12 14:36:05 -08:00
stephb9959
d040bb672d https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-12-12 14:35:57 -08:00
Dmitry Dunaev
96d133c511 [WIFI-11729] Fix: doc generation error
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-12-01 13:22:04 +03:00
stephb9959
af3a655ece Merge remote-tracking branch 'origin/main' 2022-11-30 22:18:52 -08:00
stephb9959
a80ddb727a https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-30 22:18:31 -08:00
Dmitry Dunaev
c3cd76333a Merge pull request #47 from Telecominfraproject/feature/wifi-11729--pages-docs
[WIFI-11729] Add: README info
2022-11-29 15:05:52 +03:00
Dmitry Dunaev
3f1887eeb3 [WIFI-11729] Add: README info
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-29 15:05:35 +03:00
Dmitry Dunaev
c57419b4e1 Merge pull request #46 from Telecominfraproject/feature/wifi-11729--pages-docs
[WIFI-11729] Add: workflow to generate docs to GitHub pages
2022-11-29 14:52:56 +03:00
Dmitry Dunaev
e94d6e26b9 [WIFI-11729] Add: workflow to generate docs to GitHub pages
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-29 14:52:40 +03:00
stephb9959
1348be3011 https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-27 21:29:43 -08:00
stephb9959
24da84e6ea Merge remote-tracking branch 'origin/main' 2022-11-27 14:32:34 -08:00
stephb9959
2a17655116 https://telecominfraproject.atlassian.net/browse/WIFI-11755
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-27 14:32:23 -08:00
Johann Hoffmann
53e7288c07 Merge pull request #45 from Telecominfraproject/WIFI-11419-patch-workflows
[WIFI-11419] Patch workflows with regard to deprecated Github actions commands
2022-11-25 15:34:23 +01:00
stephb9959
d9677884a2 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-23 22:04:05 -08:00
stephb9959
b0faa44582 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-23 22:02:58 -08:00
stephb9959
04841cf0d4 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-23 21:55:52 -08:00
Johann Hoffmann
f8f3390342 Update checkout action version and replace set-output commands
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-11-21 18:21:33 +01:00
stephb9959
25df7e5f5c https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-21 09:15:03 -08:00
stephb9959
d8d6168f49 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-21 07:40:05 -08:00
stephb9959
5d5f66f4c5 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-18 19:55:32 -08:00
stephb9959
ce99365f0c https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-17 21:29:52 -08:00
stephb9959
2f2a94ed5c https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 23:06:23 -08:00
stephb9959
2bd5f9139b https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 12:31:14 -08:00
stephb9959
6254936142 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 10:33:42 -08:00
stephb9959
f52aef80cb https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-16 10:27:28 -08:00
stephb9959
12f003bb09 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-14 10:09:59 -08:00
stephb9959
a1f0fafed1 Merge remote-tracking branch 'origin/main' 2022-11-08 23:12:13 -08:00
stephb9959
ff084ec00c https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-08 23:12:05 -08:00
Dmitry Dunaev
6af116d518 Merge pull request #44 from Telecominfraproject/fix/wifi-11490--git-hash
[WIFI-11490] Fix: Get Git hash command in CMakeLists
2022-11-08 14:06:26 +03:00
Dmitry Dunaev
6918f97f93 [WIFI-11490] Fix: Get Git hash command in CMakeLists
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-11-08 13:50:06 +03:00
stephb9959
3cfac6cf16 https://telecominfraproject.atlassian.net/browse/WIFI-10918
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-07 15:32:20 -08:00
stephb9959
c6def7e0e1 Merge remote-tracking branch 'origin/main' 2022-11-07 15:01:32 -08:00
stephb9959
55bea4e8ad https://telecominfraproject.atlassian.net/browse/WIFI-10918
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-07 15:01:23 -08:00
Stephane Bourque
0314746764 Merge pull request #40 from Telecominfraproject/WIFI-10959-switch-fmtlib-and-awssdk
[WIFI-10959] Switch fmtlib and aws to prebuilt packages in Dockerfiles
2022-11-03 23:28:04 -07:00
Stephane Bourque
4d5bab043d Merge branch 'main' into WIFI-10959-switch-fmtlib-and-awssdk 2022-11-03 23:27:58 -07:00
stephb9959
90d10c06e2 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 23:14:36 -07:00
stephb9959
5780e2585f https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 10:29:02 -07:00
stephb9959
fa85884d97 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-03 09:33:53 -07:00
stephb9959
3cf7d2f8d6 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-11-02 22:57:17 -07:00
stephb9959
110c88b760 Merge remote-tracking branch 'origin/main' 2022-10-31 11:20:01 -07:00
stephb9959
427b4be808 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-31 11:19:53 -07:00
Dmitry Dunaev
1041595911 Merge pull request #43 from Telecominfraproject/feature/wifi-9942--sqlite
[WIFI-9942] Add: sqlite package
2022-10-31 12:07:24 +03:00
Dmitry Dunaev
1712b2834f [WIFI-9942] Add: sqlite package
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-31 12:06:57 +03:00
stephb9959
2786a3177c https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-30 10:20:30 -07:00
stephb9959
776745f597 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-29 21:52:26 -07:00
stephb9959
bb0310d34f https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-27 23:29:19 -07:00
stephb9959
6f465479f3 Merge remote-tracking branch 'origin/main' 2022-10-27 09:50:40 -07:00
stephb9959
6990860e61 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-27 09:50:32 -07:00
stephb9959
4e6b92cadf https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-27 09:33:15 -07:00
stephb9959
d99ee187f7 https://telecominfraproject.atlassian.net/browse/WIFI-11303
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-26 23:44:04 -07:00
Dmitry Dunaev
40c6d757a7 Merge pull request #42 from Telecominfraproject/security/wifi-11170--docker-image-version
[WIFI-11170] Chg: upgrade base Debian image
2022-10-11 15:03:00 +03:00
Dmitry Dunaev
59b00f3429 [WIFI-11170] Chg: upgrade base Debian image
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-11 15:02:46 +03:00
stephb9959
c7c91360a2 Merge remote-tracking branch 'origin/main' 2022-10-04 08:08:22 -07:00
stephb9959
8e148a6d33 https://telecominfraproject.atlassian.net/browse/WIFI-10942
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-10-04 08:08:07 -07:00
Johann Hoffmann
4d44884686 Add libfmt lib to runtime container
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-04 14:57:24 +02:00
Johann Hoffmann
e3467ef3ad Switch to libfmt-dev in Dockerfile
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-10-04 13:58:15 +02:00
Dmitry Dunaev
b9128f1b50 [WIFI-10581] Fix: securityContext fsGroup in helm
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-03 15:49:05 +03:00
Dmitry Dunaev
da80ab49cd [WIFI-10581] Fix: Helm image to main
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-03 12:07:01 +03:00
Dmitry Dunaev
bf0fd21eae Merge pull request #38 from Telecominfraproject/fix/wifi-10581--postgres-client
[WIFI-10581] Add: postgresql-client in Dockerfile
2022-10-03 11:25:20 +03:00
Dmitry Dunaev
829efdfec8 [WIFI-10581] Add: postgresql-client in Dockerfile
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-10-03 11:25:07 +03:00
Stephane Bourque
d258bbb414 Merge branch 'release/v2.7.0' into main 2022-10-02 11:40:07 -07:00
Stephane Bourque
972bbbafdc Merge pull request #36 from Telecominfraproject/WIFI-10942
https://telecominfraproject.atlassian.net/browse/WIFI-10942
2022-10-02 11:38:54 -07:00
Stephane Bourque
f0442d4c8e Merge branch 'main' into WIFI-10942 2022-10-02 11:38:48 -07:00
Stephane Bourque
f3713df910 https://telecominfraproject.atlassian.net/browse/WIFI-10942 2022-10-02 11:37:37 -07:00
Stephane Bourque
085fbfcdf3 Merge pull request #23 from Telecominfraproject/WIFI-10581-switch-images-to-debian-slim
[WIFI-10581] Switch microservice Docker images from Alpine to Debian-slim
2022-10-02 11:33:57 -07:00
TIP Automation User
e7997f28f4 Chg: update image tag in helm values to v2.7.0-RC4 2022-09-30 19:49:02 +00:00
Stephane Bourque
ef7deb3515 Merge pull request #35 from Telecominfraproject/WIFI-10942
https://telecominfraproject.atlassian.net/browse/WIFI-10942
2022-09-30 11:17:36 -07:00
stephb9959
70444bb7ab https://telecominfraproject.atlassian.net/browse/WIFI-10942
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-30 11:16:28 -07:00
Stephane Bourque
105bf2912b Merge pull request #34 from Telecominfraproject/WIFI-10942
https://telecominfraproject.atlassian.net/browse/WIFI-10942
2022-09-30 11:12:22 -07:00
Stephane Bourque
87dfb313d5 Merge branch 'release/v2.7.0' into WIFI-10942 2022-09-30 11:12:15 -07:00
stephb9959
5658db43eb https://telecominfraproject.atlassian.net/browse/WIFI-10942
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-30 11:09:43 -07:00
stephb9959
bff4db6a3a https://telecominfraproject.atlassian.net/browse/WIFI-10942
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-30 11:08:20 -07:00
TIP Automation User
8ecc461749 Chg: update image tag in helm values to v2.7.0-RC3 2022-09-30 16:31:39 +00:00
Stephane Bourque
97377fef7b Merge pull request #33 from Telecominfraproject/WIFI-10942
https://telecominfraproject.atlassian.net/browse/WIFI-10942
2022-09-30 09:04:29 -07:00
stephb9959
877f7985cd https://telecominfraproject.atlassian.net/browse/WIFI-10942
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-30 09:03:57 -07:00
TIP Automation User
9b916621a2 Chg: update image tag in helm values to v2.7.0-RC2 2022-09-29 23:27:47 +00:00
jaspreetsachdev
5e57c9a7c5 Merge pull request #32 from Telecominfraproject/main
Fixes for WIFI-10839 and others
2022-09-29 19:19:34 -04:00
Dmitry Dunaev
e9bb037ef2 Merge pull request #31 from Telecominfraproject/feature/wifi-10932--docker-support-http
[WIFI-10932] Add: restapi disable property in docker entrypoing
2022-09-28 17:26:55 +03:00
Dmitry Dunaev
054c40c7ed [WIFI-10932] Add: restapi disable property in docker entrypoing
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-09-28 17:26:01 +03:00
Dmitry Dunaev
99c59313ea Merge pull request #30 from Telecominfraproject/feature/wifi-10582--helm-global-cert-secret
[WIFI-10582] Add: functionality to use external existing certificates secret
2022-09-28 17:06:25 +03:00
Dmitry Dunaev
ff843f093c [WIFI-10582] Add: functionality to use external existing certificates secret
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-09-28 13:26:51 +03:00
Stephane Bourque
eec96dff52 Merge pull request #29 from Telecominfraproject/WIFI-10839
https://telecominfraproject.atlassian.net/browse/WIFI-10839
2022-09-22 21:47:34 -07:00
stephb9959
9c9f2cbf4f https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-22 21:47:11 -07:00
Stephane Bourque
98342bb626 Merge pull request #28 from Telecominfraproject/WIFI-10839
https://telecominfraproject.atlassian.net/browse/WIFI-10839
2022-09-22 20:39:23 -07:00
stephb9959
93890a1e99 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-22 20:39:01 -07:00
Stephane Bourque
f9111bab7b Merge pull request #27 from Telecominfraproject/WIFI-10839
https://telecominfraproject.atlassian.net/browse/WIFI-10839
2022-09-21 19:50:38 -07:00
stephb9959
8f9e954f20 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-21 19:49:34 -07:00
TIP Automation User
a568fce901 Chg: update image tag in helm values to v2.7.0-RC1 2022-09-16 19:55:07 +00:00
Stephane Bourque
6e2a21c831 Merge pull request #26 from Telecominfraproject/WIFI-10839
https://telecominfraproject.atlassian.net/browse/WIFI-10839
2022-09-14 12:28:05 -07:00
stephb9959
da8a9e14cf https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 12:27:02 -07:00
stephb9959
075b83a7d5 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 12:17:36 -07:00
stephb9959
3c35ec1523 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 12:13:48 -07:00
stephb9959
b65f33c975 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 11:55:34 -07:00
stephb9959
cbd5b09cdf https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 11:51:48 -07:00
stephb9959
0a145c8501 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 11:38:55 -07:00
stephb9959
2ed88569d0 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 11:27:14 -07:00
stephb9959
58c2269893 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 09:43:04 -07:00
stephb9959
a708cc2be0 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 09:34:55 -07:00
Stephane Bourque
9c8f7ed6f9 Merge pull request #25 from Telecominfraproject/WIFI-10839
https://telecominfraproject.atlassian.net/browse/WIFI-10839
2022-09-14 08:59:24 -07:00
stephb9959
b79a3b6c12 https://telecominfraproject.atlassian.net/browse/WIFI-10839
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-09-14 08:58:32 -07:00
Dmitry Dunaev
2c3b7711b3 Merge pull request #24 from Telecominfraproject/feature/wifi-10069--add-wait-postgres-initcontainer
[WIFI-10069] Add: helm - wait-postgres init container
2022-09-02 14:33:07 +03:00
Dmitry Dunaev
831e144869 [WIFI-10069] Add: helm - wait-postgres init container
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-09-02 14:32:42 +03:00
stephb9959
67910c982a https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 23:22:00 -07:00
stephb9959
9be196ce40 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 23:19:28 -07:00
stephb9959
222afe2858 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 23:19:10 -07:00
stephb9959
40a02c4752 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 23:11:56 -07:00
stephb9959
7f1577503f https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 23:08:32 -07:00
stephb9959
7ab2e6c96e https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:26:45 -07:00
stephb9959
639db8631e https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:24:40 -07:00
stephb9959
9fe9b74dea https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:22:08 -07:00
stephb9959
20c025f994 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:18:38 -07:00
stephb9959
ee78155b68 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:13:58 -07:00
stephb9959
9f9a866ad3 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:09:13 -07:00
stephb9959
adbd852ccd https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 14:07:43 -07:00
stephb9959
4bb5ee0b86 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 13:42:34 -07:00
stephb9959
06bb8cebbe https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 13:39:18 -07:00
stephb9959
dde46ce6b2 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 13:34:13 -07:00
stephb9959
515f8a4fea https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 11:13:49 -07:00
stephb9959
8dcfe04310 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 10:38:39 -07:00
stephb9959
5db6fc3027 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-29 10:26:11 -07:00
Johann Hoffmann
25397c80c9 Fix self-signed cert file extension for Debian
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-08-19 17:18:59 +02:00
Johann Hoffmann
2e046340e3 Create necessary library links in Docker image
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-08-19 16:06:39 +02:00
Johann Hoffmann
61dff87583 Fix curl-dev package name
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-08-18 16:35:05 +02:00
Johann Hoffmann
c73fd21b94 Switch to Debian-slim base images
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-08-18 14:15:38 +02:00
Dmitry Dunaev
8049291138 Merge pull request #22 from Telecominfraproject/fix/wifi-10413--cve-fix
[WIFI-10413] Fix: vulnerable base Docker image version
2022-08-15 13:31:08 +03:00
Dmitry Dunaev
613fa2e2bb [WIFI-10413] Fix: vulnerable base Docker image version
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-08-15 11:20:31 +03:00
Stephane Bourque
eb9a748836 Merge pull request #21 from Telecominfraproject/WIFI-10547
https://telecominfraproject.atlassian.net/browse/WIFI-10547Wifi 10547
2022-08-11 21:37:29 -07:00
stephb9959
6ee3cae1db https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-11 21:36:17 -07:00
stephb9959
33e4f8abd8 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-10 23:16:56 -07:00
stephb9959
d5b4d15307 https://telecominfraproject.atlassian.net/browse/WIFI-10547
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-10 23:07:05 -07:00
Stephane Bourque
e01f985974 Merge pull request #20 from Telecominfraproject/WIFI-10245
https://telecominfraproject.atlassian.net/browse/WIFI-10245
2022-08-10 16:40:52 -07:00
stephb9959
8dc3e53fc0 https://telecominfraproject.atlassian.net/browse/WIFI-10245
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-10 16:40:28 -07:00
Stephane Bourque
52e1bf8817 Merge pull request #19 from Telecominfraproject/feature/wifi-10388--versioning
[WIFI-10388] Chg: use Docker build arg to define dependency version
2022-08-08 12:12:01 -07:00
Dmitry Dunaev
a8b0028af6 [WIFI-10388] Chg: use Docker build arg to define dependency version
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-08-08 17:46:38 +03:00
Stephane Bourque
7976602d17 Merge pull request #18 from Telecominfraproject/WIFI-10388
https://telecominfraproject.atlassian.net/browse/WIFI-10388
2022-08-07 22:30:59 -07:00
stephb9959
55b0075c0c https://telecominfraproject.atlassian.net/browse/WIFI-10388
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-07 22:30:28 -07:00
Stephane Bourque
1da468e52c Merge pull request #17 from Telecominfraproject/WIFI-10388
https://telecominfraproject.atlassian.net/browse/WIFI-10388
2022-08-04 06:59:03 -07:00
stephb9959
fa434f79c3 https://telecominfraproject.atlassian.net/browse/WIFI-10388
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-04 06:58:29 -07:00
Stephane Bourque
d396a104ff Merge pull request #16 from Telecominfraproject/WIFI-10388
https://telecominfraproject.atlassian.net/browse/WIFI-10388
2022-08-03 08:02:06 -07:00
stephb9959
61837a8975 https://telecominfraproject.atlassian.net/browse/WIFI-10388
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-03 08:01:23 -07:00
Stephane Bourque
c1f06ec784 Merge pull request #15 from Telecominfraproject/WIFI-10388
https://telecominfraproject.atlassian.net/browse/WIFI-10388
2022-08-01 09:37:46 -07:00
stephb9959
10ffba95b5 https://telecominfraproject.atlassian.net/browse/WIFI-10388
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-08-01 09:11:51 -07:00
stephb9959
fd3a6be11a https://telecominfraproject.atlassian.net/browse/WIFI-10345
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-07-26 14:52:31 -07:00
stephb9959
ec2874748f https://telecominfraproject.atlassian.net/browse/WIFI-10345
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-07-24 18:18:07 -07:00
Dmitry Dunaev
432d0ed52b Merge pull request #14 from Telecominfraproject/feature/wifi-9772--test-systeminfo
[WIFI-9772] Chg: fix test scripts to make requests to owanalytics instead of owprov
2022-07-21 15:43:52 +03:00
Dmitry Dunaev
fe247c6093 [WIFI-9772] Chg: fix test scripts to make requests to owanalytics instead of owprov
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-07-21 15:43:13 +03:00
Stephane Bourque
4c1daf84cf Merge pull request #13 from Telecominfraproject/WIFI-10040
Fix: https://telecominfraproject.atlassian.net/browse/WIFI-10040
2022-07-04 14:19:21 -07:00
stephb9959
1d4aa80205 Fix: https://telecominfraproject.atlassian.net/browse/WIFI-10040
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-07-04 14:01:19 -07:00
Stephane Bourque
d0c4030289 Merge pull request #11 from Telecominfraproject/WIFI-10040
Fix: https://telecominfraproject.atlassian.net/browse/WIFI-10040
2022-07-01 09:58:01 -07:00
stephb9959
34100b5fb0 Fix: https://telecominfraproject.atlassian.net/browse/WIFI-10040
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-07-01 09:31:54 -07:00
Johann Hoffmann
0856e256e9 Merge pull request #9 from Telecominfraproject/WIFI-9920-rttys-not-working-after-upgrade
[WIFI-9920] Always re-generate config file if TEMPLATE_CONFIG is set to true
2022-06-24 18:22:20 +02:00
Johann Hoffmann
228b2162bc Always re-generate config file if TEMPLATE_CONFIG is set to true
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-06-24 18:19:41 +02:00
stephb9959
d4602f0db1 Fix: https://telecominfraproject.atlassian.net/browse/WIFI-9553
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-06-23 11:00:04 -07:00
stephb9959
d4148e6f01 Fixing wrong error number returned on bad API call.
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-06-20 10:21:28 -07:00
stephb9959
d18d567166 Merge remote-tracking branch 'origin/main' 2022-06-18 21:58:03 -07:00
stephb9959
c8186b30b7 Framework update
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-06-18 21:57:55 -07:00
Johann Hoffmann
d83c841455 [WIFI-9534] Add condition to avoid deleting default and release branch images
Signed-off-by: Johann Hoffmann <johann.hoffmann@mailbox.org>
2022-06-17 13:06:04 +02:00
stephb9959
c180e60d0a Merge remote-tracking branch 'origin/main' 2022-06-16 07:36:33 -07:00
stephb9959
dff48d6561 https://telecominfraproject.atlassian.net/browse/WIFI-9632
Signed-off-by: stephb9959 <stephane.bourque@gmail.com>
2022-06-16 07:36:22 -07:00
stephb9959
052c685938 Merge remote-tracking branch 'origin/main' 2022-06-14 09:38:49 -07:00
stephb9959
ee916d5db6 Framework update. 2022-06-14 09:38:41 -07:00
Dmitry Dunaev
64799106ae Merge pull request #4 from Telecominfraproject/fix/wifi-9174--dep-charts
[WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
2022-06-03 19:07:58 +03:00
Dmitry Dunaev
643e748a95 [WIFI-9174] Fix: switch from deprecated bitnami charts to mirrored ones
Signed-off-by: Dmitry Dunaev <dmitry@opsfleet.com>
2022-06-03 19:07:26 +03:00
stephb9959
c36f222416 Framework update. 2022-05-31 23:53:29 -07:00
stephb9959
9e9b7cc4e8 Framework update. 2022-05-31 23:26:27 -07:00
stephb9959
6c81f0585c Invalid error returned. 2022-05-31 11:50:07 -07:00
stephb9959
76d6abc994 Invalid error returned. 2022-05-31 08:54:19 -07:00
stephb9959
e905fbe155 Changing refresh timing. 2022-05-27 16:09:54 -07:00
stephb9959
5c778c0de5 Removing extraneous logs 2022-05-27 16:05:54 -07:00
stephb9959
d1a01e9d31 Removing extraneous logs 2022-05-27 15:47:27 -07:00
stephb9959
0ceb204a83 Removing extraneous logs 2022-05-27 15:38:58 -07:00
stephb9959
df7c860246 Merge remote-tracking branch 'origin/main' 2022-05-27 15:33:06 -07:00
stephb9959
1ab0e7f291 Framework update. 2022-05-27 15:32:58 -07:00
125 changed files with 33761 additions and 9077 deletions

View File

@@ -26,7 +26,7 @@ jobs:
DOCKER_REGISTRY_USERNAME: ucentral
steps:
- name: Checkout actions repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github
@@ -57,11 +57,11 @@ jobs:
- name: Get base branch name and set as output
id: get_base_branch
run: |
echo ::set-output name=branch::$(echo ${GITHUB_BASE_REF##*/})
echo ::set-output name=owgw_branch::$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')
echo "branch=$(echo ${GITHUB_BASE_REF##*/})" >> $GITHUB_OUTPUT
echo "owgw_branch=$(echo ${GITHUB_BASE_REF##*/} | sed 's/main/master/g')" >> $GITHUB_OUTPUT
- name: Checkout actions repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github
@@ -86,7 +86,7 @@ jobs:
- docker
steps:
- name: Checkout actions repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github

View File

@@ -4,6 +4,7 @@ on:
pull_request:
branches:
- main
- 'release/*'
types: [ closed ]
defaults:
@@ -16,4 +17,10 @@ jobs:
steps:
- 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/owanalytics/$PR_BRANCH_TAG"
if [[ ! $PR_BRANCH_TAG =~ (main|master|release-*) ]]; then
echo "PR branch is $PR_BRANCH_TAG, deleting Docker image"
curl -s -uucentral:${{ secrets.DOCKER_REGISTRY_PASSWORD }} -X DELETE "https://tip.jfrog.io/artifactory/tip-wlan-cloud-ucentral/owanalytics/$PR_BRANCH_TAG"
else
echo "PR branch is $PR_BRANCH_TAG, not deleting Docker image"
fi

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout actions repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
repository: Telecominfraproject/.github
path: github

41
.github/workflows/openapi-pages.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Update OpenAPI docs on GitHub Pages
on:
push:
paths:
- 'openapi/**'
branches:
- main
workflow_dispatch:
defaults:
run:
shell: bash
jobs:
docsgen:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Generate static HTML page with docs from OpenAPI definition
run: |
docker run --rm -v "${PWD}:/local" openapitools/openapi-generator-cli:v6.2.1 generate -i https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-analytics/main/openapi/owanalytics.yaml -g html2 --skip-validate-spec -o /local/
- name: Update OpenAPI docs
run: |
mkdir tmp-docs
mv index.html tmp-docs/index.html
mkdir -p ~/.ssh
ssh-keyscan -H github.com >> ~/.ssh/known_hosts
echo https://tip-automation:${{ secrets.GIT_PUSH_PAT }}@github.com > ~/.git-credentials
git config --global credential.helper store
git config --global user.email "tip-automation@telecominfraproject.com"
git config --global user.name "TIP Automation User"
git pull
git checkout gh-pages || git checkout -b gh-pages
rm -rf docs
mv tmp-docs docs
git add docs
git commit -m'Update OpenAPI docs for GitHub pages'
git push --set-upstream origin gh-pages

View File

@@ -17,7 +17,7 @@ jobs:
HELM_REPO_USERNAME: ucentral
steps:
- name: Checkout uCentral assembly chart repo
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
path: wlan-cloud-analytics

1
.gitignore vendored
View File

@@ -32,6 +32,7 @@
*.app
test_scripts/curl/token.json
test_scripts/curl/result.json
.vscode/c_cpp_properties.json
test_scripts/curl/result.json
*.swp

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.13)
project(owanalytics VERSION 2.6.0)
project(owanalytics VERSION 2.8.0)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_GENERATOR "Unix Makefiles")
@@ -28,17 +28,18 @@ endif()
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} describe --always --tags
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_RESULT
OUTPUT_VARIABLE GIT_HASH)
if(NOT GIT_RESULT EQUAL "0")
message(FATAL_ERROR "git describe --always --tags failed with ${GIT_RESULT}")
message(FATAL_ERROR "git rev-parse --short HEAD failed with ${GIT_RESULT}")
endif()
string(REGEX REPLACE "\n$" "" GIT_HASH "${GIT_HASH}")
endif()
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Poco REQUIRED COMPONENTS Crypto JWT Net Util NetSSL Data DataSQLite)
find_package(nlohmann_json REQUIRED)
find_package(nlohmann_json_schema_validator REQUIRED)
@@ -63,6 +64,8 @@ include_directories(/usr/local/include /usr/local/opt/openssl/include src inclu
configure_file(src/ow_version.h.in ${PROJECT_SOURCE_DIR}/src/ow_version.h @ONLY)
add_definitions(-DPOCO_LOG_DEBUG="1")
add_executable(owanalytics
build
src/ow_version.h.in
@@ -72,14 +75,56 @@ add_executable(owanalytics
src/framework/OpenWifiTypes.h
src/framework/orm.h
src/framework/StorageClass.h
src/framework/MicroServiceErrorHandler.h
src/framework/UI_WebSocketClientServer.cpp
src/framework/UI_WebSocketClientServer.h
src/framework/UI_WebSocketClientNotifications.cpp
src/framework/UI_WebSocketClientNotifications.h
src/framework/utils.h
src/framework/utils.cpp
src/framework/AppServiceRegistry.h
src/framework/SubSystemServer.cpp
src/framework/SubSystemServer.h
src/framework/RESTAPI_utils.h
src/framework/AuthClient.cpp
src/framework/AuthClient.h
src/framework/MicroServiceNames.h
src/framework/MicroServiceFuncs.h
src/framework/OpenAPIRequests.cpp
src/framework/OpenAPIRequests.h
src/framework/MicroServiceFuncs.cpp
src/framework/ALBserver.cpp
src/framework/ALBserver.h
src/framework/KafkaManager.cpp
src/framework/KafkaManager.h
src/framework/RESTAPI_RateLimiter.h
src/framework/WebSocketLogger.h
src/framework/RESTAPI_GenericServerAccounting.h
src/framework/RESTAPI_SystemConfiguration.h
src/framework/CIDR.h
src/framework/RESTAPI_Handler.cpp
src/framework/RESTAPI_Handler.h
src/framework/RESTAPI_ExtServer.h
src/framework/RESTAPI_ExtServer.cpp
src/framework/RESTAPI_IntServer.cpp
src/framework/RESTAPI_IntServer.h
src/framework/RESTAPI_SystemCommand.h
src/framework/RESTAPI_WebSocketServer.h
src/framework/EventBusManager.cpp
src/framework/EventBusManager.h
src/framework/RESTAPI_PartHandler.h
src/framework/MicroService.cpp
src/framework/MicroServiceExtra.h
src/framework/ConfigurationValidator.cpp
src/framework/ConfigurationValidator.h
src/framework/ow_constants.h
src/framework/WebSocketClientNotifications.h
src/RESTObjects/RESTAPI_SecurityObjects.h src/RESTObjects/RESTAPI_SecurityObjects.cpp
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
src/RESTObjects/RESTAPI_CertObjects.cpp src/RESTObjects/RESTAPI_CertObjects.h
src/RESTObjects/RESTAPI_OWLSobjects.cpp src/RESTObjects/RESTAPI_OWLSobjects.h
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
src/RESTObjects/RESTAPI_AnalyticsObjects.cpp src/RESTObjects/RESTAPI_AnalyticsObjects.h
src/RESTObjects/RESTAPI_SubObjects.cpp src/RESTObjects/RESTAPI_SubObjects.h
src/RESTAPI/RESTAPI_routers.cpp
src/Daemon.cpp src/Daemon.h
src/Dashboard.h src/Dashboard.cpp

View File

@@ -1,16 +1,22 @@
FROM alpine:3.15 AS build-base
ARG DEBIAN_VERSION=11.5-slim
ARG POCO_VERSION=poco-tip-v2
ARG CPPKAFKA_VERSION=tip-v1
ARG JSON_VALIDATOR_VERSION=2.1.0
RUN apk add --update --no-cache \
FROM debian:$DEBIAN_VERSION AS build-base
RUN apt-get update && apt-get install --no-install-recommends -y \
make cmake g++ git \
unixodbc-dev postgresql-dev mariadb-dev \
librdkafka-dev boost-dev openssl-dev \
zlib-dev nlohmann-json \
curl-dev
libpq-dev libmariadb-dev libmariadbclient-dev-compat \
librdkafka-dev libboost-all-dev libssl-dev \
zlib1g-dev nlohmann-json3-dev ca-certificates libcurl4-openssl-dev libfmt-dev
FROM build-base AS poco-build
ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/poco /poco
ARG POCO_VERSION
ADD https://api.github.com/repos/AriliaWireless/poco/git/refs/tags/${POCO_VERSION} version.json
RUN git clone https://github.com/AriliaWireless/poco --branch ${POCO_VERSION} /poco
WORKDIR /poco
RUN mkdir cmake-build
@@ -21,8 +27,10 @@ RUN cmake --build . --target install
FROM build-base AS cppkafka-build
ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json
RUN git clone https://github.com/stephb9959/cppkafka /cppkafka
ARG CPPKAFKA_VERSION
ADD https://api.github.com/repos/AriliaWireless/cppkafka/git/refs/tags/${CPPKAFKA_VERSION} version.json
RUN git clone https://github.com/AriliaWireless/cppkafka --branch ${CPPKAFKA_VERSION} /cppkafka
WORKDIR /cppkafka
RUN mkdir cmake-build
@@ -33,8 +41,10 @@ RUN cmake --build . --target install
FROM build-base AS json-schema-validator-build
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json
RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator
ARG JSON_VALIDATOR_VERSION
ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/tags/${JSON_VALIDATOR_VERSION} version.json
RUN git clone https://github.com/pboettch/json-schema-validator --branch ${JSON_VALIDATOR_VERSION} /json-schema-validator
WORKDIR /json-schema-validator
RUN mkdir cmake-build
@@ -43,18 +53,6 @@ RUN cmake ..
RUN make
RUN make install
FROM build-base AS fmtlib-build
ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json
RUN git clone https://github.com/fmtlib/fmt /fmtlib
WORKDIR /fmtlib
RUN mkdir cmake-build
WORKDIR cmake-build
RUN cmake ..
RUN make
RUN make install
FROM build-base AS owanalytics-build
ADD CMakeLists.txt build /owanalytics/
@@ -68,8 +66,6 @@ COPY --from=cppkafka-build /usr/local/include /usr/local/include
COPY --from=cppkafka-build /usr/local/lib /usr/local/lib
COPY --from=json-schema-validator-build /usr/local/include /usr/local/include
COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib
COPY --from=fmtlib-build /usr/local/include /usr/local/include
COPY --from=fmtlib-build /usr/local/lib /usr/local/lib
WORKDIR /owanalytics
RUN mkdir cmake-build
@@ -77,21 +73,21 @@ WORKDIR /owanalytics/cmake-build
RUN cmake ..
RUN cmake --build . --config Release -j8
FROM alpine:3.15
FROM debian:$DEBIAN_VERSION
ENV OWANALYTICS_USER=owanalytics \
OWANALYTICS_ROOT=/owanalytics-data \
OWANALYTICS_CONFIG=/owanalytics-data
RUN addgroup -S "$OWANALYTICS_USER" && \
adduser -S -G "$OWANALYTICS_USER" "$OWANALYTICS_USER"
RUN useradd "$OWANALYTICS_USER"
RUN mkdir /openwifi
RUN mkdir -p "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG" && \
chown "$OWANALYTICS_USER": "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG"
RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \
mariadb-connector-c libpq unixodbc postgresql-client
RUN apt-get update && apt-get install --no-install-recommends -y \
librdkafka++1 gosu gettext ca-certificates bash jq curl wget \
libmariadb-dev-compat libpq5 postgresql-client libfmt7
COPY readiness_check /readiness_check
COPY test_scripts/curl/cli /cli
@@ -100,11 +96,13 @@ COPY owanalytics.properties.tmpl /
COPY docker-entrypoint.sh /
COPY wait-for-postgres.sh /
RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem
-O /usr/local/share/ca-certificates/restapi-ca-selfsigned.crt
COPY --from=owanalytics-build /owanalytics/cmake-build/owanalytics /openwifi/owanalytics
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib
COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib/
COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib/
RUN ldconfig
EXPOSE 16009 17009 16109

View File

@@ -1,2 +1,8 @@
# wlan-cloud-analytics
OpenWiFi Analytics V0.01
## OpenAPI
You may get static page with OpenAPI docs generated from the definition on [GitHub Page](https://telecominfraproject.github.io/wlan-cloud-analytics/).
Also you may use [Swagger UI](https://petstore.swagger.io/#/) with OpenAPI definition file raw link (i.e. [latest version file](https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-analytics/main/openapi/owanalytics.yaml)) to get interactive docs page.

2
build
View File

@@ -1 +1 @@
67
18

View File

@@ -1,11 +1,11 @@
#!/bin/sh
#!/bin/bash
set -e
if [ "$SELFSIGNED_CERTS" = 'true' ]; then
update-ca-certificates
fi
if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWANALYTICS_CONFIG"/owanalytics.properties ]]; then
if [[ "$TEMPLATE_CONFIG" = 'true' ]]; then
RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWANALYTICS_ROOT/certs/restapi-ca.pem"} \
RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16009"} \
RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWANALYTICS_ROOT/certs/restapi-cert.pem"} \
@@ -24,6 +24,7 @@ if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWANALYTICS_CONFIG"/owanalytics.prop
SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17009"} \
SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16009"} \
SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \
SECURITY_RESTAPI_DISABLE=${SECURITY_RESTAPI_DISABLE:-"false"} \
KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \
KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \
KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \
@@ -48,7 +49,7 @@ if [ "$1" = '/openwifi/owanalytics' -a "$(id -u)" = '0' ]; then
if [ "$RUN_CHOWN" = 'true' ]; then
chown -R "$OWANALYTICS_USER": "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG"
fi
exec su-exec "$OWANALYTICS_USER" "$@"
exec gosu "$OWANALYTICS_USER" "$@"
fi
exec "$@"

2
helm/.gitignore vendored
View File

@@ -1 +1,3 @@
*.swp
Chart.lock
charts/

View File

@@ -70,8 +70,8 @@ The following table lists the configurable parameters of the chart and their def
| persistence.size | string | Defines PV size | `'10Gi'` |
| public_env_variables | hash | Defines list of environment variables to be passed to the Analytics | |
| configProperties | hash | Configuration properties that should be passed to the application in `owanalytics.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 Analytics (PEM format is adviced to be used) (see `volumes.owanalytics` on where it is mounted) | |
| existingCertsSecret | string | Existing Kubernetes secret containing all required certificates and private keys for microservice operation. If set, certificates from `certs` key are ignored | `""` |
| certs | hash | Defines files (keys and certificates) that should be passed to the Gateway (PEM format is adviced to be used) (see `volumes.owanalytics` on where it is mounted). If `existingCertsSecret` is set, certificates passed this way will not be used. | |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,

View File

@@ -1,4 +1,5 @@
{{- $root := . -}}
{{- $storageType := index .Values.configProperties "storage.type" -}}
---
apiVersion: apps/v1
kind: Deployment
@@ -46,6 +47,39 @@ spec:
- -timeout
- 600s
{{- if eq $storageType "postgresql" }}
- name: wait-postgres
image: "{{ .Values.images.owanalytics.repository }}:{{ .Values.images.owanalytics.tag }}"
imagePullPolicy: {{ .Values.images.owanalytics.pullPolicy }}
command:
- /wait-for-postgres.sh
- {{ index .Values.configProperties "storage.type.postgresql.host" }}
- echo
- "PostgreSQL is ready"
env:
- name: KUBERNETES_DEPLOYED
value: "{{ now }}"
{{- range $key, $value := .Values.public_env_variables }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- range $key, $value := .Values.secret_env_variables }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ include "owanalytics.fullname" $root }}-env
key: {{ $key }}
{{- end }}
volumeMounts:
{{- range .Values.volumes.owanalytics }}
- name: {{ .name }}
mountPath: {{ .mountPath }}
{{- if .subPath }}
subPath: {{ .subPath }}
{{- end }}
{{- end }}
{{- end }}
containers:
- name: owanalytics
@@ -97,8 +131,10 @@ spec:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.securityContext }}
securityContext:
fsGroup: 101
{{- toYaml . | nindent 8 }}
{{- end }}
imagePullSecrets:
{{- range $image, $imageValue := .Values.images }}

View File

@@ -9,7 +9,7 @@ fullnameOverride: ""
images:
owanalytics:
repository: tip-tip-wlan-cloud-ucentral.jfrog.io/owanalytics
tag: v2.6.0-RC1
tag: v2.8.0-RC2
pullPolicy: Always
# regcred:
# registry: tip-tip-wlan-cloud-ucentral.jfrog.io
@@ -71,7 +71,7 @@ volumes:
mountPath: /owanalytics-data/certs
volumeDefinition: |
secret:
secretName: {{ include "owanalytics.fullname" . }}-certs
secretName: {{ if .Values.existingCertsSecret }}{{ .Values.existingCertsSecret }}{{ else }}{{ include "owanalytics.fullname" . }}-certs{{ end }}
# Change this if you want to use another volume type
- name: persist
mountPath: /owanalytics-data/persist
@@ -91,6 +91,9 @@ resources: {}
# cpu: 100m
# memory: 128Mi
securityContext:
fsGroup: 1000
nodeSelector: {}
tolerations: []
@@ -198,6 +201,9 @@ configProperties:
storage.type.mysql.username: stephb
storage.type.mysql.password: snoopy99
# NOTE: List of required certificates may be found in "certs" key. Alternative way to pass required certificates is to create external secret with all required certificates and set secret name in "existingCertsSecret" key. Details may be found in https://github.com/Telecominfraproject/wlan-cloud-ucentral-deploy/tree/main/chart#tldr
existingCertsSecret: ""
certs:
# restapi-ca.pem: ""
# restapi-cert.pem: ""

View File

@@ -27,71 +27,13 @@ components:
responses:
NotFound:
description: The specified resource was not found.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: string
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/NotFound'
Unauthorized:
description: The requested does not have sufficient rights to perform the operation.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
enum:
- 0 # Success
- 1 # PASSWORD_CHANGE_REQUIRED,
- 2 # INVALID_CREDENTIALS,
- 3 # PASSWORD_ALREADY_USED,
- 4 # USERNAME_PENDING_VERIFICATION,
- 5 # PASSWORD_INVALID,
- 6 # INTERNAL_ERROR,
- 7 # ACCESS_DENIED,
- 8 # INVALID_TOKEN
- 9 # EXPIRED_TOKEN
- 10 # RATE_LIMIT_EXCEEDED
- 11 # BAD_MFA_TRANSACTION
- 12 # MFA_FAILURE
- 13 # SECURITY_SERVICE_UNREACHABLE
ErrorDetails:
type: string
ErrorDescription:
type: string
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Unauthorized'
Success:
description: The requested operation was performed.
content:
application/json:
schema:
properties:
Operation:
type: string
Details:
type: string
Code:
type: integer
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/Success'
BadRequest:
description: The requested operation failed.
content:
application/json:
schema:
properties:
ErrorCode:
type: integer
ErrorDetails:
type: string
ErrorDescription:
type: integer
$ref: 'https://github.com/Telecominfraproject/wlan-cloud-ucentralsec/blob/main/openpapi/owsec.yaml#/components/responses/BadRequest'
schemas:
ObjectInfo:
@@ -1134,42 +1076,6 @@ paths:
404:
$ref: '#/components/responses/NotFound'
/iptocountry:
get:
tags:
- Utility
summary: Get the country code for an IP address
operationId: getIpToCountry
parameters:
- in: query
name: iplist
schema:
type: string
example:
10.2.2.2,10.3.4.3
required: true
responses:
200:
description: List of country codes.
content:
application/json:
schema:
type: object
properties:
enabled:
type: boolean
countryCodes:
type: array
items:
type: string
400:
$ref: '#/components/responses/BadRequest'
403:
$ref: '#/components/responses/Unauthorized'
404:
$ref: '#/components/responses/NotFound'
/wifiClientHistory:
get:
tags:

View File

@@ -34,6 +34,7 @@ openwifi.system.uri.private = https://localhost:17009
openwifi.system.uri.public = https://ucentral.dpaas.arilia.com:16009
openwifi.system.commandchannel = /tmp/app.owanalytics
openwifi.system.uri.ui = owprov-ui.arilia.com
openwifi.security.restapi.disable = false
#############################
# Generic information for all micro services
@@ -101,4 +102,4 @@ storage.type.mysql.connectiontimeout = 60
########################################################################
logging.type = file
logging.path = $OWANALYTICS_ROOT/logs
logging.level = debug
logging.level = debug

View File

@@ -39,6 +39,7 @@ openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE}
openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC}
openwifi.system.commandchannel = /tmp/app.owanalytics
openwifi.system.uri.ui = ${SYSTEM_URI_UI}
openwifi.security.restapi.disable = ${SECURITY_RESTAPI_DISABLE}
#############################
# Generic information for all micro services

View File

@@ -6,6 +6,8 @@
#include "dict_ssid.h"
#include "StorageService.h"
#include "WifiClientCache.h"
#include "fmt/format.h"
#include "framework/utils.h"
namespace OpenWifi {
@@ -88,12 +90,19 @@ namespace OpenWifi {
return false;
}
static int BandToInt(const std::string &band) {
if(band=="2G") return 2;
if(band=="5G") return 5;
if(band=="6G") return 6;
return 2;
}
void AP::UpdateStats(const std::shared_ptr<nlohmann::json> &State) {
DI_.states++;
DI_.connected =true;
AnalyticsObjects::DeviceTimePoint DTP;
Logger().information(fmt::format("{}: stats message.", DI_.serialNumber));
poco_information(Logger(),fmt::format("{}: stats message.", DI_.serialNumber));
// find radios first to get associations.
try {
@@ -124,7 +133,13 @@ namespace OpenWifi {
if (radio.contains("channel")) {
AnalyticsObjects::RadioTimePoint RTP;
GetJSON("channel", radio, RTP.channel, (uint64_t) 2);
RTP.band = RTP.channel <= 16 ? 2 : 5;
if(radio.contains("band") && radio["band"].is_array()) {
auto BandArray = radio["band"];
RTP.band = BandToInt(BandArray[0]);
// std::cout << "BAND (radio): " << BandToInt(BandArray[0]) << std::endl;
} else {
RTP.band = RTP.channel <= 16 ? 2 : 5;
}
radio_map[radio_index++] = std::make_pair(RTP.band, RTP.channel);
GetJSON("busy_ms", radio, RTP.busy_ms, (uint64_t) 0);
GetJSON("receive_ms", radio, RTP.receive_ms, (uint64_t) 0);
@@ -158,6 +173,7 @@ namespace OpenWifi {
auto interfaces = (*State)["interfaces"];
DI_.associations_2g = DI_.associations_5g = DI_.associations_6g = 0;
for(const auto &interface:interfaces) {
std::string InterfaceName = fmt::format("{}: {}", DI_.serialNumber, interface.contains("name") ? to_string(interface["name"]) : "unknown");
if(interface.contains("counters")) {
auto counters = interface["counters"];
GetJSON("collisions", counters, DTP.ap_data.collisions, (uint64_t) 0);
@@ -172,13 +188,57 @@ namespace OpenWifi {
GetJSON("tx_packets", counters, DTP.ap_data.tx_packets, (uint64_t) 0);
}
InterfaceClientEntryMap_t ICEM;
if(interface.contains("clients") && interface["clients"].is_array()) {
try {
auto Clients = interface["clients"];
for(const auto & client: Clients) {
if(client.contains("mac") && client["mac"].is_string()) {
InterfaceClientEntry E;
if(client.contains("ipv4_addresses") && client["ipv4_addresses"].is_array()) {
for(const auto &ip:client["ipv4_addresses"]) {
E.ipv4_addresses.push_back(ip);
}
}
if(client.contains("ipv6_addresses") && client["ipv6_addresses"].is_array()) {
for(const auto &ip:client["ipv6_addresses"]) {
E.ipv6_addresses.push_back(ip);
}
}
auto M = mac_filter(client["mac"]);
ICEM[M] = E;
}
}
} catch(...) {
std::cout << "Exception while parsing clients: " << InterfaceName << std::endl;
}
} else {
// std::cout <<"Interface: No clients: " << InterfaceName << std::endl;
}
if(interface.contains("ssids")) {
auto ssids = interface["ssids"];
for (const auto &ssid: ssids) {
AnalyticsObjects::SSIDTimePoint SSIDTP;
uint radio_location=0;
SSIDTP.band = 2;
if(ssid.contains("radio")) {
if(ssid.contains("band")) {
std::string Band = ssid["band"];
SSIDTP.band = BandToInt(Band);
// std::cout << "BAND (ssid): " << SSIDTP.band << std::endl;
auto radio = ssid["radio"];
if(radio.contains("$ref")) {
auto ref = radio["$ref"];
auto radio_parts = Poco::StringTokenizer(ref, "/");
if(radio_parts.count()==3) {
radio_location = std::strtol(radio_parts[2].c_str(), nullptr, 10);
if(radio_map.find(radio_location)!=radio_map.end()) {
SSIDTP.channel = radio_map[radio_location].second;
}
}
}
} else if(ssid.contains("radio")) {
auto radio = ssid["radio"];
if(radio.contains("$ref")) {
auto ref = radio["$ref"];
@@ -243,8 +303,19 @@ namespace OpenWifi {
GetJSON("rx_packets",association,WFH.rx_packets,(uint64_t)0);
GetJSON("tx_packets",association,WFH.tx_packets,(uint64_t)0);
WFH.ipv4 = "---";
WFH.ipv6 = "----";
// try to locate the IP addresses
auto ClientInfo = ICEM.find(WFH.station_id);
if(ClientInfo!=end(ICEM)) {
if(!ClientInfo->second.ipv4_addresses.empty()) {
WFH.ipv4 = ClientInfo->second.ipv4_addresses[0];
}
if(!ClientInfo->second.ipv6_addresses.empty()) {
WFH.ipv6 = ClientInfo->second.ipv6_addresses[0];
}
// std::cout << __LINE__ << ": " << InterfaceName << " Mac Found: " << ICEM.size() << " entries. " << WFH.station_id << std::endl;
} else {
// std::cout << __LINE__ << ": " << InterfaceName << " Mac NOT found: " << ICEM.size() << " entries. " << WFH.station_id << std::endl;
}
for(const auto &rd:DTP.radio_data) {
if(rd.band == SSIDTP.band) {
@@ -311,7 +382,7 @@ namespace OpenWifi {
}
DTP.device_info = DI_;
} catch (...) {
Logger().information(fmt::format("{}: stats failed parsing.", DI_.serialNumber));
poco_information(Logger(),fmt::format("{}: stats failed parsing.", DI_.serialNumber));
}
if(got_base) {
@@ -421,7 +492,7 @@ namespace OpenWifi {
}
if (got_connection && got_health) {
db_DTP.id = MicroService::instance().CreateUUID();
db_DTP.id = MicroServiceCreateUUID();
db_DTP.boardId = boardId_;
db_DTP.serialNumber = db_DTP.device_info.serialNumber;
StorageService()->TimePointsDB().CreateRecord(db_DTP);
@@ -435,49 +506,49 @@ namespace OpenWifi {
void AP::UpdateConnection(const std::shared_ptr<nlohmann::json> &Connection) {
DI_.pings++;
DI_.lastContact = OpenWifi::Now();
DI_.lastContact = Utils::Now();
try {
if (Connection->contains("ping")) {
got_connection = true;
Logger().information(fmt::format("{}: ping message.", DI_.serialNumber));
poco_debug(Logger(),fmt::format("{}: ping message.", DI_.serialNumber));
DI_.connected = true;
DI_.lastPing = OpenWifi::Now();
DI_.lastPing = Utils::Now();
auto ping = (*Connection)["ping"];
GetJSON("compatible", ping, DI_.deviceType, std::string{} );
GetJSON("connectionIp", ping, DI_.connectionIp, std::string{} );
GetJSON("locale", ping, DI_.locale, std::string{} );
GetJSON("timestamp", ping, DI_.lastConnection, (uint64_t) OpenWifi::Now() );
GetJSON("timestamp", ping, DI_.lastConnection, (uint64_t) Utils::Now() );
if (ping.contains("firmware")) {
auto NewFirmware = ping["firmware"];
if (NewFirmware != DI_.lastFirmware) {
DI_.lastFirmware = NewFirmware;
DI_.lastFirmwareUpdate = OpenWifi::Now();
DI_.lastFirmwareUpdate = Utils::Now();
}
}
} else if (Connection->contains("disconnection")) {
Logger().information(fmt::format("{}: disconnection message.", DI_.serialNumber));
poco_debug(Logger(),fmt::format("{}: disconnection message.", DI_.serialNumber));
auto Disconnection = (*Connection)["disconnection"];
GetJSON("timestamp", Disconnection, DI_.lastDisconnection, (uint64_t)0 );
got_base = got_health = got_connection = false;
DI_.connected = false;
} else if (Connection->contains("capabilities")) {
Logger().information(fmt::format("{}: connection message.", DI_.serialNumber));
poco_debug(Logger(),fmt::format("{}: connection message.", DI_.serialNumber));
got_connection = true;
DI_.connected = true;
DI_.lastConnection = OpenWifi::Now();
DI_.lastConnection = Utils::Now();
auto ConnectionData = (*Connection)["capabilities"];
if (ConnectionData.contains("firmware")) {
auto NewFirmware = ConnectionData["firmware"];
if (NewFirmware != DI_.lastFirmware) {
DI_.lastFirmware = NewFirmware;
DI_.lastFirmwareUpdate = OpenWifi::Now();
DI_.lastFirmwareUpdate = Utils::Now();
}
}
GetJSON("connectionIp", ConnectionData, DI_.connectionIp, std::string{} );
GetJSON("locale", ConnectionData, DI_.locale, std::string{} );
}
} catch (...) {
Logger().information(fmt::format("{}: error parsing connection message.", DI_.serialNumber));
poco_information(Logger(),fmt::format("{}: error parsing connection message.", DI_.serialNumber));
}
}
@@ -486,9 +557,9 @@ namespace OpenWifi {
got_health = true;
GetJSON("timestamp", *Health, DI_.lastHealth, (uint64_t)0 );
GetJSON("sanity", *Health, DI_.health, (uint64_t)0 );
Logger().information(fmt::format("{}: health message.", DI_.serialNumber));
poco_debug(Logger(),fmt::format("{}: health message.", DI_.serialNumber));
} catch(...) {
Logger().information(fmt::format("{}: error parsing health message.", DI_.serialNumber));
poco_information(Logger(),fmt::format("{}: error parsing health message.", DI_.serialNumber));
}
}
}

View File

@@ -5,12 +5,20 @@
#pragma once
#include <mutex>
#include "framework/MicroService.h"
#include "nlohmann/json.hpp"
#include "RESTObjects/RESTAPI_AnalyticsObjects.h"
#include "framework/utils.h"
#include "Poco/Logger.h"
namespace OpenWifi {
struct InterfaceClientEntry {
std::vector<std::string> ipv4_addresses;
std::vector<std::string> ipv6_addresses;
};
using InterfaceClientEntryMap_t = std::map<std::string,InterfaceClientEntry>;
class AP {
public:
explicit AP(uint64_t mac, const std::string &venue_id, const std::string &BoardId, Poco::Logger &L) :

View File

@@ -6,17 +6,21 @@
// Arilia Wireless Inc.
//
#include "Daemon.h"
#include "Poco/Util/Application.h"
#include "Poco/Util/Option.h"
#include "Poco/Environment.h"
#include "Poco/Net/SSLManager.h"
#include "framework/OpenWifiTypes.h"
#include "Daemon.h"
#include "StorageService.h"
#include "VenueCoordinator.h"
#include "StateReceiver.h"
#include "DeviceStatusReceiver.h"
#include "HealthReceiver.h"
#include "WifiClientCache.h"
#include "framework/UI_WebSocketClientServer.h"
namespace OpenWifi {
class Daemon *Daemon::instance_ = nullptr;
@@ -34,7 +38,8 @@ namespace OpenWifi {
DeviceStatusReceiver(),
HealthReceiver(),
VenueCoordinator(),
WifiClientCache()
WifiClientCache(),
UI_WebSocketClientServer()
});
}
return instance_;
@@ -42,20 +47,32 @@ namespace OpenWifi {
void Daemon::PostInitialization([[maybe_unused]] Poco::Util::Application &self) {
}
void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
}
}
int main(int argc, char **argv) {
try {
auto App = OpenWifi::Daemon::instance();
auto ExitCode = App->run(argc, argv);
delete App;
int ExitCode;
try {
Poco::Net::SSLManager::instance().initializeServer(nullptr, nullptr, nullptr);
auto App = OpenWifi::Daemon::instance();
ExitCode = App->run(argc, argv);
Poco::Net::SSLManager::instance().shutdown();
} catch (Poco::Exception &exc) {
ExitCode = Poco::Util::Application::EXIT_SOFTWARE;
std::cout << exc.displayText() << std::endl;
} catch (std::exception &exc) {
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
std::cout << exc.what() << std::endl;
} catch (...) {
ExitCode = Poco::Util::Application::EXIT_TEMPFAIL;
std::cout << "Exception on closure" << std::endl;
}
return ExitCode;
} catch (Poco::Exception &exc) {
std::cerr << exc.displayText() << std::endl;
return Poco::Util::Application::EXIT_SOFTWARE;
}
std::cout << "Exitcode: " << ExitCode << std::endl;
return ExitCode;
}
// end of namespace

View File

@@ -16,6 +16,7 @@
#include "Dashboard.h"
#include "framework/MicroService.h"
#include "framework/MicroServiceNames.h"
#include "framework/OpenWifiTypes.h"
#include "RESTObjects/RESTAPI_AnalyticsObjects.h"
@@ -47,8 +48,6 @@ namespace OpenWifi {
};
inline Daemon * Daemon() { return Daemon::instance(); }
inline void DaemonPostInitialization(Poco::Util::Application &self) {
Daemon()->PostInitialization(self);
}
void DaemonPostInitialization(Poco::Util::Application &self);
}

View File

@@ -7,11 +7,11 @@
//
#include "Dashboard.h"
#include "StorageService.h"
#include "framework/utils.h"
namespace OpenWifi {
void AnalyticsDashboard::Create() {
uint64_t Now = OpenWifi::Now();
uint64_t Now = Utils::Now();
if(LastRun_==0 || (Now-LastRun_)>120) {
DB_.reset();
// Todo: call dashboard creation code.

View File

@@ -5,6 +5,8 @@
#include "DeviceStatusReceiver.h"
#include "VenueWatcher.h"
#include "fmt/core.h"
#include "framework/KafkaTopics.h"
#include "framework/KafkaManager.h"
namespace OpenWifi {
int DeviceStatusReceiver::Start() {
@@ -23,6 +25,7 @@ namespace OpenWifi {
}
void DeviceStatusReceiver::run() {
Utils::SetThreadName("dev-status");
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
while(Note && Running_) {
auto Msg = dynamic_cast<DeviceStatusMessage *>(Note.get());
@@ -74,7 +77,7 @@ namespace OpenWifi {
void DeviceStatusReceiver::DeviceStatusReceived(const std::string &Key, const std::string &Payload) {
std::lock_guard G(Mutex_);
Logger().information(fmt::format("Device({}): Connection/Ping message.", Key));
poco_debug(Logger(),fmt::format("Device({}): Connection/Ping message.", Key));
Queue_.enqueueNotification( new DeviceStatusMessage(Key,Payload));
}
}

View File

@@ -4,8 +4,9 @@
#pragma once
#include "framework/MicroService.h"
// #include "VenueWatcher.h"
#include "framework/SubSystemServer.h"
#include "Poco/NotificationQueue.h"
#include "Poco/Notification.h"
namespace OpenWifi {
class DeviceStatusMessage : public Poco::Notification {

View File

@@ -4,6 +4,8 @@
#include "HealthReceiver.h"
#include "VenueWatcher.h"
#include "framework/KafkaManager.h"
#include "framework/KafkaTopics.h"
#include "fmt/core.h"
namespace OpenWifi {
@@ -23,6 +25,7 @@ namespace OpenWifi {
}
void HealthReceiver::run() {
Utils::SetThreadName("dev-health");
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
while(Note && Running_) {
auto Msg = dynamic_cast<HealthMessage *>(Note.get());
@@ -74,7 +77,7 @@ namespace OpenWifi {
void HealthReceiver::HealthReceived(const std::string &Key, const std::string &Payload) {
std::lock_guard G(Mutex_);
Logger().information(fmt::format("Device({}): Health message.", Key));
poco_debug(Logger(),fmt::format("Device({}): Health message.", Key));
Queue_.enqueueNotification( new HealthMessage(Key,Payload));
}
}

View File

@@ -2,21 +2,11 @@
// Created by stephane bourque on 2022-03-15.
//
#ifndef OWANALYTICS_HEALTHRECEIVER_H
#define OWANALYTICS_HEALTHRECEIVER_H
class HealthReceiver {
};
#endif //OWANALYTICS_HEALTHRECEIVER_H
#pragma once
#include "framework/MicroService.h"
// #include "VenueWatcher.h"
#include "framework/SubSystemServer.h"
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
namespace OpenWifi {
class HealthMessage : public Poco::Notification {

View File

@@ -4,7 +4,6 @@
#pragma once
#include "framework/MicroService.h"
#include "RESTObjects/RESTAPI_AnalyticsObjects.h"
#include "StorageService.h"
#include "framework/orm.h"

View File

@@ -8,8 +8,13 @@
namespace OpenWifi {
void RESTAPI_board_devices_handler::DoGet() {
auto id = GetBinding("id","");
if(id.empty()) {
return BadRequest(RESTAPI::Errors::MissingUUID);
}
AnalyticsObjects::BoardInfo BI;
if(!StorageService()->BoardsDB().GetRecord("id",id,BI)) {
return NotFound();

View File

@@ -4,14 +4,14 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/RESTAPI_Handler.h"
#include "StorageService.h"
namespace OpenWifi {
class RESTAPI_board_devices_handler : public RESTAPIHandler {
public:
RESTAPI_board_devices_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
RESTAPI_board_devices_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -60,6 +60,7 @@ namespace OpenWifi {
NewBoard.to_json(Answer);
return ReturnObject(Answer);
}
return InternalError(RESTAPI::Errors::RecordNotCreated);
}
void RESTAPI_board_handler::DoPut() {
@@ -89,7 +90,7 @@ namespace OpenWifi {
}
if(StorageService()->BoardsDB().UpdateRecord("id",Existing.info.id,Existing)) {
VenueCoordinator()->ModifyBoard(Existing.info.id);
VenueCoordinator()->UpdateBoard(Existing.info.id);
AnalyticsObjects::BoardInfo NewBoard;
StorageService()->BoardsDB().GetRecord("id",Existing.info.id,NewBoard);
Poco::JSON::Object Answer;

View File

@@ -4,14 +4,14 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/RESTAPI_Handler.h"
#include "StorageService.h"
namespace OpenWifi {
class RESTAPI_board_handler : public RESTAPIHandler {
public:
RESTAPI_board_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
RESTAPI_board_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -4,15 +4,14 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/RESTAPI_Handler.h"
#include "StorageService.h"
#include "RESTObjects/RESTAPI_AnalyticsObjects.h"
namespace OpenWifi {
class RESTAPI_board_list_handler : public RESTAPIHandler {
public:
RESTAPI_board_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
RESTAPI_board_list_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -5,54 +5,11 @@
#include "RESTAPI_board_timepoint_handler.h"
#include "StorageService.h"
#include <algorithm>
namespace OpenWifi {
static auto find_number_of_buckets(std::vector<AnalyticsObjects::DeviceTimePoint> &p) {
uint32_t buckets=0,cur_buckets=0;
std::string current_serialNumber;
for(const auto &i:p) {
if(current_serialNumber.empty()) {
current_serialNumber = i.device_info.serialNumber;
cur_buckets=0;
}
if(current_serialNumber==i.device_info.serialNumber) {
cur_buckets++;
} else {
buckets = std::max(buckets,cur_buckets);
current_serialNumber=i.device_info.serialNumber;
cur_buckets=1;
}
}
return std::max(buckets,cur_buckets);
}
typedef std::vector< std::vector<AnalyticsObjects::DeviceTimePoint>> split_points;
static void split_in_buckets([[maybe_unused]] uint32_t buckets,std::vector<AnalyticsObjects::DeviceTimePoint> &p,split_points &sp) {
std::string cur_sn;
uint32_t cur_bucket=0;
for(const auto &i:p) {
if(cur_sn.empty()) {
cur_bucket=1;
cur_sn=i.device_info.serialNumber;
}
if(cur_sn==i.device_info.serialNumber) {
if (cur_bucket>sp.size()) {
std::vector<AnalyticsObjects::DeviceTimePoint> tmp_p;
tmp_p.push_back(i);
sp.push_back(tmp_p);
cur_bucket++;
} else {
sp[cur_bucket-1].push_back(i);
cur_bucket++;
}
} else {
cur_bucket=1;
sp[cur_bucket-1].push_back(i);
cur_bucket++;
cur_sn=i.device_info.serialNumber;
}
}
}
typedef std::vector<std::pair<std::uint64_t , std::uint64_t >> bucket_timespans;
typedef std::vector< std::vector<AnalyticsObjects::DeviceTimePoint>> split_points;
template <typename X, typename M> void AverageAPData( X T, const std::vector<M> &Values, AnalyticsObjects::AveragePoint &P) {
if(Values.empty())
@@ -89,6 +46,81 @@ namespace OpenWifi {
P.avg = 0.0;
}
static void NewSort(const AnalyticsObjects::DeviceTimePointList &l,split_points &sp) {
struct {
bool operator()(const AnalyticsObjects::DeviceTimePoint &lhs, const AnalyticsObjects::DeviceTimePoint &rhs) const {
if (lhs.device_info.serialNumber < rhs.device_info.serialNumber) return true;
if (lhs.device_info.serialNumber > rhs.device_info.serialNumber) return false;
return lhs.timestamp < rhs.timestamp;
}
} sort_serial_ts;
// attempt at finding an interval
AnalyticsObjects::DeviceTimePointList tmp{l};
std::sort(tmp.points.begin(),tmp.points.end(),sort_serial_ts);
std::string cur_ser;
std::uint64_t cur_int=0,start_val, last_val, first_val = 0;
for(const auto &point:tmp.points) {
if(cur_ser.empty()) {
start_val = point.timestamp;
cur_ser = point.serialNumber;
first_val = point.timestamp;
continue;
}
if(cur_ser==point.serialNumber) {
auto this_int = point.timestamp - start_val;
if(cur_int) {
if(this_int<cur_int) {
cur_int = this_int;
}
} else {
cur_int = this_int;
}
start_val = point.timestamp;
} else {
cur_ser = point.serialNumber;
start_val = point.timestamp;
}
last_val = point.timestamp;
}
// std::cout << "Intervals: " << cur_int << std::endl;
std::vector<std::pair<std::uint64_t,std::uint64_t>> time_slots; // timeslot 0 has <t1,t2>
std::vector<std::set<std::string>> serial_numbers; // serial number already in a timeslot.
std::uint64_t cur_first=first_val,cur_end=0;
sp.clear();
while(cur_end<last_val) {
std::pair<std::uint64_t,std::uint64_t> e;
e.first = cur_first;
e.second = e.first + cur_int-1;
cur_first = e.second+1;
cur_end = e.second;
time_slots.emplace_back(e);
std::set<std::string> q;
serial_numbers.emplace_back(q);
std::vector<AnalyticsObjects::DeviceTimePoint> qq;
sp.emplace_back(qq);
}
for(const auto &point:tmp.points) {
std::uint64_t slot_index=0;
for(const auto &slot:time_slots) {
if(point.timestamp >= slot.first && point.timestamp <= slot.second) {
serial_numbers[slot_index].insert(point.serialNumber);
sp[slot_index].emplace_back(point);
}
slot_index++;
}
}
}
void RESTAPI_board_timepoint_handler::DoGet() {
auto id = GetBinding("id","");
if(id.empty() || !Utils::ValidUUID(id)) {
@@ -102,7 +134,12 @@ namespace OpenWifi {
auto fromDate = GetParameter("fromDate",0);
auto endDate = GetParameter("endDate",0);
auto maxRecords = GetParameter("maxRecords",1000);
std::uint64_t maxRecords;
if(Request->has("limit"))
maxRecords = QB_.Limit;
else
maxRecords = GetParameter("maxRecords",1000);
auto statsOnly = GetBoolParameter("statsOnly");
auto pointsOnly = GetBoolParameter("pointsOnly");
auto pointsStatsOnly = GetBoolParameter("pointsStatsOnly");
@@ -115,71 +152,39 @@ namespace OpenWifi {
return ReturnObject(Answer);
}
auto Points = std::make_unique<AnalyticsObjects::DeviceTimePointList>();
StorageService()->TimePointsDB().SelectRecords(id,fromDate, endDate, maxRecords, Points->points);
AnalyticsObjects::DeviceTimePointList Points;
StorageService()->TimePointsDB().SelectRecords(id,fromDate, endDate, maxRecords, Points.points);
std::cout << "1 MaxRecords=" << maxRecords << " retrieved=" << Points.points.size() << std::endl;
// sort by timestamp & serial number.
struct {
bool operator()(const AnalyticsObjects::DeviceTimePoint &lhs, const AnalyticsObjects::DeviceTimePoint &rhs) const {
if(lhs.device_info.serialNumber < rhs.device_info.serialNumber) return true;
if(lhs.device_info.serialNumber > rhs.device_info.serialNumber) return false;
return lhs.timestamp < rhs.timestamp;
}
} DeviceTimePoint_sort;
split_points sp;
struct {
bool operator()(const AnalyticsObjects::SSIDTimePoint &lhs, const AnalyticsObjects::SSIDTimePoint &rhs) const {
if(lhs.ssid < rhs.ssid) return true;
if(lhs.ssid > rhs.ssid) return false;
return lhs.bssid < rhs.bssid;
}
} SSID_sort;
NewSort(Points,sp);
std::cout << __LINE__ << std::endl;
struct {
bool operator()(const AnalyticsObjects::UETimePoint &lhs, const AnalyticsObjects::UETimePoint &rhs) const {
if(lhs.station < rhs.station) return true;
return false;
}
} Association_sort;
std::sort( Points->points.begin(), Points->points.end(), DeviceTimePoint_sort);
auto BucketsNeeded = find_number_of_buckets(Points->points);
auto sp = std::make_unique<split_points>();
split_in_buckets(BucketsNeeded,Points->points, *sp);
// must sort each bucket according to serial number.
for(auto &i: *sp) {
std::sort(i.begin(),i.end(),DeviceTimePoint_sort);
// now sort according to UEs within a block
for(auto &j:i) {
std::sort(j.ssid_data.begin(),j.ssid_data.end(),SSID_sort);
for(auto &k:j.ssid_data) {
std::sort(k.associations.begin(),k.associations.end(),Association_sort);
}
}
}
auto Answer = std::make_unique<Poco::JSON::Object>();
Poco::JSON::Object Answer;
if(!pointsStatsOnly) {
auto Points_OuterArray = std::make_unique<Poco::JSON::Array>();
for (const auto &point_list:*sp) {
Poco::JSON::Array Points_OuterArray;
for (const auto &point_list:sp) {
Poco::JSON::Array Points_InnerArray;
for (const auto &point: point_list) {
Poco::JSON::Object O;
point.to_json(O);
Points_InnerArray.add(O);
}
Points_OuterArray->add(Points_InnerArray);
Points_OuterArray.add(Points_InnerArray);
}
Answer->set("points",*Points_OuterArray);
Answer.set("points",Points_OuterArray);
}
// calculate the stats for each time slot
if(!pointsOnly) {
auto Stats_Array = std::make_unique<Poco::JSON::Array>();
for (const auto &point_list:*sp) {
Poco::JSON::Array Stats_Array;
for (const auto &point_list:sp) {
AnalyticsObjects::DeviceTimePointAnalysis DTPA;
if(point_list.empty())
continue;
DTPA.timestamp = point_list[0].timestamp;
AverageAPData(&AnalyticsObjects::APTimePoint::tx_bytes_bw, point_list, DTPA.tx_bytes_bw);
AverageAPData(&AnalyticsObjects::APTimePoint::rx_bytes_bw, point_list, DTPA.rx_bytes_bw);
@@ -200,12 +205,12 @@ namespace OpenWifi {
Poco::JSON::Object Stats_point;
DTPA.to_json(Stats_point);
Stats_Array->add(Stats_point);
Stats_Array.add(Stats_point);
}
Answer->set("stats", *Stats_Array);
Answer.set("stats", Stats_Array);
}
return ReturnObject(*Answer);
return ReturnObject(Answer);
}
void RESTAPI_board_timepoint_handler::DoDelete() {

View File

@@ -4,14 +4,14 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/RESTAPI_Handler.h"
#include "StorageService.h"
namespace OpenWifi {
class RESTAPI_board_timepoint_handler : public RESTAPIHandler {
public:
RESTAPI_board_timepoint_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
RESTAPI_board_timepoint_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -2,17 +2,18 @@
// Created by stephane bourque on 2021-10-23.
//
#include "framework/MicroService.h"
#include "RESTAPI/RESTAPI_board_list_handler.h"
#include "RESTAPI/RESTAPI_board_handler.h"
#include "RESTAPI/RESTAPI_board_devices_handler.h"
#include "RESTAPI/RESTAPI_board_timepoint_handler.h"
#include "RESTAPI/RESTAPI_wificlienthistory_handler.h"
#include "framework/RESTAPI_SystemCommand.h"
#include "framework/RESTAPI_WebSocketServer.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S,
Poco::Logger & L, RESTAPI_GenericServerAccounting & S,
uint64_t TransactionId) {
return RESTAPI_Router<
RESTAPI_system_command,
@@ -20,12 +21,13 @@ namespace OpenWifi {
RESTAPI_board_timepoint_handler,
RESTAPI_board_handler,
RESTAPI_board_list_handler,
RESTAPI_wificlienthistory_handler
RESTAPI_wificlienthistory_handler,
RESTAPI_webSocketServer
>(Path,Bindings,L, S, TransactionId);
}
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServer & S,
Poco::Logger & L, RESTAPI_GenericServerAccounting & S,
uint64_t TransactionId) {
return RESTAPI_Router_I<
RESTAPI_system_command,

View File

@@ -20,10 +20,9 @@ namespace OpenWifi {
}
if(GetBoolParameter("macsOnly")) {
auto macFilter = GetParameter("macFilter","");
std::vector<uint64_t> Macs;
WifiClientCache()->FindNumbers(venue,macFilter,500,Macs);
WifiClientCache()->FindNumbers(venue,macFilter,QB_.Offset, QB_.Limit, Macs);
Poco::JSON::Array Arr;
for(const auto &mac: Macs)
Arr.add(Utils::IntToSerialNumber(mac));
@@ -63,11 +62,8 @@ namespace OpenWifi {
return ReturnCountOnly(Count);
}
if(StorageService()->WifiClientHistoryDB().GetRecords(QB_.Offset,QB_.Limit, Results, Where, OrderBy)) {
return ReturnObject("entries",Results);
}
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
StorageService()->WifiClientHistoryDB().GetRecords(QB_.Offset,QB_.Limit, Results, Where, OrderBy);
return ReturnObject("entries",Results);
}
void RESTAPI_wificlienthistory_handler::DoDelete() {

View File

@@ -4,14 +4,14 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/RESTAPI_Handler.h"
#include "StorageService.h"
namespace OpenWifi {
class RESTAPI_wificlienthistory_handler : public RESTAPIHandler {
public:
RESTAPI_wificlienthistory_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
RESTAPI_wificlienthistory_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{
Poco::Net::HTTPRequest::HTTP_GET,

View File

@@ -4,7 +4,7 @@
#include "RESTAPI_AnalyticsObjects.h"
#include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h"
#include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;

View File

@@ -5,6 +5,7 @@
#pragma once
#include "RESTAPI_ProvObjects.h"
#include "framework/utils.h"
#include <vector>
namespace OpenWifi {
@@ -375,7 +376,7 @@ namespace OpenWifi {
};
struct WifiClientHistory {
uint64_t timestamp=OpenWifi::Now();
uint64_t timestamp=Utils::Now();
std::string station_id;
std::string bssid;
std::string ssid;

View File

@@ -3,176 +3,208 @@
//
#include "RESTAPI_CertObjects.h"
#include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi {
namespace CertObjects {
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"type", type);
field_to_json(Obj,"status", status);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"devid", devid);
field_to_json(Obj,"cas", cas);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonName", commonName);
field_to_json(Obj,"certificateId", certificateId);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"revoked", revoked);
field_to_json(Obj,"revokeCount", revokeCount);
}
namespace OpenWifi::CertObjects {
void CertificateEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"type", type);
field_to_json(Obj,"status", status);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"devid", devid);
field_to_json(Obj,"cas", cas);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonName", commonName);
field_to_json(Obj,"certificateId", certificateId);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"revoked", revoked);
field_to_json(Obj,"revokeCount", revokeCount);
field_to_json(Obj,"synched", synched);
}
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"type", type);
field_from_json(Obj,"status", status);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"devid", devid);
field_from_json(Obj,"cas", cas);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonName", commonName);
field_from_json(Obj,"certificateId", certificateId);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"revoked", revoked);
field_from_json(Obj,"revokeCount", revokeCount);
return true;
} catch (...) {
}
return false;
bool CertificateEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"type", type);
field_from_json(Obj,"status", status);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"devid", devid);
field_from_json(Obj,"cas", cas);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonName", commonName);
field_from_json(Obj,"certificateId", certificateId);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"revoked", revoked);
field_from_json(Obj,"revokeCount", revokeCount);
field_from_json(Obj,"synched", synched);
return true;
} catch (...) {
}
return false;
}
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"defaultRedirector", defaultRedirector);
field_to_json(Obj,"apiKey", apiKey);
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_to_json(Obj,"organization", organization);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"suspended", suspended);
field_to_json(Obj,"deleted", deleted);
field_to_json(Obj,"notes", notes);
}
void EntityEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"defaultRedirector", defaultRedirector);
field_to_json(Obj,"apiKey", apiKey);
field_to_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_to_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_to_json(Obj,"organization", organization);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"suspended", suspended);
field_to_json(Obj,"deleted", deleted);
field_to_json(Obj,"notes", notes);
}
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"defaultRedirector", defaultRedirector);
field_from_json(Obj,"apiKey", apiKey);
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_from_json(Obj,"organization", organization);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"suspended", suspended);
field_from_json(Obj,"deleted", deleted);
field_from_json(Obj,"notes", notes);
return true;
} catch (...) {
}
return false;
bool EntityEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"defaultRedirector", defaultRedirector);
field_from_json(Obj,"apiKey", apiKey);
field_from_json(Obj,"serverEnrollmentProfile", serverEnrollmentProfile);
field_from_json(Obj,"clientEnrollmentProfile", clientEnrollmentProfile);
field_from_json(Obj,"organization", organization);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"suspended", suspended);
field_from_json(Obj,"deleted", deleted);
field_from_json(Obj,"notes", notes);
return true;
} catch (...) {
}
return false;
}
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"jobHistory", jobHistory);
field_to_json(Obj,"notes", notes);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
field_to_json(Obj,"modified", modified);
}
void BatchEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"manufacturer", manufacturer);
field_to_json(Obj,"model", model);
field_to_json(Obj,"redirector", redirector);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"jobHistory", jobHistory);
field_to_json(Obj,"notes", notes);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
field_to_json(Obj,"modified", modified);
}
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"jobHistory", jobHistory);
field_from_json(Obj,"notes", notes);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
field_from_json(Obj,"modified", modified);
return true;
} catch (...) {
}
return false;
bool BatchEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"manufacturer", manufacturer);
field_from_json(Obj,"model", model);
field_from_json(Obj,"redirector", redirector);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"jobHistory", jobHistory);
field_from_json(Obj,"notes", notes);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
field_from_json(Obj,"modified", modified);
return true;
} catch (...) {
}
return false;
}
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"completedNames", completedNames);
field_to_json(Obj,"errorNames", errorNames);
field_to_json(Obj,"status", status);
field_to_json(Obj,"command", command);
field_to_json(Obj,"parameters", parameters);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
}
void JobEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"creator", creator);
field_to_json(Obj,"batch", batch);
field_to_json(Obj,"commonNames", commonNames);
field_to_json(Obj,"completedNames", completedNames);
field_to_json(Obj,"errorNames", errorNames);
field_to_json(Obj,"status", status);
field_to_json(Obj,"command", command);
field_to_json(Obj,"parameters", parameters);
field_to_json(Obj,"submitted", submitted);
field_to_json(Obj,"started", started);
field_to_json(Obj,"completed", completed);
field_to_json(Obj,"requesterUsername", requesterUsername);
}
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"completedNames", completedNames);
field_from_json(Obj,"errorNames", errorNames);
field_from_json(Obj,"status", status);
field_from_json(Obj,"command", command);
field_from_json(Obj,"parameters", parameters);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
return true;
} catch (...) {
}
return false;
bool JobEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"creator", creator);
field_from_json(Obj,"batch", batch);
field_from_json(Obj,"commonNames", commonNames);
field_from_json(Obj,"completedNames", completedNames);
field_from_json(Obj,"errorNames", errorNames);
field_from_json(Obj,"status", status);
field_from_json(Obj,"command", command);
field_from_json(Obj,"parameters", parameters);
field_from_json(Obj,"submitted", submitted);
field_from_json(Obj,"started", started);
field_from_json(Obj,"completed", completed);
field_from_json(Obj,"requesterUsername", requesterUsername);
return true;
} catch (...) {
}
return false;
}
void DashBoardYearlyStats::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "year", year);
field_to_json(Obj, "activeCerts", activeCerts);
field_to_json(Obj, "revokedCerts", revokedCerts);
}
void Dashboard::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"snapshot", snapshot);
field_to_json(Obj,"numberOfIssuedCerts", numberOfIssuedCerts);
field_to_json(Obj,"numberOfRevokedCerts", numberOfRevokedCerts);
field_to_json(Obj,"activeCertsPerOrganization", activeCertsPerOrganization);
field_to_json(Obj,"revokedCertsPerOrganization", revokedCertsPerOrganization);
field_to_json(Obj,"numberOfRedirectors", numberOfRedirectors);
field_to_json(Obj,"deviceTypes", deviceTypes);
field_to_json(Obj,"monthlyNumberOfCerts", monthlyNumberOfCerts);
field_to_json(Obj,"monthlyNumberOfCertsPerOrgPerYear", monthlyNumberOfCertsPerOrgPerYear);
}
void Dashboard::reset() {
snapshot=0;
numberOfRevokedCerts = numberOfIssuedCerts = 0;
activeCertsPerOrganization.clear();
revokedCertsPerOrganization.clear();
numberOfRedirectors.clear();
deviceTypes.clear();
monthlyNumberOfCerts.clear();
monthlyNumberOfCertsPerOrgPerYear.clear();
}
}

View File

@@ -5,97 +5,119 @@
#pragma once
#include <string>
#include "framework/MicroService.h"
#include "framework/OpenWifiTypes.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi {
namespace OpenWifi::CertObjects {
namespace CertObjects {
struct CertificateEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string type;
std::string status;
std::string certificate;
std::string key;
std::string devid;
std::string cas;
std::string manufacturer;
std::string model;
std::string redirector;
std::string commonName;
std::string certificateId;
OpenWifi::Types::UUID_t batch;
uint64_t created = 0;
uint64_t modified = 0;
uint64_t revoked = 0;
uint64_t revokeCount = 0;
uint64_t synched = 0;
struct CertificateEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string type;
std::string status;
std::string certificate;
std::string key;
std::string devid;
std::string cas;
std::string manufacturer;
std::string model;
std::string redirector;
std::string commonName;
std::string certificateId;
OpenWifi::Types::UUID_t batch;
uint64_t created = 0;
uint64_t modified = 0;
uint64_t revoked = 0;
uint64_t revokeCount = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct EntityEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string defaultRedirector;
std::string apiKey;
std::string serverEnrollmentProfile;
std::string clientEnrollmentProfile;
std::string organization;
SecurityObjects::NoteInfoVec notes;
bool suspended=false;
bool deleted=false;
uint64_t created = 0 ;
uint64_t modified = 0 ;
struct EntityEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string defaultRedirector;
std::string apiKey;
std::string serverEnrollmentProfile;
std::string clientEnrollmentProfile;
std::string organization;
SecurityObjects::NoteInfoVec notes;
bool suspended=false;
bool deleted=false;
uint64_t created = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct BatchEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string manufacturer;
std::string model;
std::string redirector;
std::vector<std::string> commonNames;
std::vector<std::string> jobHistory;
SecurityObjects::NoteInfoVec notes;
uint64_t submitted = 0 ;
uint64_t started = 0 ;
uint64_t completed = 0 ;
uint64_t modified = 0 ;
struct BatchEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
std::string name;
std::string description;
std::string manufacturer;
std::string model;
std::string redirector;
std::vector<std::string> commonNames;
std::vector<std::string> jobHistory;
SecurityObjects::NoteInfoVec notes;
uint64_t submitted = 0 ;
uint64_t started = 0 ;
uint64_t completed = 0 ;
uint64_t modified = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct JobEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
OpenWifi::Types::UUID_t batch;
std::string command;
OpenWifi::Types::StringVec commonNames;
OpenWifi::Types::StringVec completedNames;
OpenWifi::Types::StringVec errorNames;
Types::StringPairVec parameters;
std::string status;
uint64_t submitted=0;
uint64_t started=0;
uint64_t completed=0;
std::string requesterUsername;
struct JobEntry {
OpenWifi::Types::UUID_t id;
OpenWifi::Types::UUID_t entity;
OpenWifi::Types::UUID_t creator;
OpenWifi::Types::UUID_t batch;
std::string command;
OpenWifi::Types::StringVec commonNames;
OpenWifi::Types::StringVec completedNames;
OpenWifi::Types::StringVec errorNames;
Types::StringPairVec parameters;
std::string status;
uint64_t submitted=0;
uint64_t started=0;
uint64_t completed=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DashBoardYearlyStats {
uint64_t year=0;
OpenWifi::Types::Counted3DMapSII activeCerts;
OpenWifi::Types::Counted3DMapSII revokedCerts;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
uint64_t snapshot=0;
uint64_t numberOfIssuedCerts=0;
uint64_t numberOfRevokedCerts=0;
OpenWifi::Types::CountedMap activeCertsPerOrganization;
OpenWifi::Types::CountedMap revokedCertsPerOrganization;
OpenWifi::Types::CountedMap numberOfRedirectors;
OpenWifi::Types::CountedMap deviceTypes;
OpenWifi::Types::CountedMap monthlyNumberOfCerts;
std::vector<DashBoardYearlyStats> monthlyNumberOfCertsPerOrgPerYear;
void to_json(Poco::JSON::Object &Obj) const;
void reset();
};
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
}

View File

@@ -3,7 +3,8 @@
//
#include "RESTAPI_FMSObjects.h"
#include "framework/MicroService.h"
#include "framework/RESTAPI_utils.h"
#include "framework/utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
@@ -233,7 +234,7 @@ namespace OpenWifi::FMSObjects {
UnknownFirmwares_.clear();
totalSecondsOld_.clear();
numberOfDevices = 0 ;
snapshot = OpenWifi::Now();
snapshot = Utils::Now();
}
bool DeviceReport::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {

View File

@@ -11,12 +11,13 @@
#include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE
#include "DeviceRegistry.h"
#include "AP_WS_Server.h"
#include "CapabilitiesCache.h"
#endif
#include "RESTAPI_GWobjects.h"
#include "framework/MicroService.h"
#include "framework/RESTAPI_utils.h"
#include "framework/utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
@@ -49,6 +50,10 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"locale", locale);
field_to_json(Obj,"restrictedDevice", restrictedDevice);
field_to_json(Obj,"pendingConfiguration", pendingConfiguration);
field_to_json(Obj,"pendingConfigurationCmd", pendingConfigurationCmd);
field_to_json(Obj,"restrictionDetails", restrictionDetails);
}
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
@@ -57,7 +62,7 @@ namespace OpenWifi::GWObjects {
#ifdef TIP_GATEWAY_SERVICE
ConnectionState ConState;
if (DeviceRegistry()->GetState(SerialNumber, ConState)) {
if (AP_WS_Server()->GetState(SerialNumber, ConState)) {
ConState.to_json(Obj);
} else {
field_to_json(Obj,"ipAddress", "");
@@ -69,6 +74,7 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE");
field_to_json(Obj,"associations_2G", (uint64_t) 0);
field_to_json(Obj,"associations_5G", (uint64_t) 0);
field_to_json(Obj,"associations_6G", (uint64_t) 0);
}
#endif
}
@@ -88,6 +94,10 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"subscriber", subscriber);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"locale", locale);
field_from_json(Obj,"restrictedDevice", restrictedDevice);
field_from_json(Obj,"pendingConfiguration", pendingConfiguration);
field_from_json(Obj,"pendingConfigurationCmd", pendingConfigurationCmd);
field_from_json(Obj,"restrictionDetails", restrictionDetails);
return true;
} catch (const Poco::Exception &E) {
}
@@ -198,11 +208,17 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"lastContact", LastContact);
field_to_json(Obj,"associations_2G", Associations_2G);
field_to_json(Obj,"associations_5G", Associations_5G);
field_to_json(Obj,"associations_6G", Associations_6G);
field_to_json(Obj,"webSocketClients", webSocketClients);
field_to_json(Obj,"websocketPackets", websocketPackets);
field_to_json(Obj,"kafkaClients", kafkaClients);
field_to_json(Obj,"kafkaPackets", kafkaPackets);
field_to_json(Obj,"locale", locale);
field_to_json(Obj,"started", started);
field_to_json(Obj,"sessionId", sessionId);
field_to_json(Obj,"connectionCompletionTime", connectionCompletionTime);
field_to_json(Obj,"totalConnectionTime", Utils::Now() - started);
field_to_json(Obj,"certificateExpiryDate", certificateExpiryDate);
switch(VerifiedCertificate) {
case NO_CERTIFICATE:
@@ -218,6 +234,23 @@ namespace OpenWifi::GWObjects {
}
}
void DeviceConnectionStatistics::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"averageConnectionTime", averageConnectionTime);
field_to_json(Obj,"connectedDevices", connectedDevices );
field_to_json(Obj,"connectingDevices", connectingDevices );
}
bool DeviceConnectionStatistics::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"averageConnectionTime", averageConnectionTime);
field_from_json(Obj,"connectedDevices", connectedDevices );
field_from_json(Obj,"connectingDevices", connectingDevices );
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber);
field_to_json(Obj,"server", Server);
@@ -264,7 +297,7 @@ namespace OpenWifi::GWObjects {
lastContact.clear();
associations.clear();
numberOfDevices = 0 ;
snapshot = OpenWifi::Now();
snapshot = Utils::Now();
}
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
@@ -276,9 +309,12 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"timeout",timeout);
field_to_json(Obj,"type",type);
field_to_json(Obj,"script",script);
field_to_json(Obj,"scriptId",scriptId);
field_to_json(Obj,"script",script);
field_to_json(Obj,"when",when);
field_to_json(Obj,"signature", signature);
field_to_json(Obj,"deferred", deferred);
field_to_json(Obj,"uri", uri);
}
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -289,11 +325,13 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"script",script);
field_from_json(Obj,"scriptId",scriptId);
field_from_json(Obj,"when",when);
field_from_json(Obj,"signature", signature);
field_from_json(Obj,"deferred", deferred);
field_from_json(Obj,"uri", uri);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void RadiusProxyPoolList::to_json(Poco::JSON::Object &Obj) const {
@@ -314,6 +352,8 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"description",description);
field_to_json(Obj,"authConfig",authConfig);
field_to_json(Obj,"acctConfig",acctConfig);
field_to_json(Obj,"coaConfig",coaConfig);
field_to_json(Obj,"useByDefault",useByDefault);
}
bool RadiusProxyPool::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -322,6 +362,8 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"description",description);
field_from_json(Obj,"authConfig",authConfig);
field_from_json(Obj,"acctConfig",acctConfig);
field_from_json(Obj,"coaConfig",coaConfig);
field_from_json(Obj,"useByDefault",useByDefault);
return true;
} catch (const Poco::Exception &E) {
}
@@ -329,7 +371,7 @@ namespace OpenWifi::GWObjects {
}
void RadiusProxyServerConfig::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"policy",strategy);
field_to_json(Obj,"strategy",strategy);
field_to_json(Obj,"monitor",monitor);
field_to_json(Obj,"monitorMethod",monitorMethod);
field_to_json(Obj,"methodParameters",methodParameters);
@@ -338,7 +380,7 @@ namespace OpenWifi::GWObjects {
bool RadiusProxyServerConfig::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"policy",strategy);
field_from_json(Obj,"strategy",strategy);
field_from_json(Obj,"monitor",monitor);
field_from_json(Obj,"monitorMethod",monitorMethod);
field_from_json(Obj,"methodParameters",methodParameters);
@@ -354,6 +396,17 @@ namespace OpenWifi::GWObjects {
field_to_json(Obj,"ip",ip);
field_to_json(Obj,"port",port);
field_to_json(Obj,"weight",weight);
field_to_json(Obj,"secret",secret);
field_to_json(Obj,"certificate",certificate);
field_to_json(Obj,"radsec",radsec);
field_to_json(Obj,"allowSelfSigned",allowSelfSigned);
field_to_json(Obj,"radsecPort",radsecPort);
field_to_json(Obj,"radsecSecret",radsecSecret);
field_to_json(Obj,"radsecCacerts",radsecCacerts);
field_to_json(Obj,"radsecCert",radsecCert);
field_to_json(Obj,"radsecKey",radsecKey);
field_to_json(Obj,"radsecRealms",radsecRealms);
field_to_json(Obj,"ignore",ignore);
}
bool RadiusProxyServerEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -362,10 +415,133 @@ namespace OpenWifi::GWObjects {
field_from_json(Obj,"ip",ip);
field_from_json(Obj,"port",port);
field_from_json(Obj,"weight",weight);
field_from_json(Obj,"secret",secret);
field_from_json(Obj,"certificate",certificate);
field_from_json(Obj,"radsec",radsec);
field_from_json(Obj,"allowSelfSigned",allowSelfSigned);
field_from_json(Obj,"radsecSecret",radsecSecret);
field_from_json(Obj,"radsecPort",radsecPort);
field_from_json(Obj,"radsecCacerts",radsecCacerts);
field_from_json(Obj,"radsecCert",radsecCert);
field_from_json(Obj,"radsecKey",radsecKey);
field_from_json(Obj,"radsecRealms",radsecRealms);
field_from_json(Obj,"ignore",ignore);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void ScriptEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"name", name);
field_to_json(Obj,"description", description);
field_to_json(Obj,"uri", uri);
field_to_json(Obj,"content", content);
field_to_json(Obj,"version", version);
field_to_json(Obj,"type", type);
field_to_json(Obj,"created", created);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"author", author);
field_to_json(Obj,"restricted", restricted);
field_to_json(Obj,"deferred", deferred);
field_to_json(Obj,"timeout", timeout);
field_to_json(Obj,"defaultUploadURI", defaultUploadURI);
}
bool ScriptEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"name", name);
field_from_json(Obj,"description", description);
field_from_json(Obj,"uri", uri);
field_from_json(Obj,"content", content);
field_from_json(Obj,"version", version);
field_from_json(Obj,"type", type);
field_from_json(Obj,"created", created);
field_from_json(Obj,"modified", modified);
field_from_json(Obj,"author", author);
field_from_json(Obj,"restricted", restricted);
field_from_json(Obj,"deferred", deferred);
field_from_json(Obj,"timeout", timeout);
field_from_json(Obj,"defaultUploadURI", defaultUploadURI);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void ScriptEntryList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"scripts",scripts);
}
bool ScriptEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"scripts",scripts);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void DeviceRestrictionsKeyInfo::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"vendor", vendor);
field_to_json(Obj,"algo", algo);
}
bool DeviceRestrictionsKeyInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"vendor", vendor);
field_from_json(Obj,"algo", algo);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void DeviceRestrictions::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"dfs", dfs);
field_to_json(Obj,"ssh", ssh);
field_to_json(Obj,"rtty", rtty);
field_to_json(Obj,"tty", tty);
field_to_json(Obj,"developer", developer);
field_to_json(Obj,"upgrade", upgrade);
field_to_json(Obj,"commands", commands);
field_to_json(Obj,"country", country);
field_to_json(Obj,"key_info", key_info);
}
bool DeviceRestrictions::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"dfs", dfs);
field_from_json(Obj,"ssh", ssh);
field_from_json(Obj,"rtty", rtty);
field_from_json(Obj,"tty", tty);
field_from_json(Obj,"developer", developer);
field_from_json(Obj,"upgrade", upgrade);
field_from_json(Obj,"commands", commands);
field_from_json(Obj,"country", country);
field_from_json(Obj,"key_info", key_info);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
bool DeviceRestrictionsKeyInfo::operator!=(const OpenWifi::GWObjects::DeviceRestrictionsKeyInfo &T) const {
return (T.algo!=algo) || (T.vendor!=vendor);
}
bool DeviceRestrictions::operator!=(const OpenWifi::GWObjects::DeviceRestrictions &T) const {
return ( (T.dfs!=dfs) ||
(T.rtty!=rtty) ||
(T.upgrade!=upgrade) ||
(T.commands != commands) ||
(T.developer != developer) ||
(T.ssh !=ssh) ||
(T.key_info != key_info) ||
(T.country != country) );
}
}

View File

@@ -28,19 +28,52 @@ namespace OpenWifi::GWObjects {
uint64_t TX = 0, RX = 0;
uint64_t Associations_2G=0;
uint64_t Associations_5G=0;
uint64_t Associations_6G=0;
bool Connected = false;
uint64_t LastContact=0;
std::string Firmware;
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
std::string Compatible;
uint64_t kafkaClients=0;
uint64_t webSocketClients=0;
uint64_t kafkaPackets=0;
uint64_t websocketPackets=0;
std::string locale;
std::string Compatible;
uint64_t kafkaClients=0;
uint64_t webSocketClients=0;
uint64_t kafkaPackets=0;
uint64_t websocketPackets=0;
std::string locale;
uint64_t started=0;
uint64_t sessionId=0;
double connectionCompletionTime=0.0;
std::uint64_t certificateExpiryDate=0;
void to_json(Poco::JSON::Object &Obj) const;
};
struct DeviceRestrictionsKeyInfo {
std::string vendor;
std::string algo;
bool operator !=(const DeviceRestrictionsKeyInfo &b) const;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceRestrictions {
bool dfs = false;
bool ssh = false;
bool rtty = false;
bool tty = false;
bool developer = false;
bool upgrade = false;
bool commands = false;
std::vector<std::string> country;
DeviceRestrictionsKeyInfo key_info;
bool operator !=(const DeviceRestrictions &D) const;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Device {
std::string SerialNumber;
std::string DeviceType;
@@ -64,6 +97,10 @@ namespace OpenWifi::GWObjects {
std::string entity;
uint64_t modified=0;
std::string locale;
bool restrictedDevice=false;
std::string pendingConfiguration;
std::string pendingConfigurationCmd;
DeviceRestrictions restrictionDetails;
void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const;
@@ -71,6 +108,15 @@ namespace OpenWifi::GWObjects {
void Print() const;
};
struct DeviceConnectionStatistics {
std::uint64_t connectedDevices = 0;
std::uint64_t averageConnectionTime = 0;
std::uint64_t connectingDevices = 0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct Statistics {
std::string SerialNumber;
uint64_t UUID = 0 ;
@@ -200,13 +246,44 @@ namespace OpenWifi::GWObjects {
void to_json(Poco::JSON::Object &Obj) const;
};
struct ScriptEntry {
std::string id;
std::string name;
std::string description;
std::string uri;
std::string content;
std::string version;
std::string type;
std::uint64_t created;
std::uint64_t modified;
std::string author;
Types::StringVec restricted;
bool deferred=false;
std::uint64_t timeout=30;
std::string defaultUploadURI;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ScriptEntryList {
std::vector<ScriptEntry> scripts;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ScriptRequest {
uint64_t timeout=30;
std::string serialNumber;
uint64_t timeout=30;
std::string type;
std::string script;
std::string scriptId;
uint64_t when=0;
std::uint64_t when;
std::string signature;
bool deferred;
std::string uri;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
@@ -216,6 +293,17 @@ namespace OpenWifi::GWObjects {
std::string ip;
uint16_t port=0;
uint64_t weight=0;
std::string secret;
std::string certificate;
bool radsec=false;
bool allowSelfSigned=false;
uint16_t radsecPort=2083;
std::string radsecSecret;
std::string radsecKey;
std::string radsecCert;
std::vector<std::string> radsecCacerts;
std::vector<std::string> radsecRealms;
bool ignore=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -237,6 +325,8 @@ namespace OpenWifi::GWObjects {
std::string description;
RadiusProxyServerConfig authConfig;
RadiusProxyServerConfig acctConfig;
RadiusProxyServerConfig coaConfig;
bool useByDefault=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -248,4 +338,5 @@ namespace OpenWifi::GWObjects {
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}

View File

@@ -0,0 +1,110 @@
//
// Created by stephane bourque on 2021-08-31.
//
#include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
using OpenWifi::RESTAPI_utils::EmbedDocument;
#include "RESTAPI_OWLSobjects.h"
// SIM -> 0x53/0x073, 0x49/0x69, 0x4d/0x6d
namespace OpenWifi::OWLSObjects {
void SimulationDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"name", name);
field_to_json(Obj,"gateway", gateway);
field_to_json(Obj,"certificate", certificate);
field_to_json(Obj,"key", key);
field_to_json(Obj,"macPrefix", macPrefix);
field_to_json(Obj,"deviceType", deviceType);
field_to_json(Obj,"devices", devices);
field_to_json(Obj,"healthCheckInterval", healthCheckInterval);
field_to_json(Obj,"stateInterval", stateInterval);
field_to_json(Obj,"minAssociations", minAssociations);
field_to_json(Obj,"maxAssociations", maxAssociations);
field_to_json(Obj,"minClients", minClients);
field_to_json(Obj,"maxClients", maxClients);
field_to_json(Obj,"simulationLength", simulationLength);
field_to_json(Obj,"threads", threads);
field_to_json(Obj,"clientInterval", clientInterval);
field_to_json(Obj,"keepAlive", keepAlive);
field_to_json(Obj,"reconnectInterval", reconnectInterval);
field_to_json(Obj,"concurrentDevices", concurrentDevices);
}
bool SimulationDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"id", id);
field_from_json(Obj,"name", name);
field_from_json(Obj,"gateway", gateway);
field_from_json(Obj,"certificate", certificate);
field_from_json(Obj,"key", key);
field_from_json(Obj,"macPrefix", macPrefix);
field_from_json(Obj,"deviceType", deviceType);
field_from_json(Obj,"devices", devices);
field_from_json(Obj,"healthCheckInterval", healthCheckInterval);
field_from_json(Obj,"stateInterval", stateInterval);
field_from_json(Obj,"minAssociations", minAssociations);
field_from_json(Obj,"maxAssociations", maxAssociations);
field_from_json(Obj,"minClients", minClients);
field_from_json(Obj,"maxClients", maxClients);
field_from_json(Obj,"simulationLength", simulationLength);
field_from_json(Obj,"threads", threads);
field_from_json(Obj,"clientInterval", clientInterval);
field_from_json(Obj,"keepAlive", keepAlive);
field_from_json(Obj,"reconnectInterval", reconnectInterval);
field_from_json(Obj,"concurrentDevices", concurrentDevices);
return true;
} catch(...) {
}
return false;
}
void SimulationDetailsList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"list", list);
}
bool SimulationDetailsList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"list", list);
return true;
} catch(...) {
}
return false;
}
void SimulationStatus::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"id", id);
field_to_json(Obj,"simulationId", simulationId);
field_to_json(Obj,"state", state);
field_to_json(Obj,"tx", tx);
field_to_json(Obj,"rx", rx);
field_to_json(Obj,"msgsTx", msgsTx);
field_to_json(Obj,"msgsRx", msgsRx);
field_to_json(Obj,"liveDevices", liveDevices);
field_to_json(Obj,"timeToFullDevices", timeToFullDevices);
field_to_json(Obj,"startTime", startTime);
field_to_json(Obj,"endTime", endTime);
field_to_json(Obj,"errorDevices", errorDevices);
field_to_json(Obj,"owner", owner);
}
void Dashboard::to_json([[maybe_unused]] Poco::JSON::Object &Obj) const {
}
bool Dashboard::from_json([[maybe_unused]] const Poco::JSON::Object::Ptr &Obj) {
return true;
}
void Dashboard::reset() {
}
}

View File

@@ -0,0 +1,77 @@
//
// Created by stephane bourque on 2021-08-31.
//
#ifndef UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
#define UCENTRALSIM_RESTAPI_OWLSOBJECTS_H
#include <vector>
#include "Poco/JSON/Object.h"
namespace OpenWifi::OWLSObjects {
struct SimulationDetails {
std::string id;
std::string name;
std::string gateway;
std::string certificate;
std::string key;
std::string macPrefix;
std::string deviceType;
uint64_t devices = 5;
uint64_t healthCheckInterval = 60;
uint64_t stateInterval = 60 ;
uint64_t minAssociations = 1;
uint64_t maxAssociations = 3;
uint64_t minClients = 1 ;
uint64_t maxClients = 3;
uint64_t simulationLength = 60 * 60;
uint64_t threads = 16;
uint64_t clientInterval = 1;
uint64_t keepAlive = 300;
uint64_t reconnectInterval = 30 ;
uint64_t concurrentDevices = 5;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationDetailsList {
std::vector<SimulationDetails> list;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct SimulationStatus {
std::string id;
std::string simulationId;
std::string state;
uint64_t tx;
uint64_t rx;
uint64_t msgsTx;
uint64_t msgsRx;
uint64_t liveDevices;
uint64_t timeToFullDevices;
uint64_t startTime;
uint64_t endTime;
uint64_t errorDevices;
std::string owner;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
int O;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void reset();
};
}
#endif //UCENTRALSIM_RESTAPI_OWLSOBJECTS_H

View File

@@ -8,7 +8,9 @@
#include "RESTAPI_ProvObjects.h"
#include "framework/MicroService.h"
#include "framework/RESTAPI_utils.h"
#include "framework/MicroServiceFuncs.h"
#include "framework/utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
@@ -600,6 +602,7 @@ namespace OpenWifi::ProvObjects {
field_to_json( Obj, "devClass",devClass);
field_to_json( Obj, "locale",locale);
field_to_json( Obj, "realMacAddress",realMacAddress);
field_to_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
}
bool InventoryTag::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -621,6 +624,7 @@ namespace OpenWifi::ProvObjects {
field_from_json( Obj,"devClass",devClass);
field_from_json( Obj,"locale",locale);
field_from_json( Obj,"realMacAddress",realMacAddress);
field_from_json( Obj, "doNotAllowOverrides",doNotAllowOverrides);
return true;
} catch(...) {
@@ -1091,7 +1095,7 @@ namespace OpenWifi::ProvObjects {
}
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = OpenWifi::Now();
uint64_t Now = Utils::Now();
if(O->has("name"))
I.name = O->get("name").toString();
@@ -1112,7 +1116,7 @@ namespace OpenWifi::ProvObjects {
}
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I) {
uint64_t Now = OpenWifi::Now();
uint64_t Now = Utils::Now();
if(O->has("name"))
I.name = O->get("name").toString();
@@ -1130,14 +1134,14 @@ namespace OpenWifi::ProvObjects {
}
I.notes = N;
I.modified = I.created = Now;
I.id = MicroService::CreateUUID();
I.id = MicroServiceCreateUUID();
return true;
}
bool CreateObjectInfo([[maybe_unused]] const SecurityObjects::UserInfo &U, ObjectInfo &I) {
I.modified = I.created = OpenWifi::Now();
I.id = MicroService::CreateUUID();
I.modified = I.created = Utils::Now();
I.id = MicroServiceCreateUUID();
return true;
}
@@ -1159,5 +1163,82 @@ namespace OpenWifi::ProvObjects {
return false;
}
void RRMAlgorithmDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"name",name);
field_to_json(Obj,"parameters",parameters);
}
bool RRMAlgorithmDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"name",name);
field_from_json(Obj,"parameters",parameters);
return true;
} catch(...) {
}
return false;
}
void RRMDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"vendor",vendor);
field_to_json(Obj,"schedule",schedule);
field_to_json(Obj,"algorithms",algorithms);
}
bool RRMDetails::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"vendor",vendor);
field_from_json(Obj,"schedule",schedule);
field_from_json(Obj,"algorithms",algorithms);
return true;
} catch(...) {
}
return false;
}
void ConfigurationOverride::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"source",source);
field_to_json(Obj,"reason",reason);
field_to_json(Obj,"parameterName",parameterName);
field_to_json(Obj,"parameterType",parameterType);
field_to_json(Obj,"parameterValue",parameterValue);
field_to_json(Obj,"modified",modified);
}
bool ConfigurationOverride::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"source",source);
field_from_json(Obj,"reason",reason);
field_from_json(Obj,"parameterName",parameterName);
field_from_json(Obj,"parameterType",parameterType);
field_from_json(Obj,"parameterValue",parameterValue);
field_from_json(Obj,"modified",modified);
return true;
} catch(...) {
}
return false;
}
void ConfigurationOverrideList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"managementPolicy",managementPolicy);
field_to_json(Obj,"overrides",overrides);
}
bool ConfigurationOverrideList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"managementPolicy",managementPolicy);
field_from_json(Obj,"overrides",overrides);
return true;
} catch(...) {
}
return false;
}
}

View File

@@ -8,8 +8,7 @@
#pragma once
#include <string>
#include "RESTAPI_SecurityObjects.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
namespace OpenWifi::ProvObjects {
@@ -62,6 +61,21 @@ namespace OpenWifi::ProvObjects {
};
typedef std::vector<ManagementPolicy> ManagementPolicyVec;
struct RRMAlgorithmDetails {
std::string name;
std::string parameters;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RRMDetails {
std::string vendor;
std::string schedule;
std::vector<RRMAlgorithmDetails> algorithms;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct DeviceRules {
std::string rcOnly{"inherit"};
std::string rrm{"inherit"};
@@ -414,6 +428,7 @@ namespace OpenWifi::ProvObjects {
std::string devClass;
std::string locale;
std::string realMacAddress;
bool doNotAllowOverrides=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -679,6 +694,27 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ConfigurationOverride {
std::string source;
std::string reason;
std::string parameterName;
std::string parameterType;
std::string parameterValue;
std::uint64_t modified;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ConfigurationOverrideList {
std::string serialNumber;
Types::UUID_t managementPolicy;
std::vector<ConfigurationOverride> overrides;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
bool CreateObjectInfo(const SecurityObjects::UserInfo &U, ObjectInfo &I);

View File

@@ -9,7 +9,7 @@
#include "Poco/JSON/Parser.h"
#include "Poco/JSON/Stringifier.h"
#include "framework/MicroService.h"
#include "framework/RESTAPI_utils.h"
#include "RESTAPI_SecurityObjects.h"
using OpenWifi::RESTAPI_utils::field_to_json;
@@ -433,7 +433,7 @@ namespace OpenWifi::SecurityObjects {
SecurityObjects::NoteInfoVec NIV;
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(Obj->get("notes").toString());
for(auto const &i:NIV) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UInfo.email, .note=i.note};
Notes.push_back(ii);
}
}
@@ -446,7 +446,7 @@ namespace OpenWifi::SecurityObjects {
bool MergeNotes(const NoteInfoVec & NewNotes, const UserInfo &UInfo, NoteInfoVec & ExistingNotes) {
for(auto const &i:NewNotes) {
SecurityObjects::NoteInfo ii{.created=(uint64_t)OpenWifi::Now(), .createdBy=UInfo.email, .note=i.note};
SecurityObjects::NoteInfo ii{.created=(uint64_t)Utils::Now(), .createdBy=UInfo.email, .note=i.note};
ExistingNotes.push_back(ii);
}
return true;
@@ -619,5 +619,80 @@ namespace OpenWifi::SecurityObjects {
field_to_json(Obj,"login",login);
field_to_json(Obj,"logout",logout);
}
void ApiKeyAccessRight::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "service", service);
field_to_json(Obj, "access", access);
}
bool ApiKeyAccessRight::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "service", service);
field_from_json(Obj, "access", access);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void ApiKeyAccessRightList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "acls", acls);
}
bool ApiKeyAccessRightList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "acls", acls);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void ApiKeyEntry::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "id", id);
field_to_json(Obj, "userUuid", userUuid);
field_to_json(Obj, "name", name);
field_to_json(Obj, "apiKey", apiKey);
field_to_json(Obj, "salt", salt);
field_to_json(Obj, "description", description);
field_to_json(Obj, "expiresOn", expiresOn);
field_to_json(Obj, "rights", rights);
field_to_json(Obj, "lastUse", lastUse);
}
bool ApiKeyEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "id", id);
field_from_json(Obj, "userUuid", userUuid);
field_from_json(Obj, "name", name);
field_from_json(Obj, "apiKey", apiKey);
field_from_json(Obj, "salt", salt);
field_from_json(Obj, "description", description);
field_from_json(Obj, "expiresOn", expiresOn);
field_from_json(Obj, "rights", rights);
field_from_json(Obj, "lastUse", lastUse);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
void ApiKeyEntryList::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj, "apiKeys", apiKeys);
}
bool ApiKeyEntryList::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj, "apiKeys", apiKeys);
return true;
} catch(...) {
std::cout << "Cannot parse: Token" << std::endl;
}
return false;
}
}

View File

@@ -9,10 +9,12 @@
#pragma once
#include <string>
#include <type_traits>
#include "framework/OpenWifiTypes.h"
#include "Poco/JSON/Object.h"
#include "Poco/Data/LOB.h"
#include "Poco/Data/LOBStream.h"
#include "framework/utils.h"
namespace OpenWifi {
uint64_t Now();
@@ -27,8 +29,13 @@ namespace OpenWifi {
bool Delete_ = true;
bool PortalLogin_ = true;
AclTemplate() noexcept = default;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj); };
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
static_assert( std::is_nothrow_move_constructible_v<AclTemplate> );
struct WebToken {
std::string access_token_;
@@ -56,7 +63,7 @@ namespace OpenWifi {
std::string UserTypeToString(USER_ROLE U);
struct NoteInfo {
uint64_t created=0; // = OpenWifi::Now();
uint64_t created=0; // = Utils::Now();
std::string createdBy;
std::string note;
@@ -95,7 +102,7 @@ namespace OpenWifi {
std::string uuid;
std::string question;
std::string method;
uint64_t created = OpenWifi::Now();
uint64_t created = Utils::Now();
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -245,7 +252,8 @@ namespace OpenWifi {
VERIFY_EMAIL,
SUB_FORGOT_PASSWORD,
SUB_VERIFY_EMAIL,
SUB_SIGNUP
SUB_SIGNUP,
EMAIL_INVITATION
};
struct ActionLink {
@@ -257,7 +265,7 @@ namespace OpenWifi {
std::string locale;
std::string message;
uint64_t sent=0;
uint64_t created=OpenWifi::Now();
uint64_t created=Utils::Now();
uint64_t expires=0;
uint64_t completed=0;
uint64_t canceled=0;
@@ -317,5 +325,44 @@ namespace OpenWifi {
void to_json(Poco::JSON::Object &Obj) const;
};
struct ApiKeyAccessRight {
std::string service;
std::string access;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ApiKeyAccessRightList {
std::vector<ApiKeyAccessRight> acls;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ApiKeyEntry {
Types::UUID_t id;
Types::UUID_t userUuid;
std::string name;
std::string description;
std::string apiKey;
std::string salt;
std::uint64_t created;
std::uint64_t expiresOn=0;
ApiKeyAccessRightList rights;
std::uint64_t lastUse=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct ApiKeyEntryList {
std::vector<ApiKeyEntry> apiKeys;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}
}

View File

@@ -3,12 +3,11 @@
//
#include "RESTAPI_SubObjects.h"
#include "framework/MicroService.h"
#include "framework/RESTAPI_utils.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
namespace OpenWifi::SubObjects {
void HomeDeviceMode::to_json(Poco::JSON::Object &Obj) const {

View File

@@ -5,6 +5,8 @@
#include "StateReceiver.h"
#include "VenueWatcher.h"
#include "fmt/core.h"
#include "framework/KafkaTopics.h"
#include "framework/KafkaManager.h"
namespace OpenWifi {
@@ -25,6 +27,7 @@ namespace OpenWifi {
void StateReceiver::run() {
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("dev-state");
while(Note && Running_) {
auto Msg = dynamic_cast<StateMessage *>(Note.get());
if(Msg!= nullptr) {
@@ -58,7 +61,7 @@ namespace OpenWifi {
void StateReceiver::StateReceived( const std::string & Key, const std::string & Payload) {
std::lock_guard G(Mutex_);
Logger().information(fmt::format("Device({}): State message.", Key));
poco_debug(Logger(),fmt::format("Device({}): State message.", Key));
Queue_.enqueueNotification( new StateMessage(Key,Payload));
}

View File

@@ -3,7 +3,9 @@
//
#pragma once
#include "framework/MicroService.h"
#include "framework/SubSystemServer.h"
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
namespace OpenWifi {
class StateMessage : public Poco::Notification {

View File

@@ -8,10 +8,14 @@
#include "StorageService.h"
#include "RESTObjects/RESTAPI_ProvObjects.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
#include "framework/utils.h"
namespace OpenWifi {
int Storage::Start() {
poco_notice(Logger(),"Starting...");
std::lock_guard Guard(Mutex_);
StorageClass::Start();
@@ -24,7 +28,7 @@ namespace OpenWifi {
BoardsDB_->Create();
WifiClientHistoryDB_->Create();
PeriodicCleanup_ = MicroService::instance().ConfigGetInt("storage.cleanup.interval", 6*60*60);
PeriodicCleanup_ = MicroServiceConfigGetInt("storage.cleanup.interval", 6*60*60);
if(PeriodicCleanup_<1*60*60)
PeriodicCleanup_ = 1*60*60;
@@ -43,14 +47,14 @@ namespace OpenWifi {
uint64_t start = 0 ;
bool done = false;
const uint64_t batch=100;
Logger().information("Starting cleanup of TimePoint Database");
poco_information(Logger(),"Starting cleanup of TimePoint Database");
while(!done) {
if(!BoardsDB().GetRecords(start,batch,BoardList)) {
for(const auto &board:BoardList) {
for(const auto &venue:board.venueList) {
auto now = OpenWifi::Now();
auto now = Utils::Now();
auto lower_bound = now - venue.retention;
Logger().information(fmt::format("Removing old records for board '{}'",board.info.name));
poco_information(Logger(),fmt::format("Removing old records for board '{}'",board.info.name));
BoardsDB().DeleteRecords(fmt::format(" boardId='{}' and timestamp<{}", board.info.id, lower_bound));
}
}
@@ -58,14 +62,15 @@ namespace OpenWifi {
done = (BoardList.size() < batch);
}
auto MaxDays = MicroService::instance().ConfigGetInt("wificlient.age.limit",14);
auto LowerDate = OpenWifi::Now() - (MaxDays*60*60*24);
Logger().information(fmt::format("Removing WiFi Clients history older than {} days.", MaxDays));
auto MaxDays = MicroServiceConfigGetInt("wificlient.age.limit",14);
auto LowerDate = Utils::Now() - (MaxDays*60*60*24);
poco_information(Logger(),fmt::format("Removing WiFi Clients history older than {} days.", MaxDays));
StorageService()->WifiClientHistoryDB().DeleteRecords(fmt::format(" timestamp<{} ", LowerDate));
Logger().information(fmt::format("Done cleanup of databases. Next run in {} seconds.", PeriodicCleanup_));
poco_information(Logger(),fmt::format("Done cleanup of databases. Next run in {} seconds.", PeriodicCleanup_));
}
void Storage::run() {
Utils::SetThreadName("strg-updtr");
Running_ = true ;
bool FirstRun=true;
long Retry = 2000;
@@ -80,11 +85,12 @@ namespace OpenWifi {
}
void Storage::Stop() {
poco_notice(Logger(),"Stopping...");
Running_=false;
Timer_.stop();
Updater_.wakeUp();
Updater_.join();
Logger().notice("Stopping.");
poco_notice(Logger(),"Stopped...");
}
}

View File

@@ -8,7 +8,6 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/StorageClass.h"
#include "storage/storage_boards.h"
#include "storage/storage_timepoints.h"

View File

@@ -7,41 +7,63 @@
#include "StorageService.h"
#include "sdks/SDK_prov.h"
#include "fmt/core.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
int VenueCoordinator::Start() {
poco_notice(Logger(),"Starting...");
GetBoardList();
Worker_.start(*this);
ReconcileTimerCallback_ = std::make_unique<Poco::TimerCallback<VenueCoordinator>>(*this,&VenueCoordinator::onReconcileTimer);
ReconcileTimerTimer_.setStartInterval( 3 * 60 * 1000 );
ReconcileTimerTimer_.setPeriodicInterval(3 * 60 * 1000); // 1 hours
ReconcileTimerTimer_.start(*ReconcileTimerCallback_, MicroServiceTimerPool());
return 0;
}
void VenueCoordinator::onReconcileTimer([[maybe_unused]] Poco::Timer &timer) {
std::lock_guard G(Mutex_);
Utils::SetThreadName("brd-refresh");
poco_information(Logger(),"Starting to reconcile board information.");
for(const auto &[board_id, watcher]:Watchers_) {
poco_information(Logger(),fmt::format("Updating: {}", board_id));
UpdateBoard(board_id);
}
poco_information(Logger(),"Finished reconciling board information.");
}
void VenueCoordinator::GetBoardList() {
BoardsToWatch_.clear();
auto F = [&](const AnalyticsObjects::BoardInfo &B) ->bool {
BoardsToWatch_.insert(B);
// Logger().information(fmt::format("Starting watch for {}.", B.info.name));
// poco_information(Logger(),fmt::format("Starting watch for {}.", B.info.name));
return true;
};
StorageService()->BoardsDB().Iterate(F);
}
void VenueCoordinator::Stop() {
poco_notice(Logger(),"Stopping...");
Running_=false;
Worker_.wakeUp();
Worker_.wakeUp();
Worker_.join();
poco_notice(Logger(),"Stopped...");
}
void VenueCoordinator::run() {
Utils::SetThreadName("venue-coord");
Running_=true;
while(Running_) {
Poco::Thread::trySleep(2000);
Poco::Thread::trySleep(20000);
if(!Running_)
break;
std::lock_guard G(Mutex_);
GetBoardList();
if(!BoardsToWatch_.empty()) {
@@ -96,7 +118,7 @@ namespace OpenWifi {
ExistingBoards_[B.info.id] = Devices;
Watchers_[B.info.id] = std::make_shared<VenueWatcher>(B.info.id, B.venueList[0].id, Logger(), Devices);
Watchers_[B.info.id]->Start();
Logger().information(fmt::format("Started board {} for venue {}", B.info.name,B.venueList[0].id ));
poco_information(Logger(),fmt::format("Started board {} for venue {}", B.info.name,B.venueList[0].id ));
return true;
}
@@ -105,7 +127,7 @@ namespace OpenWifi {
return false;
}
Logger().information(fmt::format("Could not start board {}",B.info.name));
poco_information(Logger(),fmt::format("Could not start board {}",B.info.name));
return false;
}
@@ -119,7 +141,7 @@ namespace OpenWifi {
}
}
void VenueCoordinator::ModifyBoard(const std::string &id) {
void VenueCoordinator::UpdateBoard(const std::string &id) {
AnalyticsObjects::BoardInfo B;
if(StorageService()->BoardsDB().GetRecord("id",id,B)) {
std::vector<uint64_t> Devices;
@@ -130,15 +152,15 @@ namespace OpenWifi {
if(it!=ExistingBoards_.end()) {
if(it->second!=Devices) {
auto it2 = Watchers_.find(id);
if(it2!=Watchers_.end())
if(it2!=Watchers_.end()) {
it2->second->ModifySerialNumbers(Devices);
}
ExistingBoards_[id] = Devices;
Logger().information(fmt::format("Modified board {}",B.info.name));
poco_information(Logger(),fmt::format("Modified board {}",B.info.name));
} else {
Logger().information(fmt::format("No device changes in board {}",B.info.name));
poco_information(Logger(),fmt::format("No device changes in board {}",B.info.name));
}
}
Logger().information(fmt::format("Modified board {}",B.info.name));
return;
}
@@ -147,7 +169,7 @@ namespace OpenWifi {
return;
}
Logger().information(fmt::format("Could not modify board {}",B.info.name));
poco_information(Logger(),fmt::format("Could not modify board {}",B.info.name));
}
}
@@ -163,7 +185,7 @@ namespace OpenWifi {
if(StorageService()->BoardsDB().GetRecord("id",id,B))
BoardsToWatch_.insert(B);
else
Logger().information(fmt::format("Board {} does not seem to exist",id));
poco_information(Logger(),fmt::format("Board {} does not seem to exist",id));
}
void VenueCoordinator::GetDevices(std::string &id, AnalyticsObjects::DeviceInfoList &DIL) {

View File

@@ -3,9 +3,12 @@
//
#pragma once
#include "framework/MicroService.h"
#include "framework/SubSystemServer.h"
#include "VenueWatcher.h"
#include "Poco/Timer.h"
namespace OpenWifi {
class VenueCoordinator : public SubSystemServer, Poco::Runnable {
@@ -21,7 +24,7 @@ namespace OpenWifi {
void run() override;
void StopBoard(const std::string &id);
void ModifyBoard(const std::string &id);
void UpdateBoard(const std::string &id);
void AddBoard(const std::string &id);
bool GetDevicesForBoard(const AnalyticsObjects::BoardInfo &B, std::vector<uint64_t> & Devices, bool & VenueExists);
@@ -30,13 +33,17 @@ namespace OpenWifi {
bool Watching(const std::string &id);
void RetireBoard(const AnalyticsObjects::BoardInfo &B);
private:
Poco::Thread Worker_;
std::atomic_bool Running_=false;
std::set<AnalyticsObjects::BoardInfo> BoardsToWatch_;
std::map<std::string,std::shared_ptr<VenueWatcher>> Watchers_;
void onReconcileTimer(Poco::Timer & timer);
std::map<std::string,std::vector<uint64_t>> ExistingBoards_;
private:
Poco::Thread Worker_;
std::atomic_bool Running_=false;
std::set<AnalyticsObjects::BoardInfo> BoardsToWatch_;
std::map<std::string,std::shared_ptr<VenueWatcher>> Watchers_;
std::unique_ptr<Poco::TimerCallback<VenueCoordinator>> ReconcileTimerCallback_;
Poco::Timer ReconcileTimerTimer_;
std::map<std::string,std::vector<uint64_t>> ExistingBoards_;
VenueCoordinator() noexcept:
SubSystemServer("VenueCoordinator", "VENUE-COORD", "venue.coordinator")

View File

@@ -10,6 +10,7 @@
namespace OpenWifi {
void VenueWatcher::Start() {
poco_notice(Logger(),"Starting...");
for(const auto &mac:SerialNumbers_) {
auto ap = std::make_shared<AP>(mac, venue_id_, boardId_, Logger());
APs_[mac ] = ap;
@@ -24,6 +25,7 @@ namespace OpenWifi {
}
void VenueWatcher::Stop() {
poco_notice(Logger(),"Stopping...");
Running_ = false;
Queue_.wakeUpAll();
Worker_.join();
@@ -31,9 +33,11 @@ namespace OpenWifi {
StateReceiver()->DeRegister(i,this);
DeviceStatusReceiver()->DeRegister(this);
HealthReceiver()->DeRegister(this);
poco_notice(Logger(),"Stopped...");
}
void VenueWatcher::run() {
Utils::SetThreadName("venue-watch");
Running_ = true;
Poco::AutoPtr<Poco::Notification> Msg(Queue_.waitDequeueNotification());
while(Msg && Running_) {

View File

@@ -4,9 +4,11 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/SubSystemServer.h"
#include "APStats.h"
#include "RESTObjects/RESTAPI_AnalyticsObjects.h"
#include "Poco/NotificationQueue.h"
#include "Poco/Notification.h"
namespace OpenWifi {
@@ -69,9 +71,11 @@ namespace OpenWifi {
void GetDevices(std::vector<AnalyticsObjects::DeviceInfo> & DI);
void GetBandwidth(uint64_t start, uint64_t end, uint64_t interval , AnalyticsObjects::BandwidthAnalysis & BW);
inline std::string Venue() const {
return venue_id_;
}
private:
std::recursive_mutex Mutex_;
std::mutex Mutex_;
std::string boardId_;
std::string venue_id_;
Poco::NotificationQueue Queue_;

View File

@@ -2,14 +2,17 @@
// Created by stephane bourque on 2021-08-11.
//
#include "WifiClientCache.h"
#include <mutex>
#include "WifiClientCache.h"
#include "StorageService.h"
#include "fmt/format.h"
#include "framework/utils.h"
namespace OpenWifi {
int WifiClientCache::Start() {
poco_notice(Logger(),"Starting...");
TimerCallback_ = std::make_unique<Poco::TimerCallback<WifiClientCache>>(*this,&WifiClientCache::onTimer);
Timer_.setStartInterval( 30 * 1000); // first run in 20 seconds
Timer_.setPeriodicInterval( 60 * 60 * 1000); // 1 hours
@@ -18,7 +21,9 @@ namespace OpenWifi {
}
void WifiClientCache::Stop() {
poco_notice(Logger(),"Stopping...");
Timer_.stop();
poco_notice(Logger(),"Stopped...");
}
void WifiClientCache::onTimer([[maybe_unused]] Poco::Timer & timer) {
@@ -124,32 +129,36 @@ namespace OpenWifi {
}
}
void WifiClientCache::FindNumbers(const std::string &venue_id, const std::string &S, uint HowMany, std::vector<uint64_t> &A) {
void WifiClientCache::FindNumbers(const std::string &venueId, const std::string &SerialNumber, std::uint64_t StartingOffset, std::uint64_t HowMany, std::vector<uint64_t> &A) {
std::lock_guard G(Mutex_);
A.clear();
auto VenueIt = Cache_.find(venue_id);
auto VenueIt = Cache_.find(venueId);
if(VenueIt==Cache_.end())
return;
if(S.empty()) {
if(SerialNumber.empty()) {
auto Start = VenueIt->second.SNs_.begin();
std::uint64_t Offset=0;
while(HowMany && Start!=VenueIt->second.SNs_.end()) {
A.push_back(*Start);
if(Offset>=StartingOffset) {
A.push_back(*Start);
HowMany--;
}
Start++;
HowMany--;
Offset++;
}
return;
}
if (S[0] == '*') {
if (SerialNumber[0] == '*') {
std::string Reversed;
std::copy(rbegin(S), rend(S)-1, std::back_inserter(Reversed));
std::copy(rbegin(SerialNumber), rend(SerialNumber)-1, std::back_inserter(Reversed));
if(Reversed.empty())
return;
return ReturnNumbers(Reversed, HowMany, VenueIt->second.Reverse_SNs_, A, true);
} else {
return ReturnNumbers(S, HowMany, VenueIt->second.SNs_, A, false);
return ReturnNumbers(SerialNumber, HowMany, VenueIt->second.SNs_, A, false);
}
}
}

View File

@@ -4,7 +4,7 @@
#pragma once
#include "framework/MicroService.h"
#include "framework/SubSystemServer.h"
#include "Poco/Timer.h"
namespace OpenWifi {
@@ -20,7 +20,7 @@ namespace OpenWifi {
void Stop() override;
void AddSerialNumber(const std::string &venueId, const std::string &SerialNumber);
void DeleteSerialNumber(const std::string &venueId, const std::string &SerialNumber);
void FindNumbers(const std::string &venueId, const std::string &SerialNumber, uint HowMany, std::vector<uint64_t> &A);
void FindNumbers(const std::string &venueId, const std::string &SerialNumber, std::uint64_t start, std::uint64_t HowMany, std::vector<uint64_t> &A);
inline bool NumberExists(const std::string &venueId, uint64_t SerialNumber) {
std::lock_guard G(Mutex_);
auto It = Cache_.find(venueId);

View File

@@ -0,0 +1,77 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "ALBserver.h"
#include "framework/utils.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
namespace OpenWifi {
void ALBRequestHandler::handleRequest([[maybe_unused]] Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) {
Utils::SetThreadName("alb-request");
try {
if((id_ % 100) == 0) {
Logger_.debug(fmt::format("ALB-REQUEST({}): ALB Request {}.", Request.clientAddress().toString(), id_));
}
Response.setChunkedTransferEncoding(true);
Response.setContentType("text/html");
Response.setDate(Poco::Timestamp());
Response.setStatus(Poco::Net::HTTPResponse::HTTP_OK);
Response.setKeepAlive(true);
Response.set("Connection", "keep-alive");
Response.setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
std::ostream &Answer = Response.send();
Answer << "process Alive and kicking!";
} catch (...) {
}
}
ALBRequestHandlerFactory::ALBRequestHandlerFactory(Poco::Logger & L):
Logger_(L) {
}
ALBRequestHandler* ALBRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request) {
if (request.getURI() == "/")
return new ALBRequestHandler(Logger_, req_id_++);
else
return nullptr;
}
ALBHealthCheckServer::ALBHealthCheckServer() :
SubSystemServer("ALBHealthCheckServer", "ALB-SVR", "alb")
{
}
int ALBHealthCheckServer::Start() {
if(MicroServiceConfigGetBool("alb.enable",false)) {
poco_information(Logger(),"Starting...");
Running_=true;
Port_ = (int)MicroServiceConfigGetInt("alb.port",15015);
Poco::Net::IPAddress Addr(Poco::Net::IPAddress::wildcard(
Poco::Net::Socket::supportsIPv6() ? Poco::Net::AddressFamily::IPv6
: Poco::Net::AddressFamily::IPv4));
Poco::Net::SocketAddress SockAddr(Addr, Port_);
Poco::Net::ServerSocket ClientSocket(SockAddr, 64);
Socket_ = std::make_unique<Poco::Net::ServerSocket>(SockAddr, Port_);
auto Params = new Poco::Net::HTTPServerParams;
Params->setName("ws:alb");
Server_ = std::make_unique<Poco::Net::HTTPServer>(new ALBRequestHandlerFactory(Logger()), *Socket_, Params);
Server_->start();
}
return 0;
}
void ALBHealthCheckServer::Stop() {
poco_information(Logger(),"Stopping...");
if(Running_)
Server_->stopAll(true);
poco_information(Logger(),"Stopped...");
}
} // namespace OpenWifi

63
src/framework/ALBserver.h Normal file
View File

@@ -0,0 +1,63 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPRequestHandlerFactory.h"
#include "Poco/Net/HTTPServer.h"
namespace OpenWifi {
class ALBRequestHandler: public Poco::Net::HTTPRequestHandler {
public:
explicit ALBRequestHandler(Poco::Logger & L, uint64_t id)
: Logger_(L), id_(id) {
}
void handleRequest([[maybe_unused]] Poco::Net::HTTPServerRequest& Request, Poco::Net::HTTPServerResponse& Response) override;
private:
Poco::Logger & Logger_;
uint64_t id_;
};
class ALBRequestHandlerFactory: public Poco::Net::HTTPRequestHandlerFactory
{
public:
explicit ALBRequestHandlerFactory(Poco::Logger & L);
ALBRequestHandler* createRequestHandler(const Poco::Net::HTTPServerRequest& request) override;
private:
Poco::Logger &Logger_;
inline static std::atomic_uint64_t req_id_=1;
};
class ALBHealthCheckServer : public SubSystemServer {
public:
ALBHealthCheckServer();
static auto instance() {
static auto instance = new ALBHealthCheckServer;
return instance;
}
int Start() override;
void Stop() override;
private:
std::unique_ptr<Poco::Net::HTTPServer> Server_;
std::unique_ptr<Poco::Net::ServerSocket> Socket_;
int Port_ = 0;
mutable std::atomic_bool Running_=false;
};
inline auto ALBHealthCheckServer() { return ALBHealthCheckServer::instance(); }
} // namespace OpenWifi

View File

@@ -4,8 +4,14 @@
#pragma once
#include "framework/MicroService.h"
#include "Poco/Logger.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/URI.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
inline void API_Proxy( Poco::Logger &Logger,
@@ -15,7 +21,7 @@ namespace OpenWifi {
const char * PathRewrite,
uint64_t msTimeout_ = 10000 ) {
try {
auto Services = MicroService::instance().GetServices(ServiceType);
auto Services = MicroServiceGetServices(ServiceType);
for(auto const &Svc:Services) {
Poco::URI SourceURI(Request->getURI());
Poco::URI DestinationURI(Svc.PrivateEndPoint);
@@ -35,7 +41,7 @@ namespace OpenWifi {
ProxyRequest.add("Authorization", Request->get("Authorization"));
} else {
ProxyRequest.add("X-API-KEY", Svc.AccessKey);
ProxyRequest.add("X-INTERNAL-NAME", MicroService::instance().PublicEndPoint());
ProxyRequest.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
}
if(Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE) {

View File

@@ -0,0 +1,102 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <fstream>
#include <iomanip>
#include <iostream>
#include "Poco/StreamCopier.h"
#include "Poco/File.h"
#include "framework/MicroServiceFuncs.h"
#include "nlohmann/json.hpp"
namespace OpenWifi {
class AppServiceRegistry {
public:
AppServiceRegistry() {
FileName = MicroServiceDataDirectory() + "/registry.json";
Poco::File F(FileName);
try {
if(F.exists()) {
std::ostringstream OS;
std::ifstream IF(FileName);
Poco::StreamCopier::copyStream(IF, OS);
Registry_ = nlohmann::json::parse(OS.str());
}
} catch (...) {
Registry_ = nlohmann::json::parse("{}");
}
}
static AppServiceRegistry & instance() {
static auto instance_= new AppServiceRegistry;
return *instance_;
}
inline ~AppServiceRegistry() {
Save();
}
inline void Save() {
std::istringstream IS( to_string(Registry_));
std::ofstream OF;
OF.open(FileName,std::ios::binary | std::ios::trunc);
Poco::StreamCopier::copyStream(IS, OF);
}
inline void Set(const char *Key, uint64_t Value ) {
Registry_[Key] = Value;
Save();
}
inline void Set(const char *Key, const std::string &Value ) {
Registry_[Key] = Value;
Save();
}
inline void Set(const char *Key, bool Value ) {
Registry_[Key] = Value;
Save();
}
inline bool Get(const char *Key, bool & Value ) {
if(Registry_[Key].is_boolean()) {
Value = Registry_[Key].get<bool>();
return true;
}
return false;
}
inline bool Get(const char *Key, uint64_t & Value ) {
if(Registry_[Key].is_number_unsigned()) {
Value = Registry_[Key].get<uint64_t>();
return true;
}
return false;
}
inline bool Get(const char *Key, std::string & Value ) {
if(Registry_[Key].is_string()) {
Value = Registry_[Key].get<std::string>();
return true;
}
return false;
}
private:
std::string FileName;
nlohmann::json Registry_;
};
inline auto AppServiceRegistry() { return AppServiceRegistry::instance(); }
}

View File

@@ -0,0 +1,129 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "Poco/Net/HTTPServerResponse.h"
#include "framework/AuthClient.h"
#include "framework/MicroServiceNames.h"
#include "framework/OpenAPIRequests.h"
#include "framework/utils.h"
#include "fmt/format.h"
namespace OpenWifi {
bool AuthClient::RetrieveTokenInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub) {
try {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("token",SessionToken));
std::string AlternateURIForLogging = fmt::format("{}?token={}", Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken", Utils::SanitizeToken(SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY,
Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken",
QueryData,
10000,
AlternateURIForLogging
);
Poco::JSON::Object::Ptr Response;
auto StatusCode = Req.Do(Response);
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
Contacted = false;
return false;
}
Contacted = true;
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo")) {
UInfo.from_json(Response);
if(IsTokenExpired(UInfo.webtoken)) {
Expired = true;
return false;
}
Expired = false;
Cache_.update(SessionToken, UInfo);
return true;
} else {
return false;
}
}
} catch (...) {
poco_error(Logger(),fmt::format("Failed to retrieve token={} for TID={}", Utils::SanitizeToken(SessionToken), TID));
}
Expired = false;
return false;
}
bool AuthClient::IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub) {
auto User = Cache_.get(SessionToken);
if(!User.isNull()) {
if(IsTokenExpired(User->webtoken)) {
Expired = true;
Cache_.remove(SessionToken);
return false;
}
Expired = false;
UInfo = *User;
return true;
}
return RetrieveTokenInformation(SessionToken, UInfo, TID, Expired, Contacted, Sub);
}
bool AuthClient::RetrieveApiKeyInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted) {
try {
Types::StringPairVec QueryData;
QueryData.push_back(std::make_pair("apikey",SessionToken));
std::string AlternateURIForLogging = fmt::format("/api/v1/validateApiKey?apiKey={}", Utils::SanitizeToken(SessionToken));
OpenAPIRequestGet Req( uSERVICE_SECURITY,
"/api/v1/validateApiKey" ,
QueryData,
10000,
AlternateURIForLogging);
Poco::JSON::Object::Ptr Response;
auto StatusCode = Req.Do(Response);
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT) {
Contacted = false;
return false;
}
Contacted = true;
if(StatusCode==Poco::Net::HTTPServerResponse::HTTP_OK) {
if(Response->has("tokenInfo") && Response->has("userInfo") && Response->has("expiresOn")) {
UInfo.from_json(Response);
Expired = false;
ApiKeyCache_.update(SessionToken, ApiKeyCacheEntry{ .UserInfo = UInfo, .ExpiresOn = Response->get("expiresOn")});
return true;
} else {
return false;
}
}
} catch (...) {
poco_error(Logger(),fmt::format("Failed to retrieve api key={} for TID={}", Utils::SanitizeToken(SessionToken), TID));
}
Expired = false;
return false;
}
bool AuthClient::IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy &UInfo,
std::uint64_t TID, bool &Expired, bool &Contacted) {
auto User = ApiKeyCache_.get(SessionToken);
if (!User.isNull()) {
if(User->ExpiresOn < Utils::Now()) {
Expired = false;
UInfo = User->UserInfo;
return true;
}
ApiKeyCache_.remove(SessionToken);
}
return RetrieveApiKeyInformation(SessionToken, UInfo, TID, Expired, Contacted);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,79 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "Poco/ExpireLRUCache.h"
#include "framework/utils.h"
namespace OpenWifi {
class AuthClient : public SubSystemServer {
public:
explicit AuthClient() noexcept:
SubSystemServer("Authentication", "AUTH-CLNT", "authentication")
{
}
static auto instance() {
static auto instance_ = new AuthClient;
return instance_;
}
struct ApiKeyCacheEntry {
OpenWifi::SecurityObjects::UserInfoAndPolicy UserInfo;
std::uint64_t ExpiresOn;
};
inline int Start() override {
return 0;
}
inline void Stop() override {
poco_information(Logger(),"Stopping...");
std::lock_guard G(Mutex_);
Cache_.clear();
poco_information(Logger(),"Stopped...");
}
inline void RemovedCachedToken(const std::string &Token) {
Cache_.remove(Token);
ApiKeyCache_.remove(Token);
}
inline static bool IsTokenExpired(const SecurityObjects::WebToken &T) {
return ((T.expires_in_+T.created_) < Utils::Now());
}
bool RetrieveTokenInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub=false);
bool RetrieveApiKeyInformation(const std::string & SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted);
bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted, bool Sub = false);
bool IsValidApiKey(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo,
std::uint64_t TID,
bool & Expired, bool & Contacted);
private:
Poco::ExpireLRUCache<std::string,OpenWifi::SecurityObjects::UserInfoAndPolicy> Cache_{512,1200000 };
Poco::ExpireLRUCache<std::string,ApiKeyCacheEntry> ApiKeyCache_{512,1200000 };
};
inline auto AuthClient() { return AuthClient::instance(); }
} // namespace OpenWifi

155
src/framework/CIDR.h Normal file
View File

@@ -0,0 +1,155 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "Poco/Net/IPAddress.h"
#include "Poco/StringTokenizer.h"
#include "framework/OpenWifiTypes.h"
namespace OpenWifi::CIDR {
static bool cidr_match(const in_addr &addr, const in_addr &net, uint8_t bits) {
if (bits == 0) {
return true;
}
return !((addr.s_addr ^ net.s_addr) & htonl(0xFFFFFFFFu << (32 - bits)));
}
static bool cidr6_match(const in6_addr &address, const in6_addr &network, uint8_t bits) {
#ifdef __linux__
const uint32_t *a = address.s6_addr32;
const uint32_t *n = network.s6_addr32;
#else
const uint32_t *a = address.__u6_addr.__u6_addr32;
const uint32_t *n = network.__u6_addr.__u6_addr32;
#endif
int bits_whole, bits_incomplete;
bits_whole = bits >> 5; // number of whole u32
bits_incomplete = bits & 0x1F; // number of bits in incomplete u32
if (bits_whole) {
if (memcmp(a, n, bits_whole << 2) != 0) {
return false;
}
}
if (bits_incomplete) {
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
if ((a[bits_whole] ^ n[bits_whole]) & mask) {
return false;
}
}
return true;
}
static bool ConvertStringToLong(const char *S, unsigned long &L) {
char *end;
L = std::strtol(S, &end, 10);
return end != S;
}
static bool CidrIPinRange(const Poco::Net::IPAddress &IP, const std::string &Range) {
Poco::StringTokenizer TimeTokens(Range, "/", Poco::StringTokenizer::TOK_TRIM);
Poco::Net::IPAddress RangeIP;
if (Poco::Net::IPAddress::tryParse(TimeTokens[0], RangeIP)) {
if (TimeTokens.count() == 2) {
if (RangeIP.family() == Poco::Net::IPAddress::IPv4) {
unsigned long MaskLength;
if (ConvertStringToLong(TimeTokens[1].c_str(), MaskLength)) {
return cidr_match(*static_cast<const in_addr *>(RangeIP.addr()),
*static_cast<const in_addr *>(IP.addr()), MaskLength);
}
} else if (RangeIP.family() == Poco::Net::IPAddress::IPv6) {
unsigned long MaskLength;
if (ConvertStringToLong(TimeTokens[1].c_str(), MaskLength)) {
return cidr6_match(*static_cast<const in6_addr *>(RangeIP.addr()),
*static_cast<const in6_addr *>(IP.addr()), MaskLength);
}
}
}
return false;
}
return false;
}
//
// Ranges can be a single IP, of IP1-IP2, of A set of IPs: IP1,IP2,IP3, or a cidr IP/24
// These can work for IPv6 too...
//
static bool ValidateRange(const std::string &R) {
auto Tokens = Poco::StringTokenizer(R, "-");
if (Tokens.count() == 2) {
Poco::Net::IPAddress a, b;
if (!Poco::Net::IPAddress::tryParse(Tokens[0], a) &&
Poco::Net::IPAddress::tryParse(Tokens[1], b))
return false;
return a.family() == b.family();
}
Tokens = Poco::StringTokenizer(R, ",");
if (Tokens.count() > 1) {
return std::all_of(Tokens.begin(), Tokens.end(), [](const std::string &A) {
Poco::Net::IPAddress a;
return Poco::Net::IPAddress::tryParse(A, a);
});
}
Tokens = Poco::StringTokenizer(R, "/");
if (Tokens.count() == 2) {
Poco::Net::IPAddress a;
if (!Poco::Net::IPAddress::tryParse(Tokens[0], a))
return false;
if (std::atoi(Tokens[1].c_str()) == 0)
return false;
return true;
}
Poco::Net::IPAddress a;
return Poco::Net::IPAddress::tryParse(R, a);
}
static bool IpInRange(const Poco::Net::IPAddress &target, const std::string &R) {
auto Tokens = Poco::StringTokenizer(R, "-");
if (Tokens.count() == 2) {
auto a = Poco::Net::IPAddress::parse(Tokens[0]);
auto b = Poco::Net::IPAddress::parse(Tokens[1]);
if (target.family() != a.family())
return false;
return (a <= target && b >= target);
}
Tokens = Poco::StringTokenizer(R, ",");
if (Tokens.count() > 1) {
return std::any_of(Tokens.begin(), Tokens.end(), [target](const std::string &Element) {
return Poco::Net::IPAddress::parse(Element) == target;
});
}
Tokens = Poco::StringTokenizer(R, "/");
if (Tokens.count() == 2) {
return CidrIPinRange(target, R);
}
return Poco::Net::IPAddress::parse(R) == target;
}
[[nodiscard]] inline bool IpInRanges(const std::string &IP, const Types::StringVec &R) {
Poco::Net::IPAddress Target;
if (!Poco::Net::IPAddress::tryParse(IP, Target))
return false;
return std::any_of(cbegin(R), cend(R),
[Target](const std::string &i) { return IpInRange(Target, i); });
}
[[nodiscard]] inline bool ValidateIpRanges(const Types::StringVec &Ranges) {
return std::all_of(cbegin(Ranges), cend(Ranges), ValidateRange);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
#pragma once
#include <nlohmann/json-schema.hpp>
#include "framework/MicroService.h"
#include "framework/SubSystemServer.h"
using nlohmann::json;
using nlohmann::json_schema::json_validator;
@@ -32,7 +32,7 @@ namespace OpenWifi {
nlohmann::json RootSchema_;
ConfigurationValidator():
SubSystemServer("configvalidator", "CFG-VALIDATOR", "config.validator") {
SubSystemServer("ConfigValidator", "CFG-VALIDATOR", "config.validator") {
}
};

View File

@@ -0,0 +1,49 @@
//
// Created by stephane bourque on 2022-10-26.
//
#include "framework/EventBusManager.h"
#include "framework/KafkaManager.h"
#include "framework/utils.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
EventBusManager::EventBusManager(Poco::Logger &L) :
Logger_(L) {
}
void EventBusManager::run() {
Running_ = true;
Utils::SetThreadName("fmwk:EventMgr");
auto Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_JOIN);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
while(Running_) {
Poco::Thread::trySleep((unsigned long)MicroServiceDaemonBusTimer());
if(!Running_)
break;
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
}
Msg = MicroServiceMakeSystemEventMessage(KafkaTopics::ServiceEvents::EVENT_LEAVE);
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS,MicroServicePrivateEndPoint(),Msg, false);
};
void EventBusManager::Start() {
poco_information(Logger(),"Starting...");
if(KafkaManager()->Enabled()) {
Thread_.start(*this);
}
}
void EventBusManager::Stop() {
if(KafkaManager()->Enabled()) {
poco_information(Logger(),"Stopping...");
Running_ = false;
Thread_.wakeUp();
Thread_.join();
poco_information(Logger(),"Stopped...");
}
}
} // namespace OpenWifi

View File

@@ -0,0 +1,28 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include "Poco/Runnable.h"
#include "Poco/Logger.h"
#include "Poco/Thread.h"
namespace OpenWifi {
class EventBusManager : public Poco::Runnable {
public:
explicit EventBusManager(Poco::Logger &L);
void run() final;
void Start();
void Stop();
inline Poco::Logger & Logger() { return Logger_; }
private:
mutable std::atomic_bool Running_ = false;
Poco::Thread Thread_;
Poco::Logger &Logger_;
};
} // namespace OpenWifi

View File

@@ -0,0 +1,365 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "KafkaManager.h"
#include "framework/MicroServiceFuncs.h"
#include "fmt/format.h"
namespace OpenWifi {
void KafkaLoggerFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int level, const std::string & facility, const std::string &message) {
switch ((cppkafka::LogLevel) level) {
case cppkafka::LogLevel::LogNotice: {
poco_notice(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogDebug: {
poco_debug(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogInfo: {
poco_information(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogWarning: {
poco_warning(KafkaManager()->Logger(), fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogAlert:
case cppkafka::LogLevel::LogCrit: {
poco_critical(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
case cppkafka::LogLevel::LogErr:
case cppkafka::LogLevel::LogEmerg:
default: {
poco_error(KafkaManager()->Logger(),fmt::format("kafka-log: facility: {} message: {}",facility, message));
}
break;
}
}
inline void KafkaErrorFun([[maybe_unused]] cppkafka::KafkaHandleBase & handle, int error, const std::string &reason) {
poco_error(KafkaManager()->Logger(),fmt::format("kafka-error: {}, reason: {}", error, reason));
}
inline void AddKafkaSecurity(cppkafka::Configuration & Config) {
auto CA = MicroServiceConfigGetString("openwifi.kafka.ssl.ca.location","");
auto Certificate = MicroServiceConfigGetString("openwifi.kafka.ssl.certificate.location","");
auto Key = MicroServiceConfigGetString("openwifi.kafka.ssl.key.location","");
auto Password = MicroServiceConfigGetString("openwifi.kafka.ssl.key.password","");
if(CA.empty() || Certificate.empty() || Key.empty())
return;
Config.set("ssl.ca.location", CA);
Config.set("ssl.certificate.location", Certificate);
Config.set("ssl.key.location", Key);
if(!Password.empty())
Config.set("ssl.key.password", Password);
}
void KafkaManager::initialize(Poco::Util::Application & self) {
SubSystemServer::initialize(self);
KafkaEnabled_ = MicroServiceConfigGetBool("openwifi.kafka.enable",false);
}
inline void KafkaProducer::run() {
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-PRODUCER", KafkaManager()->Logger().getChannel());
poco_information(Logger_,"Starting...");
Utils::SetThreadName("Kafka:Prod");
cppkafka::Configuration Config({
{ "client.id", MicroServiceConfigGetString("openwifi.kafka.client.id", "") },
{ "metadata.broker.list", MicroServiceConfigGetString("openwifi.kafka.brokerlist", "") }
});
AddKafkaSecurity(Config);
Config.set_log_callback(KafkaLoggerFun);
Config.set_error_callback(KafkaErrorFun);
KafkaManager()->SystemInfoWrapper_ = R"lit({ "system" : { "id" : )lit" +
std::to_string(MicroServiceID()) +
R"lit( , "host" : ")lit" + MicroServicePrivateEndPoint() +
R"lit(" } , "payload" : )lit" ;
cppkafka::Producer Producer(Config);
Running_ = true;
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
while(Note && Running_) {
try {
auto Msg = dynamic_cast<KafkaMessage *>(Note.get());
if (Msg != nullptr) {
Producer.produce(
cppkafka::MessageBuilder(Msg->Topic()).key(Msg->Key()).payload(Msg->Payload()));
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,fmt::format("Caught a Kafka exception (producer): {}", E.what()));
} catch( const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_error(Logger_,"std::exception");
}
Note = Queue_.waitDequeueNotification();
}
poco_information(Logger_,"Stopped...");
}
inline void KafkaConsumer::run() {
Utils::SetThreadName("Kafka:Cons");
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-CONSUMER", KafkaManager()->Logger().getChannel());
poco_information(Logger_,"Starting...");
cppkafka::Configuration Config({
{ "client.id", MicroServiceConfigGetString("openwifi.kafka.client.id","") },
{ "metadata.broker.list", MicroServiceConfigGetString("openwifi.kafka.brokerlist","") },
{ "group.id", MicroServiceConfigGetString("openwifi.kafka.group.id","") },
{ "enable.auto.commit", MicroServiceConfigGetBool("openwifi.kafka.auto.commit",false) },
{ "auto.offset.reset", "latest" } ,
{ "enable.partition.eof", false }
});
AddKafkaSecurity(Config);
Config.set_log_callback(KafkaLoggerFun);
Config.set_error_callback(KafkaErrorFun);
cppkafka::TopicConfiguration topic_config = {
{ "auto.offset.reset", "smallest" }
};
// Now configure it to be the default topic config
Config.set_default_topic_configuration(topic_config);
cppkafka::Consumer Consumer(Config);
Consumer.set_assignment_callback([&](cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) {
poco_information(Logger_,fmt::format("Partition assigned: {}...",
partitions.front().get_partition()));
}
});
Consumer.set_revocation_callback([&](const cppkafka::TopicPartitionList& partitions) {
if(!partitions.empty()) {
poco_information(Logger_,fmt::format("Partition revocation: {}...",
partitions.front().get_partition()));
}
});
bool AutoCommit = MicroServiceConfigGetBool("openwifi.kafka.auto.commit",false);
auto BatchSize = MicroServiceConfigGetInt("openwifi.kafka.consumer.batchsize",20);
Types::StringVec Topics;
KafkaManager()->Topics(Topics);
Consumer.subscribe(Topics);
Running_ = true;
while(Running_) {
try {
std::vector<cppkafka::Message> MsgVec = Consumer.poll_batch(BatchSize, std::chrono::milliseconds(100));
for(auto const &Msg:MsgVec) {
if (!Msg)
continue;
if (Msg.get_error()) {
if (!Msg.is_eof()) {
poco_error(Logger_,fmt::format("Error: {}", Msg.get_error().to_string()));
}
if(!AutoCommit)
Consumer.async_commit(Msg);
continue;
}
KafkaManager()->Dispatch(Msg.get_topic(), Msg.get_key(),Msg.get_payload() );
if (!AutoCommit)
Consumer.async_commit(Msg);
}
} catch (const cppkafka::HandleException &E) {
poco_warning(Logger_,fmt::format("Caught a Kafka exception (consumer): {}", E.what()));
} catch (const Poco::Exception &E) {
Logger_.log(E);
} catch (...) {
poco_error(Logger_,"std::exception");
}
}
Consumer.unsubscribe();
poco_information(Logger_,"Stopped...");
}
void KafkaProducer::Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void KafkaProducer::Stop() {
if(Running_) {
Running_=false;
Queue_.wakeUpAll();
Worker_.join();
}
}
void KafkaProducer::Produce(const std::string &Topic, const std::string &Key, const std::string &Payload) {
std::lock_guard G(Mutex_);
Queue_.enqueueNotification( new KafkaMessage(Topic,Key,Payload));
}
void KafkaConsumer::Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void KafkaConsumer::Stop() {
if(Running_) {
Running_=false;
Worker_.wakeUp();
Worker_.join();
}
}
void KafkaDispatcher::Start() {
if(!Running_) {
Running_=true;
Worker_.start(*this);
}
}
void KafkaDispatcher::Stop() {
if(Running_) {
Running_=false;
Queue_.wakeUpAll();
Worker_.join();
}
}
auto KafkaDispatcher::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if(It == Notifiers_.end()) {
Types::TopicNotifyFunctionList L;
L.emplace(L.end(),std::make_pair(F,FunctionId_));
Notifiers_[Topic] = std::move(L);
} else {
It->second.emplace(It->second.end(),std::make_pair(F,FunctionId_));
}
return FunctionId_++;
}
void KafkaDispatcher::UnregisterTopicWatcher(const std::string &Topic, int Id) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if(It != Notifiers_.end()) {
Types::TopicNotifyFunctionList & L = It->second;
for(auto it=L.begin(); it!=L.end(); it++)
if(it->second == Id) {
L.erase(it);
break;
}
}
}
void KafkaDispatcher::Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload) {
std::lock_guard G(Mutex_);
auto It = Notifiers_.find(Topic);
if(It!=Notifiers_.end()) {
Queue_.enqueueNotification(new KafkaMessage(Topic, Key, Payload));
}
}
void KafkaDispatcher::run() {
Poco::Logger &Logger_ = Poco::Logger::create("KAFKA-DISPATCHER", KafkaManager()->Logger().getChannel());
poco_information(Logger_,"Starting...");
Poco::AutoPtr<Poco::Notification> Note(Queue_.waitDequeueNotification());
Utils::SetThreadName("kafka:dispatch");
while(Note && Running_) {
auto Msg = dynamic_cast<KafkaMessage*>(Note.get());
if(Msg!= nullptr) {
auto It = Notifiers_.find(Msg->Topic());
if (It != Notifiers_.end()) {
const auto & FL = It->second;
for(const auto &[CallbackFunc,_]:FL) {
CallbackFunc(Msg->Key(), Msg->Payload());
}
}
}
Note = Queue_.waitDequeueNotification();
}
poco_information(Logger_,"Stopped...");
}
void KafkaDispatcher::Topics(std::vector<std::string> &T) {
T.clear();
for(const auto &[TopicName,_]:Notifiers_)
T.push_back(TopicName);
}
int KafkaManager::Start() {
if(!KafkaEnabled_)
return 0;
ConsumerThr_.Start();
ProducerThr_.Start();
Dispatcher_.Start();
return 0;
}
void KafkaManager::Stop() {
if(KafkaEnabled_) {
poco_information(Logger(),"Stopping...");
Dispatcher_.Stop();
ProducerThr_.Stop();
ConsumerThr_.Stop();
poco_information(Logger(),"Stopped...");
return;
}
}
void KafkaManager::PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage ) {
if(KafkaEnabled_) {
ProducerThr_.Produce(topic,key,WrapMessage ? WrapSystemId(PayLoad) : PayLoad);
}
}
void KafkaManager::Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload) {
Dispatcher_.Dispatch(Topic, Key, Payload);
}
[[nodiscard]] std::string KafkaManager::WrapSystemId(const std::string & PayLoad) {
return SystemInfoWrapper_ + PayLoad + "}";
}
uint64_t KafkaManager::RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F) {
if(KafkaEnabled_) {
return Dispatcher_.RegisterTopicWatcher(Topic,F);
} else {
return 0;
}
}
void KafkaManager::UnregisterTopicWatcher(const std::string &Topic, uint64_t Id) {
if(KafkaEnabled_) {
Dispatcher_.UnregisterTopicWatcher(Topic, Id);
}
}
void KafkaManager::Topics(std::vector<std::string> &T) {
Dispatcher_.Topics(T);
}
void KafkaManager::PartitionAssignment(const cppkafka::TopicPartitionList& partitions) {
poco_information(Logger(),fmt::format("Partition assigned: {}...", partitions.front().get_partition()));
}
void KafkaManager::PartitionRevocation(const cppkafka::TopicPartitionList& partitions) {
poco_information(Logger(),fmt::format("Partition revocation: {}...",partitions.front().get_partition()));
}
} // namespace OpenWifi

View File

@@ -0,0 +1,122 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "Poco/Notification.h"
#include "Poco/NotificationQueue.h"
#include "framework/SubSystemServer.h"
#include "framework/OpenWifiTypes.h"
#include "framework/utils.h"
#include "framework/KafkaTopics.h"
#include "cppkafka/cppkafka.h"
namespace OpenWifi {
class KafkaMessage: public Poco::Notification {
public:
KafkaMessage( const std::string &Topic, const std::string &Key, const std::string & Payload) :
Topic_(Topic), Key_(Key), Payload_(Payload) {
}
inline const std::string & Topic() { return Topic_; }
inline const std::string & Key() { return Key_; }
inline const std::string & Payload() { return Payload_; }
private:
std::string Topic_;
std::string Key_;
std::string Payload_;
};
class KafkaProducer : public Poco::Runnable {
public:
void run () override;
void Start();
void Stop();
void Produce(const std::string &Topic, const std::string &Key, const std::string &Payload);
private:
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_=false;
Poco::NotificationQueue Queue_;
};
class KafkaConsumer : public Poco::Runnable {
public:
void run() override;
void Start();
void Stop();
private:
std::recursive_mutex Mutex_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_=false;
};
class KafkaDispatcher : public Poco::Runnable {
public:
void Start();
void Stop();
auto RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, int Id);
void Dispatch(const std::string &Topic, const std::string &Key, const std::string &Payload);
void run() override;
void Topics(std::vector<std::string> &T);
private:
std::recursive_mutex Mutex_;
Types::NotifyTable Notifiers_;
Poco::Thread Worker_;
mutable std::atomic_bool Running_=false;
uint64_t FunctionId_=1;
Poco::NotificationQueue Queue_;
};
class KafkaManager : public SubSystemServer {
public:
friend class KafkaConsumer;
friend class KafkaProducer;
inline void initialize(Poco::Util::Application & self) override;
static auto instance() {
static auto instance_ = new KafkaManager;
return instance_;
}
int Start() override;
void Stop() override;
void PostMessage(const std::string &topic, const std::string & key, const std::string &PayLoad, bool WrapMessage = true );
void Dispatch(const std::string &Topic, const std::string & Key, const std::string &Payload);
[[nodiscard]] std::string WrapSystemId(const std::string & PayLoad);
[[nodiscard]] inline bool Enabled() const { return KafkaEnabled_; }
uint64_t RegisterTopicWatcher(const std::string &Topic, Types::TopicNotifyFunction &F);
void UnregisterTopicWatcher(const std::string &Topic, uint64_t Id);
void Topics(std::vector<std::string> &T);
private:
bool KafkaEnabled_ = false;
std::string SystemInfoWrapper_;
KafkaProducer ProducerThr_;
KafkaConsumer ConsumerThr_;
KafkaDispatcher Dispatcher_;
void PartitionAssignment(const cppkafka::TopicPartitionList& partitions);
void PartitionRevocation(const cppkafka::TopicPartitionList& partitions);
KafkaManager() noexcept:
SubSystemServer("KafkaManager", "KAFKA-SVR", "openwifi.kafka") {
}
};
inline auto KafkaManager() { return KafkaManager::instance(); }
} // namespace OpenWifi

View File

@@ -8,6 +8,7 @@
#pragma once
#include <string>
namespace OpenWifi::KafkaTopics {
static const std::string HEALTHCHECK{"healthcheck"};
static const std::string STATE{"state"};

View File

@@ -0,0 +1,712 @@
//
// Created by stephane bourque on 2022-10-26.
//
#include "Poco/FileChannel.h"
#include "Poco/ConsoleChannel.h"
#include "Poco/PatternFormatter.h"
#include "Poco/FormattingChannel.h"
#include "Poco/AsyncChannel.h"
#include "Poco/NullChannel.h"
#include "Poco/SplitterChannel.h"
#include "Poco/Net/HTTPStreamFactory.h"
#include "Poco/Net/HTTPSStreamFactory.h"
#include "Poco/Net/FTPSStreamFactory.h"
#include "Poco/Net/FTPStreamFactory.h"
#include "Poco/Net/SSLManager.h"
#include "Poco/JSON/JSONException.h"
#include "framework/MicroService.h"
#include "framework/MicroServiceErrorHandler.h"
#include "framework/UI_WebSocketClientServer.h"
#include "framework/MicroServiceNames.h"
#include "framework/AuthClient.h"
#include "framework/ALBserver.h"
#include "framework/KafkaManager.h"
#include "framework/RESTAPI_GenericServerAccounting.h"
#include "framework/RESTAPI_ExtServer.h"
#include "framework/RESTAPI_IntServer.h"
#include "framework/utils.h"
#include "framework/WebSocketLogger.h"
namespace OpenWifi {
void MicroService::Exit(int Reason) {
std::exit(Reason);
}
void MicroService::BusMessageReceived([[maybe_unused]] const std::string &Key, const std::string & Payload) {
std::lock_guard G(InfraMutex_);
try {
Poco::JSON::Parser P;
auto Object = P.parse(Payload).extract<Poco::JSON::Object::Ptr>();
if (Object->has(KafkaTopics::ServiceEvents::Fields::ID) &&
Object->has(KafkaTopics::ServiceEvents::Fields::EVENT)) {
uint64_t ID = Object->get(KafkaTopics::ServiceEvents::Fields::ID);
auto Event = Object->get(KafkaTopics::ServiceEvents::Fields::EVENT).toString();
if (ID != ID_) {
if( Event==KafkaTopics::ServiceEvents::EVENT_JOIN ||
Event==KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE ||
Event==KafkaTopics::ServiceEvents::EVENT_LEAVE ) {
if( Object->has(KafkaTopics::ServiceEvents::Fields::TYPE) &&
Object->has(KafkaTopics::ServiceEvents::Fields::PUBLIC) &&
Object->has(KafkaTopics::ServiceEvents::Fields::PRIVATE) &&
Object->has(KafkaTopics::ServiceEvents::Fields::VRSN) &&
Object->has(KafkaTopics::ServiceEvents::Fields::KEY)) {
auto PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString();
if (Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE && Services_.find(PrivateEndPoint) != Services_.end()) {
Services_[PrivateEndPoint].LastUpdate = Utils::Now();
} else if (Event == KafkaTopics::ServiceEvents::EVENT_LEAVE) {
Services_.erase(PrivateEndPoint);
poco_debug(logger(),fmt::format("Service {} ID={} leaving system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
} else if (Event == KafkaTopics::ServiceEvents::EVENT_JOIN || Event == KafkaTopics::ServiceEvents::EVENT_KEEP_ALIVE) {
poco_debug(logger(),fmt::format("Service {} ID={} joining system.",Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),ID));
Services_[PrivateEndPoint] = Types::MicroServiceMeta{
.Id = ID,
.Type = Poco::toLower(Object->get(KafkaTopics::ServiceEvents::Fields::TYPE).toString()),
.PrivateEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PRIVATE).toString(),
.PublicEndPoint = Object->get(KafkaTopics::ServiceEvents::Fields::PUBLIC).toString(),
.AccessKey = Object->get(KafkaTopics::ServiceEvents::Fields::KEY).toString(),
.Version = Object->get(KafkaTopics::ServiceEvents::Fields::VRSN).toString(),
.LastUpdate = Utils::Now() };
std::string SvcList;
for (const auto &Svc: Services_) {
if(SvcList.empty())
SvcList = Svc.second.Type;
else
SvcList += ", " + Svc.second.Type;
}
poco_information(logger(),fmt::format("Current list of microservices: {}", SvcList));
}
} else {
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing a field.",Event));
}
} else if (Event==KafkaTopics::ServiceEvents::EVENT_REMOVE_TOKEN) {
if(Object->has(KafkaTopics::ServiceEvents::Fields::TOKEN)) {
#ifndef TIP_SECURITY_SERVICE
AuthClient()->RemovedCachedToken(Object->get(KafkaTopics::ServiceEvents::Fields::TOKEN).toString());
#endif
} else {
poco_error(logger(),fmt::format("KAFKA-MSG: invalid event '{}', missing token",Event));
}
} else {
poco_error(logger(),fmt::format("Unknown Event: {} Source: {}", Event, ID));
}
}
} else {
poco_error(logger(),"Bad bus message.");
}
auto i=Services_.begin();
auto now = Utils::Now();
for(;i!=Services_.end();) {
if((now - i->second.LastUpdate)>60) {
i = Services_.erase(i);
} else
++i;
}
} catch (const Poco::Exception &E) {
logger().log(E);
}
}
Types::MicroServiceMetaVec MicroService::GetServices(const std::string & Type) {
std::lock_guard G(InfraMutex_);
auto T = Poco::toLower(Type);
Types::MicroServiceMetaVec Res;
for(const auto &[_,ServiceRec]:Services_) {
if(ServiceRec.Type==T)
Res.push_back(ServiceRec);
}
return Res;
}
Types::MicroServiceMetaVec MicroService::GetServices() {
std::lock_guard G(InfraMutex_);
Types::MicroServiceMetaVec Res;
for(const auto &[_,ServiceRec]:Services_) {
Res.push_back(ServiceRec);
}
return Res;
}
void MicroService::LoadConfigurationFile() {
std::string Location = Poco::Environment::get(DAEMON_CONFIG_ENV_VAR,".");
ConfigFileName_ = ConfigFileName_.empty() ? Location + "/" + DAEMON_PROPERTIES_FILENAME : ConfigFileName_;
Poco::Path ConfigFile(ConfigFileName_);
if(!ConfigFile.isFile())
{
std::cerr << DAEMON_APP_NAME << ": Configuration "
<< ConfigFile.toString() << " does not seem to exist. Please set " + DAEMON_CONFIG_ENV_VAR
+ " env variable the path of the " + DAEMON_PROPERTIES_FILENAME + " file." << std::endl;
std::exit(Poco::Util::Application::EXIT_CONFIG);
}
// loadConfiguration(ConfigFile.toString());
PropConfigurationFile_ = new Poco::Util::PropertyFileConfiguration(ConfigFile.toString());
configPtr()->addWriteable(PropConfigurationFile_, PRIO_DEFAULT);
}
void MicroService::Reload() {
LoadConfigurationFile();
LoadMyConfig();
}
void MicroService::LoadMyConfig() {
NoAPISecurity_ = ConfigGetBool("openwifi.security.restapi.disable",false);
std::string KeyFile = ConfigPath("openwifi.service.key","");
if(!KeyFile.empty()) {
std::string KeyFilePassword = ConfigPath("openwifi.service.key.password", "");
AppKey_ = Poco::SharedPtr<Poco::Crypto::RSAKey>(new Poco::Crypto::RSAKey("", KeyFile, KeyFilePassword));
Cipher_ = CipherFactory_.createCipher(*AppKey_);
Signer_.setRSAKey(AppKey_);
Signer_.addAllAlgorithms();
NoBuiltInCrypto_ = false;
} else {
NoBuiltInCrypto_ = true;
}
ID_ = Utils::GetSystemId();
if(!DebugMode_)
DebugMode_ = ConfigGetBool("openwifi.system.debug",false);
MyPrivateEndPoint_ = ConfigGetString("openwifi.system.uri.private");
MyPublicEndPoint_ = ConfigGetString("openwifi.system.uri.public");
UIURI_ = ConfigGetString("openwifi.system.uri.ui");
MyHash_ = Utils::ComputeHash(MyPublicEndPoint_);
}
void MicroService::InitializeLoggingSystem() {
static auto initialized = false;
if(!initialized) {
initialized = true;
LoadConfigurationFile();
auto LoggingDestination = MicroService::instance().ConfigGetString("logging.type", "file");
auto LoggingFormat = MicroService::instance().ConfigGetString("logging.format",
"%Y-%m-%d %H:%M:%S.%i %s: [%p][thr:%I] %t");
auto UseAsyncLogs_ = MicroService::instance().ConfigGetBool("logging.asynch", true);
auto DisableWebSocketLogging = MicroService::instance().ConfigGetBool("logging.websocket",false);
if (LoggingDestination == "null") {
Poco::AutoPtr<Poco::NullChannel> DevNull(new Poco::NullChannel);
Poco::Logger::root().setChannel(DevNull);
} else if (LoggingDestination == "console") {
SetConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else if (LoggingDestination == "colorconsole") {
SetColorConsoleLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else if (LoggingDestination == "sql") {
SetSQLLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else if (LoggingDestination == "syslog") {
SetSyslogLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat);
} else {
SetFileLogs(UseAsyncLogs_, DisableWebSocketLogging, LoggingFormat, DAEMON_ROOT_ENV_VAR);
}
auto Level = Poco::Logger::parseLevel(MicroService::instance().ConfigGetString("logging.level", "debug"));
Poco::Logger::root().setLevel(Level);
if(!DisableWebSocketLogging) {
static const UI_WebSocketClientServer::NotificationTypeIdVec Notifications = {
{1, "log"}};
UI_WebSocketClientServer()->RegisterNotifications(Notifications);
}
}
}
void MicroService::SetConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
Poco::AutoPtr<Poco::ConsoleChannel> Console(new Poco::ConsoleChannel);
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
Formatter->setProperty("pattern", FormatterPattern);
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
if(DisableWebSocketLogging) {
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(FormattingChannel);
}
} else {
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel);
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(Splitter);
}
}
Poco::Logger::root().information(fmt::format("Enabled console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
}
void MicroService::SetColorConsoleLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern) {
Poco::AutoPtr<Poco::ColorConsoleChannel> Console(new Poco::ColorConsoleChannel);
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
Formatter->setProperty("pattern", FormatterPattern);
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, Console));
if(DisableWebSocketLogging) {
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(FormattingChannel);
}
} else {
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel);
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(Splitter);
}
}
Poco::Logger::root().information(fmt::format("Enabled color console logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
}
void MicroService::SetSQLLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
//"CREATE TABLE T_POCO_LOG (Source VARCHAR, Name VARCHAR, ProcessId INTEGER, Thread VARCHAR, ThreadId INTEGER, Priority INTEGER, Text VARCHAR, DateTime DATE)"
}
void MicroService::SetSyslogLogs([[maybe_unused]] bool UseAsync,[[maybe_unused]] bool DisableWebSocketLogging,[[maybe_unused]] const std::string & FormatterPattern) {
}
void MicroService::SetFileLogs(bool UseAsync, bool DisableWebSocketLogging, const std::string & FormatterPattern, const std::string & root_env_var) {
std::string DefaultLogPath = fmt::format("${}/logs",root_env_var);
auto LoggingLocationDir = MicroService::instance().ConfigPath("logging.path", DefaultLogPath);
Poco::File LD(LoggingLocationDir);
try {
if(!LD.exists()) {
LD.createDirectory();
}
} catch(const Poco::Exception &E) {
std::cout << "Cannot create " << LD.path() << " Error: " << E.message() << std::endl;
}
auto LoggingLocationDirFilePattern = LoggingLocationDir + "/log";
Poco::AutoPtr<Poco::FileChannel> FileChannel(new Poco::FileChannel);
FileChannel->setProperty("rotation", "10 M");
FileChannel->setProperty("archive", "timestamp");
FileChannel->setProperty("purgeCount", "10");
FileChannel->setProperty("path", LoggingLocationDirFilePattern);
Poco::AutoPtr<Poco::PatternFormatter> Formatter(new Poco::PatternFormatter);
Formatter->setProperty("pattern", FormatterPattern);
Poco::AutoPtr<Poco::FormattingChannel> FormattingChannel(new Poco::FormattingChannel(Formatter, FileChannel));
if(DisableWebSocketLogging) {
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(FormattingChannel));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(FormattingChannel);
}
} else {
Poco::AutoPtr<WebSocketLogger> WSLogger(new WebSocketLogger);
Poco::AutoPtr<Poco::SplitterChannel> Splitter(new Poco::SplitterChannel);
Splitter->addChannel(WSLogger);
Splitter->addChannel(FormattingChannel);
if(UseAsync) {
Poco::AutoPtr<Poco::AsyncChannel> Async(new Poco::AsyncChannel(Splitter));
Poco::Logger::root().setChannel(Async);
} else {
Poco::Logger::root().setChannel(Splitter);
}
}
Poco::Logger::root().information(fmt::format("Enabled file logs: asynch={} websocket={}",UseAsync,DisableWebSocketLogging));
}
void DaemonPostInitialization(Poco::Util::Application &self);
void MicroService::initialize(Poco::Util::Application &self) {
// add the default services
LoadConfigurationFile();
InitializeLoggingSystem();
SubSystems_.push_back(KafkaManager());
SubSystems_.push_back(ALBHealthCheckServer());
SubSystems_.push_back(RESTAPI_ExtServer());
SubSystems_.push_back(RESTAPI_IntServer());
#ifndef TIP_SECURITY_SERVICE
SubSystems_.push_back(AuthClient());
#endif
Poco::Net::initializeSSL();
Poco::Net::HTTPStreamFactory::registerFactory();
Poco::Net::HTTPSStreamFactory::registerFactory();
Poco::Net::FTPStreamFactory::registerFactory();
Poco::Net::FTPSStreamFactory::registerFactory();
Poco::File DataDir(ConfigPath("openwifi.system.data"));
DataDir_ = DataDir.path();
if(!DataDir.exists()) {
try {
DataDir.createDirectory();
} catch (const Poco::Exception &E) {
logger().log(E);
}
}
WWWAssetsDir_ = ConfigPath("openwifi.restapi.wwwassets","");
if(WWWAssetsDir_.empty())
WWWAssetsDir_ = DataDir_;
LoadMyConfig();
InitializeSubSystemServers();
ServerApplication::initialize(self);
DaemonPostInitialization(self);
Types::TopicNotifyFunction F = [this](const std::string &Key,const std::string &Payload) { this->BusMessageReceived(Key, Payload); };
KafkaManager()->RegisterTopicWatcher(KafkaTopics::SERVICE_EVENTS, F);
}
void MicroService::uninitialize() {
// add your own uninitialization code here
ServerApplication::uninitialize();
}
void MicroService::reinitialize(Poco::Util::Application &self) {
ServerApplication::reinitialize(self);
// add your own reinitialization code here
}
void MicroService::defineOptions(Poco::Util::OptionSet &options) {
ServerApplication::defineOptions(options);
options.addOption(
Poco::Util::Option("help", "", "display help information on command line arguments")
.required(false)
.repeatable(false)
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleHelp)));
options.addOption(
Poco::Util::Option("file", "", "specify the configuration file")
.required(false)
.repeatable(false)
.argument("file")
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleConfig)));
options.addOption(
Poco::Util::Option("debug", "", "to run in debug, set to true")
.required(false)
.repeatable(false)
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleDebug)));
options.addOption(
Poco::Util::Option("logs", "", "specify the log directory and file (i.e. dir/file.log)")
.required(false)
.repeatable(false)
.argument("dir")
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleLogs)));
options.addOption(
Poco::Util::Option("version", "", "get the version and quit.")
.required(false)
.repeatable(false)
.callback(Poco::Util::OptionCallback<MicroService>(this, &MicroService::handleVersion)));
}
void MicroService::handleHelp([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
HelpRequested_ = true;
displayHelp();
stopOptionsProcessing();
}
void MicroService::handleVersion([[maybe_unused]] const std::string &name, [[maybe_unused]] const std::string &value) {
HelpRequested_ = true;
std::cout << Version() << std::endl;
stopOptionsProcessing();
}
void MicroService::handleDebug([[maybe_unused]] const std::string &name, const std::string &value) {
if(value == "true")
DebugMode_ = true ;
}
void MicroService::handleLogs([[maybe_unused]] const std::string &name, const std::string &value) {
LogDir_ = value;
}
void MicroService::handleConfig([[maybe_unused]] const std::string &name, const std::string &value) {
ConfigFileName_ = value;
}
void MicroService::displayHelp() {
Poco::Util::HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A " + DAEMON_APP_NAME + " implementation for TIP.");
helpFormatter.format(std::cout);
}
void MicroService::InitializeSubSystemServers() {
for(auto i:SubSystems_) {
addSubsystem(i);
}
}
void MicroService::StartSubSystemServers() {
AddActivity("Starting");
for(auto i:SubSystems_) {
i->Start();
}
EventBusManager_ = std::make_unique<EventBusManager>(Poco::Logger::create("EventBusManager",Poco::Logger::root().getChannel(),Poco::Logger::root().getLevel()));
EventBusManager_->Start();
}
void MicroService::StopSubSystemServers() {
AddActivity("Stopping");
EventBusManager_->Stop();
for(auto i=SubSystems_.rbegin(); i!=SubSystems_.rend(); ++i) {
(*i)->Stop();
}
}
[[nodiscard]] std::string MicroService::CreateUUID() {
static std::random_device rd;
static std::mt19937_64 gen(rd());
static std::uniform_int_distribution<> dis(0, 15);
static std::uniform_int_distribution<> dis2(8, 11);
std::stringstream ss;
int i;
ss << std::hex;
for (i = 0; i < 8; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 4; i++) {
ss << dis(gen);
}
ss << "-4";
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
ss << dis2(gen);
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 12; i++) {
ss << dis(gen);
};
return ss.str();
}
bool MicroService::SetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
try {
auto P = Poco::Logger::parseLevel(Level);
auto Sub = Poco::toLower(SubSystem);
if (Sub == "all") {
for (auto i : SubSystems_) {
i->Logger().setLevel(P);
}
return true;
} else {
for (auto i : SubSystems_) {
if (Sub == Poco::toLower(i->Name())) {
i->Logger().setLevel(P);
return true;
}
}
}
} catch (const Poco::Exception & E) {
std::cerr << "Exception" << std::endl;
}
return false;
}
void MicroService::Reload(const std::string &Sub) {
for (auto i : SubSystems_) {
if (Poco::toLower(Sub) == Poco::toLower(i->Name())) {
i->reinitialize(Poco::Util::Application::instance());
return;
}
}
}
Types::StringVec MicroService::GetSubSystems() const {
Types::StringVec Result;
for(auto i:SubSystems_)
Result.push_back(Poco::toLower(i->Name()));
return Result;
}
Types::StringPairVec MicroService::GetLogLevels() {
Types::StringPairVec Result;
for(auto &i:SubSystems_) {
auto P = std::make_pair( i->Name(), Utils::LogLevelToString(i->GetLoggingLevel()));
Result.push_back(P);
}
return Result;
}
const Types::StringVec & MicroService::GetLogLevelNames() {
static Types::StringVec LevelNames{"none", "fatal", "critical", "error", "warning", "notice", "information", "debug", "trace" };
return LevelNames;
}
uint64_t MicroService::ConfigGetInt(const std::string &Key,uint64_t Default) {
return (uint64_t) config().getInt64(Key,Default);
}
uint64_t MicroService::ConfigGetInt(const std::string &Key) {
return config().getInt(Key);
}
uint64_t MicroService::ConfigGetBool(const std::string &Key,bool Default) {
return config().getBool(Key,Default);
}
uint64_t MicroService::ConfigGetBool(const std::string &Key) {
return config().getBool(Key);
}
std::string MicroService::ConfigGetString(const std::string &Key,const std::string & Default) {
return config().getString(Key, Default);
}
std::string MicroService::ConfigGetString(const std::string &Key) {
return config().getString(Key);
}
std::string MicroService::ConfigPath(const std::string &Key,const std::string & Default) {
std::string R = config().getString(Key, Default);
return Poco::Path::expand(R);
}
std::string MicroService::ConfigPath(const std::string &Key) {
std::string R = config().getString(Key);
return Poco::Path::expand(R);
}
std::string MicroService::Encrypt(const std::string &S) {
if(NoBuiltInCrypto_) {
return S;
}
return Cipher_->encryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
}
std::string MicroService::Decrypt(const std::string &S) {
if(NoBuiltInCrypto_) {
return S;
}
return Cipher_->decryptString(S, Poco::Crypto::Cipher::Cipher::ENC_BASE64);;
}
std::string MicroService::MakeSystemEventMessage( const std::string & Type ) const {
Poco::JSON::Object Obj;
Obj.set(KafkaTopics::ServiceEvents::Fields::EVENT,Type);
Obj.set(KafkaTopics::ServiceEvents::Fields::ID,ID_);
Obj.set(KafkaTopics::ServiceEvents::Fields::TYPE,Poco::toLower(DAEMON_APP_NAME));
Obj.set(KafkaTopics::ServiceEvents::Fields::PUBLIC,MyPublicEndPoint_);
Obj.set(KafkaTopics::ServiceEvents::Fields::PRIVATE,MyPrivateEndPoint_);
Obj.set(KafkaTopics::ServiceEvents::Fields::KEY,MyHash_);
Obj.set(KafkaTopics::ServiceEvents::Fields::VRSN,Version_);
std::stringstream ResultText;
Poco::JSON::Stringifier::stringify(Obj, ResultText);
return ResultText.str();
}
[[nodiscard]] bool MicroService::IsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
try {
auto APIKEY = Request.get("X-API-KEY");
return APIKEY == MyHash_;
} catch (const Poco::Exception &E) {
logger().log(E);
}
return false;
}
void MicroService::SavePID() {
try {
std::ofstream O;
O.open(MicroService::instance().DataDir() + "/pidfile",std::ios::binary | std::ios::trunc);
O << Poco::Process::id();
O.close();
} catch (...)
{
std::cout << "Could not save system ID" << std::endl;
}
}
int MicroService::main([[maybe_unused]] const ArgVec &args) {
MicroServiceErrorHandler ErrorHandler(*this);
Poco::ErrorHandler::set(&ErrorHandler);
if (!HelpRequested_) {
SavePID();
Poco::Logger &logger = Poco::Logger::get(DAEMON_APP_NAME);
logger.notice(fmt::format("Starting {} version {}.",DAEMON_APP_NAME, Version()));
if(Poco::Net::Socket::supportsIPv6())
poco_information(logger,"System supports IPv6.");
else
poco_information(logger,"System does NOT support IPv6.");
if (config().getBool("application.runAsDaemon", false)) {
poco_information(logger,"Starting as a daemon.");
}
poco_information(logger,fmt::format("System ID set to {}",ID_));
StartSubSystemServers();
waitForTerminationRequest();
StopSubSystemServers();
logger.notice(fmt::format("Stopped {}...",DAEMON_APP_NAME));
}
return Application::EXIT_OK;
}
void MicroService::AddActivity(const std::string &Activity) {
if(!DataDir_.empty()) {
std::string ActivityFile{ DataDir_ + "/activity.log"};
try {
std::ofstream of(ActivityFile,std::ios_base::app | std::ios_base::out );
auto t = std::chrono::system_clock::now();
std::time_t now = std::chrono::system_clock::to_time_t(t);
of << Activity << " at " << std::ctime(&now) ;
} catch (...) {
}
}
}
[[nodiscard]] std::string MicroService::Sign(Poco::JWT::Token &T, const std::string &Algo) {
if(NoBuiltInCrypto_) {
return T.toString();
} else {
return Signer_.sign(T,Algo);
}
}
void MicroService::DeleteOverrideConfiguration() {
Poco::File F(DataDir_ + ExtraConfigurationFilename);
try {
if(F.exists())
F.remove();
} catch (...) {
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,212 @@
//
// Created by stephane bourque on 2022-09-29.
//
#pragma once
#include "fmt/format.h"
#include "Poco/Util/Application.h"
#include "Poco/ErrorHandler.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/SSLException.h"
#include "Poco/JSON/Template.h"
#include "Poco/JSON/JSONException.h"
#include "Poco/Thread.h"
namespace OpenWifi {
class MicroServiceErrorHandler : public Poco::ErrorHandler {
public:
explicit MicroServiceErrorHandler(Poco::Util::Application &App) : App_(App) {
}
inline void exception(const Poco::Exception & Base) override {
try {
if(Poco::Thread::current()!= nullptr) {
t_name = Poco::Thread::current()->getName();
t_id = Poco::Thread::current()->id();
} else {
t_name = "startup_code";
t_id = 0;
}
App_.logger().log(Base);
Base.rethrow();
} catch (const Poco::Net::InvalidCertificateException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidCertificateException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::InvalidSocketException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::WebSocketException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::WebSocketException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::ConnectionResetException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::ConnectionResetException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::CertificateValidationException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::CertificateValidationException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::SSLConnectionUnexpectedlyClosedException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::SSLConnectionUnexpectedlyClosedException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::SSLContextException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::SSLContextException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::SSLException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::SSLException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::InvalidAddressException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::InvalidAddressException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Net::NetException &E) {
poco_error(App_.logger(), fmt::format("Poco::Net::NetException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::IOException &E) {
poco_error(App_.logger(), fmt::format("Poco::IOException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::TimeoutException &E) {
poco_error(App_.logger(), fmt::format("Poco::TimeoutException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::NoThreadAvailableException &E) {
poco_error(App_.logger(), fmt::format("Poco::NoThreadAvailableException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::OutOfMemoryException &E) {
poco_error(App_.logger(), fmt::format("Poco::OutOfMemoryException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::BadCastException &E) {
poco_error(App_.logger(), fmt::format("Poco::BadCastException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::DataException &E) {
poco_error(App_.logger(), fmt::format("Poco::DataException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::PoolOverflowException &E) {
poco_error(App_.logger(), fmt::format("Poco::PoolOverflowException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::SystemException &E) {
poco_error(App_.logger(), fmt::format("Poco::SystemException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::RuntimeException &E) {
poco_error(App_.logger(), fmt::format("Poco::RuntimeException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::JSON::JSONTemplateException &E) {
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONTemplateException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::JSON::JSONException &E) {
poco_error(App_.logger(), fmt::format("Poco::JSON::JSONException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::ApplicationException &E) {
poco_error(App_.logger(), fmt::format("Poco::ApplicationException thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (const Poco::Exception &E) {
poco_error(App_.logger(), fmt::format("Poco::Exception thr_name={} thr_id={} code={} text={} msg={} what={}",
t_name, t_id, E.code(),
E.displayText(),
E.message(),
E.what()));
} catch (...) {
poco_error(App_.logger(), fmt::format("Poco:Generic thr_name={}",t_name, t_id));
}
}
inline void exception(const std::exception & E) override {
if(Poco::Thread::current()!= nullptr) {
t_name = Poco::Thread::current()->getName();
t_id = Poco::Thread::current()->id();
} else {
t_name = "startup_code";
t_id = 0;
}
poco_warning(App_.logger(), fmt::format("std::exception in {}: {} thr_id={}",
t_name,E.what(),
t_id));
}
inline void exception() override {
if(Poco::Thread::current()!= nullptr) {
t_name = Poco::Thread::current()->getName();
t_id = Poco::Thread::current()->id();
} else {
t_name = "startup_code";
t_id = 0;
}
poco_warning(App_.logger(), fmt::format("generic exception in {} thr_id={}",
t_name, t_id));
}
private:
Poco::Util::Application &App_;
std::string t_name;
int t_id=0;
};
}

View File

@@ -0,0 +1,132 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include <string>
#include <map>
#include "Poco/BasicEvent.h"
#include "Poco/ExpireLRUCache.h"
namespace OpenWifi {
class ConfigurationEntry {
public:
template <typename T> explicit ConfigurationEntry(T def) :
Default_(def),
Current_(def){
}
template <typename T> explicit ConfigurationEntry(T def, T cur, const std::string &Hint="") :
Default_(def),
Current_(cur),
Hint_(Hint){
}
inline ConfigurationEntry()=default;
inline ~ConfigurationEntry()=default;
template <typename T> explicit operator T () const { return std::get<T>(Current_); }
inline ConfigurationEntry & operator=(const char *v) { Current_ = std::string(v); return *this;}
template <typename T> ConfigurationEntry & operator=(T v) { Current_ = (T) v; return *this;}
void reset() {
Current_ = Default_;
}
private:
std::variant<bool,uint64_t,std::string> Default_, Current_;
std::string Hint_;
};
inline std::string to_string(const ConfigurationEntry &v) { return (std::string) v; }
typedef std::map<std::string,ConfigurationEntry> ConfigurationMap_t;
template <typename T> class FIFO {
public:
explicit FIFO(uint32_t Size) :
Size_(Size) {
Buffer_ = new T [Size_];
}
~FIFO() {
delete [] Buffer_;
}
mutable Poco::BasicEvent<bool> Writable_;
mutable Poco::BasicEvent<bool> Readable_;
inline bool Read(T &t) {
{
std::lock_guard M(Mutex_);
if (Write_ == Read_) {
return false;
}
t = Buffer_[Read_++];
if (Read_ == Size_) {
Read_ = 0;
}
Used_--;
}
bool flag = true;
Writable_.notify(this, flag);
return true;
}
inline bool Write(const T &t) {
{
std::lock_guard M(Mutex_);
Buffer_[Write_++] = t;
if (Write_ == Size_) {
Write_ = 0;
}
Used_++;
MaxEverUsed_ = std::max(Used_,MaxEverUsed_);
}
bool flag = true;
Readable_.notify(this, flag);
return false;
}
inline bool isFull() {
std::lock_guard M(Mutex_);
return Used_==Buffer_->capacity();
}
inline auto MaxEverUser() const { return MaxEverUsed_; }
private:
std::recursive_mutex Mutex_;
uint32_t Size_=0;
uint32_t Read_=0;
uint32_t Write_=0;
uint32_t Used_=0;
uint32_t MaxEverUsed_=0;
T * Buffer_ = nullptr;
};
template <class Record, typename KeyType = std::string, int Size=256, int Expiry=60000> class RecordCache {
public:
explicit RecordCache( KeyType Record::* Q) :
MemberOffset(Q){
};
inline auto update(const Record &R) {
return Cache_.update(R.*MemberOffset, R);
}
inline auto get(const KeyType &K) {
return Cache_.get(K);
}
inline auto remove(const KeyType &K) {
return Cache_.remove(K);
}
inline auto remove(const Record &R) {
return Cache_.remove(R.*MemberOffset);
}
private:
KeyType Record::* MemberOffset;
Poco::ExpireLRUCache<KeyType,Record> Cache_{Size,Expiry};
};
}

View File

@@ -0,0 +1,121 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "framework/MicroService.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
const std::string &MicroServiceDataDirectory() { return MicroService::instance().DataDir(); }
Types::MicroServiceMetaVec MicroServiceGetServices(const std::string &Type) {
return MicroService::instance().GetServices(Type);
}
Types::MicroServiceMetaVec MicroServiceGetServices() {
return MicroService::instance().GetServices();
}
std::string MicroServicePublicEndPoint() { return MicroService::instance().PublicEndPoint(); }
std::string MicroServiceConfigGetString(const std::string &Key, const std::string &DefaultValue) {
return MicroService::instance().ConfigGetString(Key, DefaultValue);
}
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue) {
return MicroService::instance().ConfigGetBool(Key, DefaultValue);
}
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue) {
return MicroService::instance().ConfigGetInt(Key, DefaultValue);
}
std::string MicroServicePrivateEndPoint() { return MicroService::instance().PrivateEndPoint(); }
std::uint64_t MicroServiceID() { return MicroService::instance().ID(); }
bool MicroServiceIsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request) {
return MicroService::instance().IsValidAPIKEY(Request);
}
bool MicroServiceNoAPISecurity() { return MicroService::instance().NoAPISecurity(); }
void MicroServiceLoadConfigurationFile() { MicroService::instance().LoadConfigurationFile(); }
void MicroServiceReload() { MicroService::instance().Reload(); }
void MicroServiceReload(const std::string &Type) { MicroService::instance().Reload(Type); }
const Types::StringVec MicroServiceGetLogLevelNames() {
return MicroService::instance().GetLogLevelNames();
}
const Types::StringVec MicroServiceGetSubSystems() {
return MicroService::instance().GetSubSystems();
}
Types::StringPairVec MicroServiceGetLogLevels() { return MicroService::instance().GetLogLevels(); }
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level) {
return MicroService::instance().SetSubsystemLogLevel(SubSystem, Level);
}
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer) {
MicroService::instance().GetExtraConfiguration(Answer);
}
std::string MicroServiceVersion() { return MicroService::instance().Version(); }
std::uint64_t MicroServiceUptimeTotalSeconds() {
return MicroService::instance().uptime().totalSeconds();
}
std::uint64_t MicroServiceStartTimeEpochTime() {
return MicroService::instance().startTime().epochTime();
}
std::string MicroServiceGetUIURI() { return MicroService::instance().GetUIURI(); }
const SubSystemVec MicroServiceGetFullSubSystems() {
return MicroService::instance().GetFullSubSystems();
}
std::string MicroServiceCreateUUID() { return MicroService::CreateUUID(); }
std::uint64_t MicroServiceDaemonBusTimer() { return MicroService::instance().DaemonBusTimer(); }
std::string MicroServiceMakeSystemEventMessage(const std::string &Type) {
return MicroService::instance().MakeSystemEventMessage(Type);
}
Poco::ThreadPool &MicroServiceTimerPool() { return MicroService::instance().TimerPool(); }
std::string MicroServiceConfigPath(const std::string &Key,
const std::string &DefaultValue) {
return MicroService::instance().ConfigPath(Key, DefaultValue);
}
std::string MicroServiceWWWAssetsDir() {
return MicroService::instance().WWWAssetsDir();
}
std::uint64_t MicroServiceRandom(std::uint64_t Start,std::uint64_t End) {
return MicroService::instance().Random(Start, End);
}
std::uint64_t MicroServiceRandom(std::uint64_t Range) {
return MicroService::instance().Random(Range);
}
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo) {
return MicroService::instance().Sign(T, Algo);
}
std::string MicroServiceGetPublicAPIEndPoint() {
return MicroService::instance().GetPublicAPIEndPoint();
}
void MicroServiceDeleteOverrideConfiguration() {
return MicroService::instance().DeleteOverrideConfiguration();
}
}

View File

@@ -0,0 +1,56 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "framework/OpenWifiTypes.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/JSON/Object.h"
#include "Poco/ThreadPool.h"
#include "Poco/JWT/Token.h"
namespace OpenWifi {
class SubSystemServer;
using SubSystemVec=std::vector<SubSystemServer *>;
const std::string & MicroServiceDataDirectory();
Types::MicroServiceMetaVec MicroServiceGetServices(const std::string & Type);
Types::MicroServiceMetaVec MicroServiceGetServices();
std::string MicroServicePublicEndPoint();
std::string MicroServiceConfigGetString(const std::string &Key, const std::string &DefaultValue);
bool MicroServiceConfigGetBool(const std::string &Key, bool DefaultValue);
std::uint64_t MicroServiceConfigGetInt(const std::string &Key, std::uint64_t DefaultValue);
std::string MicroServicePrivateEndPoint();
std::uint64_t MicroServiceID();
bool MicroServiceIsValidAPIKEY(const Poco::Net::HTTPServerRequest &Request);
bool MicroServiceNoAPISecurity();
void MicroServiceLoadConfigurationFile();
void MicroServiceReload();
void MicroServiceReload(const std::string &Type);
const Types::StringVec MicroServiceGetLogLevelNames();
const Types::StringVec MicroServiceGetSubSystems();
Types::StringPairVec MicroServiceGetLogLevels();
bool MicroServiceSetSubsystemLogLevel(const std::string &SubSystem, const std::string &Level);
void MicroServiceGetExtraConfiguration(Poco::JSON::Object &Answer);
std::string MicroServiceVersion();
std::uint64_t MicroServiceUptimeTotalSeconds();
std::uint64_t MicroServiceStartTimeEpochTime();
std::string MicroServiceGetUIURI();
const SubSystemVec MicroServiceGetFullSubSystems();
std::string MicroServiceCreateUUID();
std::uint64_t MicroServiceDaemonBusTimer();
std::string MicroServiceMakeSystemEventMessage( const std::string & Type );
Poco::ThreadPool & MicroServiceTimerPool();
std::string MicroServiceConfigPath(const std::string &Key,
const std::string &DefaultValue);
std::string MicroServiceWWWAssetsDir();
std::uint64_t MicroServiceRandom(std::uint64_t Start,std::uint64_t End);
std::uint64_t MicroServiceRandom(std::uint64_t Range);
std::string MicroServiceSign(Poco::JWT::Token &T, const std::string &Algo);
std::string MicroServiceGetPublicAPIEndPoint();
void MicroServiceDeleteOverrideConfiguration();
}

View File

@@ -0,0 +1,22 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
namespace OpenWifi {
static const std::string uSERVICE_SECURITY{"owsec"};
static const std::string uSERVICE_GATEWAY{"owgw"};
static const std::string uSERVICE_FIRMWARE{ "owfms"};
static const std::string uSERVICE_TOPOLOGY{ "owtopo"};
static const std::string uSERVICE_PROVISIONING{ "owprov"};
static const std::string uSERVICE_OWLS{ "owls"};
static const std::string uSERVICE_SUBCRIBER{ "owsub"};
static const std::string uSERVICE_INSTALLER{ "owinst"};
static const std::string uSERVICE_ANALYTICS{ "owanalytics"};
static const std::string uSERVICE_OWRRM{ "owrrm"};
}

View File

@@ -0,0 +1,289 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "OpenAPIRequests.h"
#include "Poco/Logger.h"
#include "Poco/URI.h"
#include "Poco/Net/HTTPRequest.h"
#include "Poco/Net/HTTPSClientSession.h"
#include "Poco/JSON/Parser.h"
#include "fmt/format.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestGet::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_GET,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
poco_debug(Poco::Logger::get("REST-CALLER-GET"), fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-GET").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPut::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
poco_debug(Poco::Logger::get("REST-CALLER-PUT"), fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_PUT,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
std::ostringstream obody;
Poco::JSON::Stringifier::stringify(Body_,obody);
Request.setContentType("application/json");
Request.setContentLength(obody.str().size());
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-PUT").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestPost::Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
poco_debug(Poco::Logger::get("REST-CALLER-POST"),fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_POST,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
std::ostringstream obody;
Poco::JSON::Stringifier::stringify(Body_,obody);
Request.setContentType("application/json");
Request.setContentLength(obody.str().size());
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
std::ostream &os = Session.sendRequest(Request);
os << obody.str();
Poco::Net::HTTPResponse Response;
std::istream &is = Session.receiveResponse(Response);
if (Response.getStatus() == Poco::Net::HTTPResponse::HTTP_OK) {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
} else {
Poco::JSON::Parser P;
ResponseObject = P.parse(is).extract<Poco::JSON::Object::Ptr>();
}
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-POST").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
Poco::Net::HTTPServerResponse::HTTPStatus OpenAPIRequestDelete::Do(const std::string & BearerToken) {
try {
auto Services = MicroServiceGetServices(Type_);
for(auto const &Svc:Services) {
Poco::URI URI(Svc.PrivateEndPoint);
auto Secure = (URI.getScheme() == "https");
URI.setPath(EndPoint_);
for (const auto &qp : QueryData_)
URI.addQueryParameter(qp.first, qp.second);
poco_debug(Poco::Logger::get("REST-CALLER-DELETE"),fmt::format(" {}", LoggingStr_.empty() ? URI.toString() : LoggingStr_ ) );
std::string Path(URI.getPathAndQuery());
Poco::Net::HTTPRequest Request(Poco::Net::HTTPRequest::HTTP_DELETE,
Path,
Poco::Net::HTTPMessage::HTTP_1_1);
if(BearerToken.empty()) {
Request.add("X-API-KEY", Svc.AccessKey);
Request.add("X-INTERNAL-NAME", MicroServicePublicEndPoint());
} else {
// Authorization: Bearer ${token}
Request.add("Authorization", "Bearer " + BearerToken);
}
if(Secure) {
Poco::Net::HTTPSClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
Session.receiveResponse(Response);
return Response.getStatus();
} else {
Poco::Net::HTTPClientSession Session(URI.getHost(), URI.getPort());
Session.setTimeout(Poco::Timespan(msTimeout_ / 1000, msTimeout_ % 1000));
Session.sendRequest(Request);
Poco::Net::HTTPResponse Response;
Session.receiveResponse(Response);
return Response.getStatus();
}
}
}
catch (const Poco::Exception &E)
{
Poco::Logger::get("REST-CALLER-DELETE").log(E);
}
return Poco::Net::HTTPServerResponse::HTTP_GATEWAY_TIMEOUT;
}
} // namespace OpenWifi

View File

@@ -0,0 +1,110 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include "Poco/JSON/Object.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "framework/OpenWifiTypes.h"
namespace OpenWifi {
class OpenAPIRequestGet {
public:
explicit OpenAPIRequestGet( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
std::string LoggingStr_;
};
class OpenAPIRequestPut {
public:
explicit OpenAPIRequestPut( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
const Poco::JSON::Object & Body,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
Body_(Body),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
Poco::JSON::Object Body_;
std::string LoggingStr_;
};
class OpenAPIRequestPost {
public:
explicit OpenAPIRequestPost( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
const Poco::JSON::Object & Body,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
Body_(Body),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(Poco::JSON::Object::Ptr &ResponseObject, const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
Poco::JSON::Object Body_;
std::string LoggingStr_;
};
class OpenAPIRequestDelete {
public:
explicit OpenAPIRequestDelete( const std::string & Type,
const std::string & EndPoint,
const Types::StringPairVec & QueryData,
uint64_t msTimeout,
const std::string &LoggingStr=""):
Type_(Type),
EndPoint_(EndPoint),
QueryData_(QueryData),
msTimeout_(msTimeout),
LoggingStr_(LoggingStr){};
Poco::Net::HTTPServerResponse::HTTPStatus Do(const std::string & BearerToken = "");
private:
std::string Type_;
std::string EndPoint_;
Types::StringPairVec QueryData_;
uint64_t msTimeout_;
Poco::JSON::Object Body_;
std::string LoggingStr_;
};
} // namespace OpenWifi

View File

@@ -28,6 +28,19 @@ namespace OpenWifi::Types {
typedef std::string UUID_t;
typedef std::vector<UUID_t> UUIDvec_t;
typedef std::map<std::string,std::map<uint32_t,uint64_t>> Counted3DMapSII;
struct MicroServiceMeta {
uint64_t Id=0;
std::string Type;
std::string PrivateEndPoint;
std::string PublicEndPoint;
std::string AccessKey;
std::string Version;
uint64_t LastUpdate=0;
};
typedef std::map<std::string, MicroServiceMeta> MicroServiceMetaMap;
typedef std::vector<MicroServiceMeta> MicroServiceMetaVec;
}
namespace OpenWifi {

View File

@@ -0,0 +1,27 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "framework/RESTAPI_ExtServer.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler *ExtRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &Request) {
try {
Poco::URI uri(Request.getURI());
auto TID = NextTransactionId_++;
Utils::SetThreadName(fmt::format("x-rest:{}",TID).c_str());
return RESTAPI_ExtServer()->CallServer(uri.getPath(), TID);
} catch (...) {
}
return nullptr;
}
Poco::Net::HTTPRequestHandler *RESTAPI_ExtServer::CallServer(const std::string &Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings;
Utils::SetThreadName(fmt::format("x-rest:{}",Id).c_str());
return RESTAPI_ExtRouter(Path, Bindings, Logger(), Server_, Id);
}
}

View File

@@ -0,0 +1,99 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "Poco/Net/HTTPServer.h"
#include "framework/SubSystemServer.h"
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_ExtRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t Id);
class ExtRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
ExtRequestHandlerFactory() = default;
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override;
private:
static inline std::atomic_uint64_t NextTransactionId_ = 1;
};
class RESTAPI_ExtServer : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new RESTAPI_ExtServer;
return instance_;
}
inline int Start() override {
poco_information(Logger(),"Starting.");
Server_.InitLogging();
for(const auto & Svr: ConfigServersList_) {
if(MicroServiceNoAPISecurity()) {
poco_information(Logger(),fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port()));
} else {
poco_information(Logger(),fmt::format("Starting: {}:{} Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(),
Svr.KeyFile(),Svr.CertFile()));
Svr.LogCert(Logger());
if (!Svr.RootCA().empty())
Svr.LogCas(Logger());
}
Poco::Net::HTTPServerParams::Ptr Params = new Poco::Net::HTTPServerParams;
Params->setKeepAlive(true);
Params->setName("ws:xrest");
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
if(MicroServiceNoAPISecurity()) {
auto Sock{Svr.CreateSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory, Pool_, Sock, Params);
} else {
auto Sock{Svr.CreateSecureSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new ExtRequestHandlerFactory, Pool_, Sock, Params);
};
NewServer->start();
RESTServers_.push_back(std::move(NewServer));
}
return 0;
}
inline void Stop() override {
poco_information(Logger(),"Stopping...");
for( const auto & svr : RESTServers_ )
svr->stopAll(true);
Pool_.stopAll();
Pool_.joinAll();
RESTServers_.clear();
poco_information(Logger(),"Stopped...");
}
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
MicroServiceLoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
Stop();
Start();
}
Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id);
const Poco::ThreadPool & Pool() { return Pool_; }
private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_{"x-rest",8,128};
RESTAPI_GenericServerAccounting Server_;
RESTAPI_ExtServer() noexcept:
SubSystemServer("RESTAPI_ExtServer", "REST-XSRV", "openwifi.restapi")
{
}
};
inline auto RESTAPI_ExtServer() { return RESTAPI_ExtServer::instance(); };
}

View File

@@ -1,299 +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 "Poco/JSON/Parser.h"
#include "Poco/JSON/Stringifier.h"
#include "Daemon.h"
#ifdef TIP_GATEWAY_SERVICE
#include "DeviceRegistry.h"
#include "CapabilitiesCache.h"
#endif
#include "RESTAPI_GWobjects.h"
#include "framework/MicroService.h"
using OpenWifi::RESTAPI_utils::field_to_json;
using OpenWifi::RESTAPI_utils::field_from_json;
using OpenWifi::RESTAPI_utils::EmbedDocument;
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", CapabilitiesCache::instance()->GetPlatform(Compatible));
#endif
field_to_json(Obj,"macAddress", MACAddress);
field_to_json(Obj,"manufacturer", Manufacturer);
field_to_json(Obj,"UUID", UUID);
EmbedDocument("configuration", Obj, Configuration);
field_to_json(Obj,"notes", Notes);
field_to_json(Obj,"createdTimestamp", CreationTimestamp);
field_to_json(Obj,"lastConfigurationChange", LastConfigurationChange);
field_to_json(Obj,"lastConfigurationDownload", LastConfigurationDownload);
field_to_json(Obj,"lastFWUpdate", LastFWUpdate);
field_to_json(Obj,"owner", Owner);
field_to_json(Obj,"location", Location);
field_to_json(Obj,"venue", Venue);
field_to_json(Obj,"firmware", Firmware);
field_to_json(Obj,"compatible", Compatible);
field_to_json(Obj,"fwUpdatePolicy", FWUpdatePolicy);
field_to_json(Obj,"devicePassword", DevicePassword);
field_to_json(Obj,"subscriber", subscriber);
field_to_json(Obj,"entity", entity);
field_to_json(Obj,"modified", modified);
field_to_json(Obj,"locale", locale);
}
void Device::to_json_with_status(Poco::JSON::Object &Obj) const {
to_json(Obj);
#ifdef TIP_GATEWAY_SERVICE
ConnectionState ConState;
if (DeviceRegistry()->GetState(SerialNumber, ConState)) {
ConState.to_json(Obj);
} else {
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", "");
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
}
bool Device::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",SerialNumber);
field_from_json(Obj,"deviceType",DeviceType);
field_from_json(Obj,"macAddress",MACAddress);
field_from_json(Obj,"configuration",Configuration);
field_from_json(Obj,"notes",Notes);
field_from_json(Obj,"manufacturer",Manufacturer);
field_from_json(Obj,"owner",Owner);
field_from_json(Obj,"location",Location);
field_from_json(Obj,"venue",Venue);
field_from_json(Obj,"compatible",Compatible);
field_from_json(Obj,"subscriber", subscriber);
field_from_json(Obj,"entity", entity);
field_from_json(Obj,"locale", locale);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void Device::Print() const {
std::cout << "Device: " << SerialNumber << " DeviceType:" << DeviceType << " MACAddress:" << MACAddress << " Manufacturer:"
<< Manufacturer << " " << Configuration << std::endl;
}
void Statistics::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("data", Obj, Data);
field_to_json(Obj,"UUID", UUID);
field_to_json(Obj,"recorded", Recorded);
}
void Capabilities::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("capabilities", Obj, Capabilities);
field_to_json(Obj,"firstUpdate", FirstUpdate);
field_to_json(Obj,"lastUpdate", LastUpdate);
}
void DeviceLog::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("data", Obj, Data);
field_to_json(Obj,"log", Log);
field_to_json(Obj,"severity", Severity);
field_to_json(Obj,"recorded", Recorded);
field_to_json(Obj,"logType", LogType);
field_to_json(Obj,"UUID", UUID);
}
void HealthCheck::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("values", Obj, Data);
field_to_json(Obj,"UUID", UUID);
field_to_json(Obj,"sanity", Sanity);
field_to_json(Obj,"recorded", Recorded);
}
void DefaultConfiguration::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("configuration", Obj, Configuration);
field_to_json(Obj,"name", Name);
field_to_json(Obj,"modelIds", Models);
field_to_json(Obj,"description", Description);
field_to_json(Obj,"created", Created);
field_to_json(Obj,"lastModified", LastModified);
}
void CommandDetails::to_json(Poco::JSON::Object &Obj) const {
EmbedDocument("details", Obj, Details);
EmbedDocument("results", Obj, Results);
field_to_json(Obj,"UUID", UUID);
field_to_json(Obj,"serialNumber", SerialNumber);
field_to_json(Obj,"command", Command);
field_to_json(Obj,"errorText", ErrorText);
field_to_json(Obj,"submittedBy", SubmittedBy);
field_to_json(Obj,"status", Status);
field_to_json(Obj,"submitted", Submitted);
field_to_json(Obj,"executed", Executed);
field_to_json(Obj,"completed", Completed);
field_to_json(Obj,"when", RunAt);
field_to_json(Obj,"errorCode", ErrorCode);
field_to_json(Obj,"custom", Custom);
field_to_json(Obj,"waitingForFile", WaitingForFile);
field_to_json(Obj,"attachFile", AttachDate);
field_to_json(Obj,"executionTime", executionTime);
}
bool DefaultConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"name",Name);
field_from_json(Obj,"configuration",Configuration);
field_from_json(Obj,"modelIds",Models);
field_from_json(Obj,"description",Description);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void BlackListedDevice::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", serialNumber);
field_to_json(Obj,"author", author);
field_to_json(Obj,"reason", reason);
field_to_json(Obj,"created", created);
}
bool BlackListedDevice::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"author",author);
field_from_json(Obj,"reason",reason);
field_from_json(Obj,"created",created);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
void ConnectionState::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"ipAddress", Address);
field_to_json(Obj,"txBytes", TX);
field_to_json(Obj,"rxBytes", RX);
field_to_json(Obj,"messageCount", MessageCount);
field_to_json(Obj,"UUID", UUID);
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);
field_to_json(Obj,"webSocketClients", webSocketClients);
field_to_json(Obj,"websocketPackets", websocketPackets);
field_to_json(Obj,"kafkaClients", kafkaClients);
field_to_json(Obj,"kafkaPackets", kafkaPackets);
field_to_json(Obj,"locale", locale);
switch(VerifiedCertificate) {
case NO_CERTIFICATE:
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break;
case VALID_CERTIFICATE:
field_to_json(Obj,"verifiedCertificate", "VALID_CERTIFICATE"); break;
case MISMATCH_SERIAL:
field_to_json(Obj,"verifiedCertificate", "MISMATCH_SERIAL"); break;
case VERIFIED:
field_to_json(Obj,"verifiedCertificate", "VERIFIED"); break;
default:
field_to_json(Obj,"verifiedCertificate", "NO_CERTIFICATE"); break;
}
}
void RttySessionDetails::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber", SerialNumber);
field_to_json(Obj,"server", Server);
field_to_json(Obj,"port", Port);
field_to_json(Obj,"token",Token);
field_to_json(Obj,"timeout", TimeOut);
field_to_json(Obj,"connectionId",ConnectionId);
field_to_json(Obj,"commandUUID",CommandUUID);
field_to_json(Obj,"started", Started);
field_to_json(Obj,"viewport",ViewPort);
field_to_json(Obj,"password",DevicePassword);
}
void Dashboard::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"commands",commands);
field_to_json(Obj,"upTimes",upTimes);
field_to_json(Obj,"memoryUsed",memoryUsed);
field_to_json(Obj,"load1",load1);
field_to_json(Obj,"load5",load5);
field_to_json(Obj,"load15",load15);
field_to_json(Obj,"vendors",vendors);
field_to_json(Obj,"status",status);
field_to_json(Obj,"deviceType",deviceType);
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() {
commands.clear();
upTimes.clear();
memoryUsed.clear();
load1.clear();
load5.clear();
load15.clear();
vendors.clear();
status.clear();
deviceType.clear();
healths.clear();
certificates.clear();
lastContact.clear();
associations.clear();
numberOfDevices = 0 ;
snapshot = OpenWifi::Now();
}
void CapabilitiesModel::to_json(Poco::JSON::Object &Obj) const{
field_to_json(Obj,"deviceType", deviceType);
field_to_json(Obj,"capabilities", capabilities);
};
void ScriptRequest::to_json(Poco::JSON::Object &Obj) const {
field_to_json(Obj,"serialNumber",serialNumber);
field_to_json(Obj,"timeout",timeout);
field_to_json(Obj,"type",type);
field_to_json(Obj,"script",script);
field_to_json(Obj,"scriptId",scriptId);
field_to_json(Obj,"when",when);
}
bool ScriptRequest::from_json(const Poco::JSON::Object::Ptr &Obj) {
try {
field_from_json(Obj,"serialNumber",serialNumber);
field_from_json(Obj,"timeout",timeout);
field_from_json(Obj,"type",type);
field_from_json(Obj,"script",script);
field_from_json(Obj,"scriptId",scriptId);
field_from_json(Obj,"when",when);
return true;
} catch (const Poco::Exception &E) {
}
return false;
}
}

View File

@@ -1,213 +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.
//
#pragma once
#include "Poco/JSON/Object.h"
#include "RESTAPI_SecurityObjects.h"
namespace OpenWifi::GWObjects {
enum CertificateValidation {
NO_CERTIFICATE,
VALID_CERTIFICATE,
MISMATCH_SERIAL,
VERIFIED
};
struct ConnectionState {
uint64_t MessageCount = 0 ;
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;
CertificateValidation VerifiedCertificate = NO_CERTIFICATE;
std::string Compatible;
uint64_t kafkaClients=0;
uint64_t webSocketClients=0;
uint64_t kafkaPackets=0;
uint64_t websocketPackets=0;
std::string locale;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Device {
std::string SerialNumber;
std::string DeviceType;
std::string MACAddress;
std::string Manufacturer;
std::string Configuration;
SecurityObjects::NoteInfoVec Notes;
std::string Owner;
std::string Location;
std::string Firmware;
std::string Compatible;
std::string FWUpdatePolicy;
uint64_t UUID = 0 ;
uint64_t CreationTimestamp = 0 ;
uint64_t LastConfigurationChange = 0 ;
uint64_t LastConfigurationDownload = 0 ;
uint64_t LastFWUpdate = 0 ;
std::string Venue;
std::string DevicePassword;
std::string subscriber;
std::string entity;
uint64_t modified=0;
std::string locale;
void to_json(Poco::JSON::Object &Obj) const;
void to_json_with_status(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
void Print() const;
};
struct Statistics {
std::string SerialNumber;
uint64_t UUID = 0 ;
std::string Data;
uint64_t Recorded = 0;
void to_json(Poco::JSON::Object &Obj) const;
};
struct HealthCheck {
std::string SerialNumber;
uint64_t UUID = 0 ;
std::string Data;
uint64_t Recorded = 0 ;
uint64_t Sanity = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Capabilities {
std::string Capabilities;
uint64_t FirstUpdate = 0 ;
uint64_t LastUpdate = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
};
struct DeviceLog {
enum Level {
LOG_EMERG = 0, /* system is unusable */
LOG_ALERT = 1, /* action must be taken immediately */
LOG_CRIT = 2, /* critical conditions */
LOG_ERR = 3, /* error conditions */
LOG_WARNING = 4, /* warning conditions */
LOG_NOTICE = 5, /* normal but significant condition */
LOG_INFO = 6, /* informational */
LOG_DEBUG = 7 /* debug-level messages */
};
std::string SerialNumber;
std::string Log;
std::string Data;
uint64_t Severity = 0 ;
uint64_t Recorded = 0 ;
uint64_t LogType = 0 ;
uint64_t UUID = 0 ;
void to_json(Poco::JSON::Object &Obj) const;
};
struct DefaultConfiguration {
std::string Name;
std::string Configuration;
Types::StringVec Models;
std::string Description;
uint64_t Created;
uint64_t LastModified;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct CommandDetails {
std::string UUID;
std::string SerialNumber;
std::string Command;
std::string Status;
std::string SubmittedBy;
std::string Results;
std::string Details;
std::string ErrorText;
uint64_t Submitted = time(nullptr);
uint64_t Executed = 0;
uint64_t Completed = 0 ;
uint64_t RunAt = 0 ;
uint64_t ErrorCode = 0 ;
uint64_t Custom = 0 ;
uint64_t WaitingForFile = 0 ;
uint64_t AttachDate = 0 ;
uint64_t AttachSize = 0 ;
std::string AttachType;
double executionTime = 0.0;
void to_json(Poco::JSON::Object &Obj) const;
};
struct BlackListedDevice {
std::string serialNumber;
std::string reason;
std::string author;
uint64_t created;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
struct RttySessionDetails {
std::string SerialNumber;
std::string Server;
uint64_t Port = 0 ;
std::string Token;
uint64_t TimeOut = 0 ;
std::string ConnectionId;
uint64_t Started = 0 ;
std::string CommandUUID;
uint64_t ViewPort = 0 ;
std::string DevicePassword;
void to_json(Poco::JSON::Object &Obj) const;
};
struct Dashboard {
uint64_t snapshot = 0 ;
uint64_t numberOfDevices = 0 ;
Types::CountedMap commands;
Types::CountedMap upTimes;
Types::CountedMap memoryUsed;
Types::CountedMap load1;
Types::CountedMap load5;
Types::CountedMap load15;
Types::CountedMap vendors;
Types::CountedMap status;
Types::CountedMap deviceType;
Types::CountedMap healths;
Types::CountedMap certificates;
Types::CountedMap lastContact;
Types::CountedMap associations;
void to_json(Poco::JSON::Object &Obj) const;
void reset();
};
struct CapabilitiesModel {
std::string deviceType;
std::string capabilities;
void to_json(Poco::JSON::Object &Obj) const;
};
struct ScriptRequest {
uint64_t timeout=30;
std::string serialNumber;
std::string type;
std::string script;
std::string scriptId;
uint64_t when=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
}

View File

@@ -0,0 +1,75 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <array>
#include "Poco/StringTokenizer.h"
#include "Poco/String.h"
#include "Poco/Net/HTTPRequest.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
class RESTAPI_GenericServerAccounting {
public:
enum {
LOG_GET=0,
LOG_DELETE,
LOG_PUT,
LOG_POST
};
void inline SetFlags(bool External, const std::string &Methods) {
Poco::StringTokenizer Tokens(Methods,",");
auto Offset = (External ? 0 : 4);
for(const auto &i:Tokens) {
if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_DELETE)==0)
LogFlags_[Offset+LOG_DELETE]=true;
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_PUT)==0)
LogFlags_[Offset+LOG_PUT]=true;
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_POST)==0)
LogFlags_[Offset+LOG_POST]=true;
else if(Poco::icompare(i,Poco::Net::HTTPRequest::HTTP_GET)==0)
LogFlags_[Offset+LOG_GET]=true;
}
}
inline void InitLogging() {
std::string Public = MicroServiceConfigGetString("apilogging.public.methods","PUT,POST,DELETE");
SetFlags(true, Public);
std::string Private = MicroServiceConfigGetString("apilogging.private.methods","PUT,POST,DELETE");
SetFlags(false, Private);
std::string PublicBadTokens = MicroServiceConfigGetString("apilogging.public.badtokens.methods","");
LogBadTokens_[0] = (Poco::icompare(PublicBadTokens,"true")==0);
std::string PrivateBadTokens = MicroServiceConfigGetString("apilogging.private.badtokens.methods","");
LogBadTokens_[1] = (Poco::icompare(PrivateBadTokens,"true")==0);
}
[[nodiscard]] inline bool LogIt(const std::string &Method, bool External) const {
auto Offset = (External ? 0 : 4);
if(Method == Poco::Net::HTTPRequest::HTTP_GET)
return LogFlags_[Offset+LOG_GET];
if(Method == Poco::Net::HTTPRequest::HTTP_POST)
return LogFlags_[Offset+LOG_POST];
if(Method == Poco::Net::HTTPRequest::HTTP_PUT)
return LogFlags_[Offset+LOG_PUT];
if(Method == Poco::Net::HTTPRequest::HTTP_DELETE)
return LogFlags_[Offset+LOG_DELETE];
return false;
};
[[nodiscard]] inline bool LogBadTokens(bool External) const {
return LogBadTokens_[ (External ? 0 : 1) ];
};
private:
std::array<bool,8> LogFlags_{false};
std::array<bool,2> LogBadTokens_{false};
};
}

View File

@@ -0,0 +1,8 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "RESTAPI_Handler.h"
namespace OpenWifi {
} // namespace OpenWifi

View File

@@ -0,0 +1,826 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include <string>
#include <vector>
#include <map>
#include "Poco/Net/HTTPRequestHandler.h"
#include "Poco/Logger.h"
#include "Poco/JSON/Object.h"
#include "Poco/JSON/Parser.h"
#include "Poco/Net/HTTPResponse.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/DeflatingStream.h"
#include "Poco/TemporaryFile.h"
#include "Poco/Net/OAuth20Credentials.h"
#include "framework/ow_constants.h"
#include "framework/RESTAPI_GenericServerAccounting.h"
#include "framework/RESTAPI_RateLimiter.h"
#include "framework/utils.h"
#include "framework/RESTAPI_utils.h"
#include "framework/AuthClient.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#if defined(TIP_SECURITY_SERVICE)
#include "AuthService.h"
#endif
using namespace std::chrono_literals;
namespace OpenWifi {
class RESTAPIHandler : public Poco::Net::HTTPRequestHandler {
public:
struct QueryBlock {
uint64_t StartDate = 0 , EndDate = 0 , Offset = 0 , Limit = 0, LogType = 0 ;
std::string SerialNumber, Filter;
std::vector<std::string> Select;
bool Lifetime=false, LastOnly=false, Newest=false, CountOnly=false, AdditionalInfo=false;
};
typedef std::map<std::string, std::string> BindingMap;
struct RateLimit {
int64_t Interval=1000;
int64_t MaxCalls=10;
};
RESTAPIHandler( BindingMap map,
Poco::Logger &l,
std::vector<std::string> Methods,
RESTAPI_GenericServerAccounting & Server,
uint64_t TransactionId,
bool Internal,
bool AlwaysAuthorize=true,
bool RateLimited=false,
const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100},
bool SubscriberOnly=false)
: Bindings_(std::move(map)),
Logger_(l),
Methods_(std::move(Methods)),
Internal_(Internal),
RateLimited_(RateLimited),
SubOnlyService_(SubscriberOnly),
AlwaysAuthorize_(AlwaysAuthorize),
Server_(Server),
MyRates_(Profile),
TransactionId_(TransactionId)
{
}
inline bool RoleIsAuthorized([[maybe_unused]] const std::string & Path, [[maybe_unused]] const std::string & Method, [[maybe_unused]] std::string & Reason) {
return true;
}
inline void handleRequest(Poco::Net::HTTPServerRequest &RequestIn,
Poco::Net::HTTPServerResponse &ResponseIn) final {
try {
Request = &RequestIn;
Response = &ResponseIn;
// std::string th_name = "restsvr_" + std::to_string(TransactionId_);
// Utils::SetThreadName(th_name.c_str());
if(Request->getContentLength()>0) {
if(Request->getContentType().find("application/json")!=std::string::npos) {
ParsedBody_ = IncomingParser_.parse(Request->stream()).extract<Poco::JSON::Object::Ptr>();
}
}
if(RateLimited_ && RESTAPI_RateLimiter()->IsRateLimited(RequestIn,MyRates_.Interval, MyRates_.MaxCalls)) {
return UnAuthorized(RESTAPI::Errors::RATE_LIMIT_EXCEEDED);
}
if (!ContinueProcessing())
return;
bool Expired=false, Contacted=false;
if (AlwaysAuthorize_ && !IsAuthorized(Expired, Contacted, SubOnlyService_)) {
if(Expired)
return UnAuthorized(RESTAPI::Errors::EXPIRED_TOKEN);
if(Contacted)
return UnAuthorized(RESTAPI::Errors::INVALID_TOKEN);
else
return UnAuthorized(RESTAPI::Errors::SECURITY_SERVICE_UNREACHABLE);
}
std::string Reason;
if(!RoleIsAuthorized(RequestIn.getURI(), Request->getMethod(), Reason)) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
ParseParameters();
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_GET)
return DoGet();
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
return DoPost();
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_DELETE)
return DoDelete();
else if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_PUT)
return DoPut();
return BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
} catch (const Poco::Exception &E) {
Logger_.log(E);
return BadRequest(RESTAPI::Errors::InternalError);
}
}
[[nodiscard]] inline bool NeedAdditionalInfo() const { return QB_.AdditionalInfo; }
[[nodiscard]] inline const std::vector<std::string> & SelectedRecords() const { return QB_.Select; }
inline static bool ParseBindings(const std::string & Request, const std::list<std::string> & EndPoints, BindingMap &bindings) {
bindings.clear();
auto PathItems = Poco::StringTokenizer(Request, "/");
for(const auto &EndPoint:EndPoints) {
auto ParamItems = Poco::StringTokenizer(EndPoint, "/");
if (PathItems.count() != ParamItems.count())
continue;
bool Matched = true;
for (size_t i = 0; i < PathItems.count(); i++) {
if (PathItems[i] != ParamItems[i]) {
if (ParamItems[i][0] == '{') {
auto ParamName = ParamItems[i].substr(1, ParamItems[i].size() - 2);
bindings[Poco::toLower(ParamName)] = PathItems[i];
} else {
Matched = false;
break;
}
}
}
if(Matched)
return true;
}
return false;
}
inline void PrintBindings() {
for (const auto &[key, value] : Bindings_)
std::cout << "Key = " << key << " Value= " << value << std::endl;
}
inline void ParseParameters() {
Poco::URI uri(Request->getURI());
Parameters_ = uri.getQueryParameters();
InitQueryBlock();
}
inline static bool is_number(const std::string &s) {
return !s.empty() && std::all_of(s.begin(), s.end(), ::isdigit);
}
inline static bool is_bool(const std::string &s) {
if (s == "true" || s == "false")
return true;
return false;
}
[[nodiscard]] inline uint64_t GetParameter(const std::string &Name, const uint64_t Default) {
auto Hint = std::find_if(Parameters_.begin(),Parameters_.end(),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==Parameters_.end() || !is_number(Hint->second))
return Default;
return std::stoull(Hint->second);
}
[[nodiscard]] inline bool GetBoolParameter(const std::string &Name, bool Default=false) {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_) || !is_bool(Hint->second))
return Default;
return Hint->second=="true";
}
[[nodiscard]] inline std::string GetParameter(const std::string &Name, const std::string &Default="") {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_))
return Default;
return Hint->second;
}
[[nodiscard]] inline bool HasParameter(const std::string &Name, std::string &Value) {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_))
return false;
Value = Hint->second;
return true;
}
[[nodiscard]] inline bool HasParameter(const std::string &Name, uint64_t & Value) {
auto Hint = std::find_if(begin(Parameters_),end(Parameters_),[&](const std::pair<std::string,std::string> &S){ return S.first==Name; });
if(Hint==end(Parameters_))
return false;
Value = std::stoull(Hint->second);
return true;
}
[[nodiscard]] inline const std::string & GetBinding(const std::string &Name, const std::string &Default="") {
auto E = Bindings_.find(Poco::toLower(Name));
if (E == Bindings_.end())
return Default;
return E->second;
}
[[nodiscard]] inline static std::string MakeList(const std::vector<std::string> &L) {
std::string Return;
for (const auto &i : L) {
if (Return.empty())
Return = i;
else
Return += ", " + i;
}
return Return;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Types::UUIDvec_t & Value) {
if(O->has(Field) && O->isArray(Field)) {
auto Arr = O->getArray(Field);
for(const auto &i:*Arr)
Value.emplace_back(i.toString());
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, std::string &Value) {
if(O->has(Field)) {
Value = O->get(Field).toString();
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, uint64_t &Value) {
if(O->has(Field)) {
Value = O->get(Field);
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, bool &Value) {
if(O->has(Field)) {
Value = O->get(Field).toString()=="true";
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, double &Value) {
if(O->has(Field)) {
Value = (double) O->get(Field);
return true;
}
return false;
}
static inline bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, Poco::Data::BLOB &Value) {
if(O->has(Field)) {
std::string Content = O->get(Field).toString();
auto DecodedBlob = Utils::base64decode(Content);
Value.assignRaw((const unsigned char *)&DecodedBlob[0],DecodedBlob.size());
return true;
}
return false;
}
template <typename T> bool AssignIfPresent(const Poco::JSON::Object::Ptr &O, const std::string &Field, const T &value, T & assignee) {
if(O->has(Field)) {
assignee = value;
return true;
}
return false;
}
inline void SetCommonHeaders(bool CloseConnection=false) {
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
Response->setChunkedTransferEncoding(true);
Response->setContentType("application/json");
auto Origin = Request->find("Origin");
if (Origin != Request->end()) {
Response->set("Access-Control-Allow-Origin", Origin->second);
} else {
Response->set("Access-Control-Allow-Origin", "*");
}
Response->set("Vary", "Origin, Accept-Encoding");
if(CloseConnection) {
Response->set("Connection", "close");
Response->setKeepAlive(false);
} else {
Response->setKeepAlive(true);
Response->set("Connection", "Keep-Alive");
Response->set("Keep-Alive", "timeout=30, max=1000");
}
}
inline void ProcessOptions() {
Response->setVersion(Poco::Net::HTTPMessage::HTTP_1_1);
Response->setChunkedTransferEncoding(true);
auto Origin = Request->find("Origin");
if (Origin != Request->end()) {
Response->set("Access-Control-Allow-Origin", Origin->second);
} else {
Response->set("Access-Control-Allow-Origin", "*");
}
Response->set("Access-Control-Allow-Methods", MakeList(Methods_));
auto RequestHeaders = Request->find("Access-Control-Request-Headers");
if(RequestHeaders!=Request->end())
Response->set("Access-Control-Allow-Headers", RequestHeaders->second);
Response->set("Vary", "Origin, Accept-Encoding");
Response->set("Access-Control-Allow-Credentials", "true");
Response->set("Access-Control-Max-Age", "86400");
Response->set("Connection", "Keep-Alive");
Response->set("Keep-Alive", "timeout=30, max=1000");
Response->setContentLength(0);
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
Response->send();
}
inline void PrepareResponse(Poco::Net::HTTPResponse::HTTPStatus Status = Poco::Net::HTTPResponse::HTTP_OK,
bool CloseConnection = false) {
Response->setStatus(Status);
SetCommonHeaders(CloseConnection);
}
inline void BadRequest(const OpenWifi::RESTAPI::Errors::msg &E, const std::string & Extra="") {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",400);
ErrorObject.set("ErrorDetails",Request->getMethod());
if(Extra.empty())
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
else
ErrorObject.set("ErrorDescription",fmt::format("{}: {} ({})",E.err_num,E.err_txt, Extra)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
inline void InternalError(const OpenWifi::RESTAPI::Errors::msg &E) {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",500);
ErrorObject.set("ErrorDetails",Request->getMethod());
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
inline void UnAuthorized(const OpenWifi::RESTAPI::Errors::msg &E) {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_FORBIDDEN);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",E.err_num);
ErrorObject.set("ErrorDetails",Request->getMethod());
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
inline void NotFound() {
PrepareResponse(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
Poco::JSON::Object ErrorObject;
ErrorObject.set("ErrorCode",404);
ErrorObject.set("ErrorDetails",Request->getMethod());
const auto & E = OpenWifi::RESTAPI::Errors::Error404;
ErrorObject.set("ErrorDescription",fmt::format("{}: {}",E.err_num,E.err_txt)) ;
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
poco_debug(Logger_,fmt::format("RES-NOTFOUND: User='{}@{}' Method='{}' Path='{}",
Requester(),
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->getMethod(),
Request->getURI()));
}
inline void OK() {
PrepareResponse();
if( Request->getMethod()==Poco::Net::HTTPRequest::HTTP_DELETE ||
Request->getMethod()==Poco::Net::HTTPRequest::HTTP_OPTIONS) {
Response->send();
} else {
Poco::JSON::Object ErrorObject;
ErrorObject.set("Code", 0);
ErrorObject.set("Operation", Request->getMethod());
ErrorObject.set("Details", "Command completed.");
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(ErrorObject, Answer);
}
}
inline void SendCompressedTarFile(const std::string & FileName, const std::string & Content) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Response->set("Content-Type","application/gzip");
Response->set("Content-Disposition", "attachment; filename=" + FileName );
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setStatus(Poco::Net::HTTPResponse::HTTP_OK);
Response->setContentLength(Content.size());
Response->setChunkedTransferEncoding(true);
std::ostream& OutputStream = Response->send();
OutputStream << Content;
}
inline void SendFile(Poco::File & File, const std::string & UUID) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Response->set("Content-Type","application/octet-stream");
Response->set("Content-Disposition", "attachment; filename=" + UUID );
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(File.getSize());
Response->sendFile(File.path(),"application/octet-stream");
}
inline void SendFile(Poco::File & File) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Poco::Path P(File.path());
auto MT = Utils::FindMediaType(File);
if(MT.Encoding==Utils::BINARY) {
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->sendFile(File.path(),MT.ContentType);
}
inline void SendFile(Poco::TemporaryFile &TempAvatar, [[maybe_unused]] const std::string &Type, const std::string & Name) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
auto MT = Utils::FindMediaType(Name);
if(MT.Encoding==Utils::BINARY) {
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Content-Disposition", "attachment; filename=" + Name );
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(TempAvatar.getSize());
Response->sendFile(TempAvatar.path(),MT.ContentType);
}
inline void SendFileContent(const std::string &Content, const std::string &Type, const std::string & Name) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
auto MT = Utils::FindMediaType(Name);
if(MT.Encoding==Utils::BINARY) {
Response->set("Content-Transfer-Encoding","binary");
Response->set("Accept-Ranges", "bytes");
}
Response->set("Content-Disposition", "attachment; filename=" + Name );
Response->set("Accept-Ranges", "bytes");
Response->set("Cache-Control", "no-store");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
Response->setContentLength(Content.size());
Response->setContentType(Type );
auto & OutputStream = Response->send();
OutputStream << Content ;
}
inline void SendHTMLFileBack(Poco::File & File,
const Types::StringPairVec & FormVars) {
Response->setStatus(Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK);
SetCommonHeaders();
Response->set("Pragma", "private");
Response->set("Expires", "Mon, 26 Jul 2027 05:00:00 GMT");
std::string FormContent = Utils::LoadFile(File.path());
Utils::ReplaceVariables(FormContent, FormVars);
Response->setContentLength(FormContent.size());
Response->setChunkedTransferEncoding(true);
Response->setContentType("text/html");
std::ostream& ostr = Response->send();
ostr << FormContent;
}
inline void ReturnStatus(Poco::Net::HTTPResponse::HTTPStatus Status, bool CloseConnection=false) {
PrepareResponse(Status, CloseConnection);
if(Status == Poco::Net::HTTPResponse::HTTP_NO_CONTENT) {
Response->setContentLength(0);
Response->erase("Content-Type");
Response->setChunkedTransferEncoding(false);
}
Response->send();
}
inline bool ContinueProcessing() {
if (Request->getMethod() == Poco::Net::HTTPRequest::HTTP_OPTIONS) {
ProcessOptions();
return false;
} else if (std::find(Methods_.begin(), Methods_.end(), Request->getMethod()) == Methods_.end()) {
BadRequest(RESTAPI::Errors::UnsupportedHTTPMethod);
return false;
}
return true;
}
inline bool IsAuthorized(bool & Expired, bool & Contacted, bool SubOnly = false );
inline void ReturnObject(Poco::JSON::Object &Object) {
PrepareResponse();
if(Request!= nullptr) {
// can we compress ???
auto AcceptedEncoding = Request->find("Accept-Encoding");
if(AcceptedEncoding!=Request->end()) {
if( AcceptedEncoding->second.find("gzip")!=std::string::npos ||
AcceptedEncoding->second.find("compress")!=std::string::npos) {
Response->set("Content-Encoding", "gzip");
std::ostream &Answer = Response->send();
Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP);
Poco::JSON::Stringifier::stringify(Object, deflater);
deflater.close();
return;
}
}
}
std::ostream &Answer = Response->send();
Poco::JSON::Stringifier::stringify(Object, Answer);
}
inline void ReturnRawJSON(const std::string &json_doc) {
PrepareResponse();
if(Request!= nullptr) {
// can we compress ???
auto AcceptedEncoding = Request->find("Accept-Encoding");
if(AcceptedEncoding!=Request->end()) {
if( AcceptedEncoding->second.find("gzip")!=std::string::npos ||
AcceptedEncoding->second.find("compress")!=std::string::npos) {
Response->set("Content-Encoding", "gzip");
std::ostream &Answer = Response->send();
Poco::DeflatingOutputStream deflater(Answer, Poco::DeflatingStreamBuf::STREAM_GZIP);
deflater << json_doc;
deflater.close();
return;
}
}
}
std::ostream &Answer = Response->send();
Answer << json_doc;
}
inline void ReturnCountOnly(uint64_t Count) {
Poco::JSON::Object Answer;
Answer.set("count", Count);
ReturnObject(Answer);
}
inline bool InitQueryBlock() {
if(QueryBlockInitialized_)
return true;
QueryBlockInitialized_=true;
QB_.SerialNumber = GetParameter(RESTAPI::Protocol::SERIALNUMBER, "");
QB_.StartDate = GetParameter(RESTAPI::Protocol::STARTDATE, 0);
QB_.EndDate = GetParameter(RESTAPI::Protocol::ENDDATE, 0);
QB_.Offset = GetParameter(RESTAPI::Protocol::OFFSET, 0);
QB_.Limit = GetParameter(RESTAPI::Protocol::LIMIT, 100);
QB_.Filter = GetParameter(RESTAPI::Protocol::FILTER, "");
QB_.Lifetime = GetBoolParameter(RESTAPI::Protocol::LIFETIME,false);
QB_.LogType = GetParameter(RESTAPI::Protocol::LOGTYPE,0);
QB_.LastOnly = GetBoolParameter(RESTAPI::Protocol::LASTONLY,false);
QB_.Newest = GetBoolParameter(RESTAPI::Protocol::NEWEST,false);
QB_.CountOnly = GetBoolParameter(RESTAPI::Protocol::COUNTONLY,false);
QB_.AdditionalInfo = GetBoolParameter(RESTAPI::Protocol::WITHEXTENDEDINFO,false);
auto RawSelect = GetParameter(RESTAPI::Protocol::SELECT, "");
auto Entries = Poco::StringTokenizer(RawSelect,",");
for(const auto &i:Entries) {
QB_.Select.emplace_back(i);
}
if(QB_.Offset<1)
QB_.Offset=0;
return true;
}
[[nodiscard]] inline uint64_t Get(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, uint64_t Default=0){
if(Obj->has(Parameter))
return Obj->get(Parameter);
return Default;
}
[[nodiscard]] inline std::string GetS(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, const std::string & Default=""){
if(Obj->has(Parameter))
return Obj->get(Parameter).toString();
return Default;
}
[[nodiscard]] inline bool GetB(const char *Parameter,const Poco::JSON::Object::Ptr &Obj, bool Default=false){
if(Obj->has(Parameter))
return Obj->get(Parameter).toString()=="true";
return Default;
}
[[nodiscard]] inline uint64_t GetWhen(const Poco::JSON::Object::Ptr &Obj) {
return RESTAPIHandler::Get(RESTAPI::Protocol::WHEN, Obj);
}
template<typename T> void ReturnObject(const char *Name, const std::vector<T> & Objects) {
Poco::JSON::Object Answer;
RESTAPI_utils::field_to_json(Answer,Name,Objects);
ReturnObject(Answer);
}
template<typename T> void Object(const char *Name, const std::vector<T> & Objects) {
Poco::JSON::Object Answer;
RESTAPI_utils::field_to_json(Answer,Name,Objects);
ReturnObject(Answer);
}
template <typename T> void Object(const T &O) {
Poco::JSON::Object Answer;
O.to_json(Answer);
ReturnObject(Answer);
}
Poco::Logger & Logger() { return Logger_; }
virtual void DoGet() = 0 ;
virtual void DoDelete() = 0 ;
virtual void DoPost() = 0 ;
virtual void DoPut() = 0 ;
Poco::Net::HTTPServerRequest *Request= nullptr;
Poco::Net::HTTPServerResponse *Response= nullptr;
SecurityObjects::UserInfoAndPolicy UserInfo_;
QueryBlock QB_;
const std::string & Requester() const { return REST_Requester_; }
protected:
BindingMap Bindings_;
Poco::URI::QueryParameters Parameters_;
Poco::Logger &Logger_;
std::string SessionToken_;
std::vector<std::string> Methods_;
bool Internal_=false;
bool RateLimited_=false;
bool QueryBlockInitialized_=false;
bool SubOnlyService_=false;
bool AlwaysAuthorize_=true;
Poco::JSON::Parser IncomingParser_;
RESTAPI_GenericServerAccounting & Server_;
RateLimit MyRates_;
uint64_t TransactionId_;
Poco::JSON::Object::Ptr ParsedBody_;
std::string REST_Requester_;
};
#ifdef TIP_SECURITY_SERVICE
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken,
SecurityObjects::UserInfoAndPolicy & UInfo, std::uint64_t TID, bool & Expired , bool Sub );
#endif
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , [[maybe_unused]] bool & Contacted , bool Sub ) {
if(Internal_ && Request->has("X-INTERNAL-NAME")) {
auto Allowed = MicroServiceIsValidAPIKEY(*Request);
Contacted = true;
if(!Allowed) {
if(Server_.LogBadTokens(false)) {
poco_debug(Logger_,fmt::format("I-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(), Request->getURI()));
}
} else {
auto Id = Request->get("X-INTERNAL-NAME", "unknown");
REST_Requester_ = Id;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("I-REQ-ALLOWED({}): TID={} User='{}' Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Id,
Request->getMethod(), Request->getURI()));
}
}
return Allowed;
} else if(!Internal_ && Request->has("X-API-KEY")) {
SessionToken_ = Request->get("X-API-KEY", "");
#ifdef TIP_SECURITY_SERVICE
std::uint64_t expiresOn;
if (AuthService()->IsValidApiKey(SessionToken_, UserInfo_.webtoken, UserInfo_.userinfo, Expired, expiresOn)) {
#else
if (AuthClient()->IsValidApiKey( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted)) {
#endif
REST_Requester_ = UserInfo_.userinfo.email;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): APIKEY-ACCESS TID={} User='{}@{}' Method={} Path={}",
UserInfo_.userinfo.email,
TransactionId_,
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->clientAddress().toString(),
Request->getMethod(),
Request->getURI()));
}
return true;
} else {
if(Server_.LogBadTokens(true)) {
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(),
Request->getURI()));
}
}
return false;
} else {
if (SessionToken_.empty()) {
try {
Poco::Net::OAuth20Credentials Auth(*Request);
if (Auth.getScheme() == "Bearer") {
SessionToken_ = Auth.getBearerToken();
}
} catch (const Poco::Exception &E) {
Logger_.log(E);
}
}
#ifdef TIP_SECURITY_SERVICE
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, TransactionId_, Expired, Sub)) {
#else
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, TransactionId_, Expired, Contacted, Sub)) {
#endif
REST_Requester_ = UserInfo_.userinfo.email;
if(Server_.LogIt(Request->getMethod(),true)) {
poco_debug(Logger_,fmt::format("X-REQ-ALLOWED({}): TID={} User='{}@{}' Method={} Path={}",
UserInfo_.userinfo.email,
TransactionId_,
Utils::FormatIPv6(Request->clientAddress().toString()),
Request->clientAddress().toString(),
Request->getMethod(),
Request->getURI()));
}
return true;
} else {
if(Server_.LogBadTokens(true)) {
poco_debug(Logger_,fmt::format("X-REQ-DENIED({}): TID={} Method={} Path={}",
Utils::FormatIPv6(Request->clientAddress().toString()),
TransactionId_,
Request->getMethod(),
Request->getURI()));
}
}
return false;
}
}
class RESTAPI_UnknownRequestHandler : public RESTAPIHandler {
public:
RESTAPI_UnknownRequestHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L, std::vector<std::string>{}, Server, TransactionId, Internal) {}
inline void DoGet() override {};
inline void DoPost() override {};
inline void DoPut() override {};
inline void DoDelete() override {};
};
template<class T>
constexpr auto test_has_PathName_method(T*)
-> decltype( T::PathName() , std::true_type{} )
{
return std::true_type{};
}
constexpr auto test_has_PathName_method(...) -> std::false_type
{
return std::false_type{};
}
template<typename T, typename... Args>
RESTAPIHandler * RESTAPI_Router(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & Logger, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId) {
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
return new T(Bindings, Logger, Server, TransactionId, false);
}
if constexpr (sizeof...(Args) == 0) {
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, false);
} else {
return RESTAPI_Router<Args...>(RequestedPath, Bindings, Logger, Server, TransactionId);
}
}
template<typename T, typename... Args>
RESTAPIHandler * RESTAPI_Router_I(const std::string & RequestedPath, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & Logger, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId) {
static_assert(test_has_PathName_method((T*)nullptr), "Class must have a static PathName() method.");
if(RESTAPIHandler::ParseBindings(RequestedPath,T::PathName(),Bindings)) {
return new T(Bindings, Logger, Server, TransactionId, true );
}
if constexpr (sizeof...(Args) == 0) {
return new RESTAPI_UnknownRequestHandler(Bindings,Logger, Server, TransactionId, true);
} else {
return RESTAPI_Router_I<Args...>(RequestedPath, Bindings, Logger, Server, TransactionId);
}
}
} // namespace OpenWifi

View File

@@ -0,0 +1,17 @@
//
// Created by stephane bourque on 2022-10-25.
//
#include "RESTAPI_IntServer.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler *
IntRequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest &Request) {
auto TID = NextTransactionId_++;
Utils::SetThreadName(fmt::format("i-rest:{}", TID).c_str());
Poco::URI uri(Request.getURI());
return RESTAPI_IntServer()->CallServer(uri.getPath(), TID);
}
} // namespace OpenWifi

View File

@@ -0,0 +1,104 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "Poco/Net/HTTPServer.h"
#include "framework/SubSystemServer.h"
#include "framework/RESTAPI_Handler.h"
namespace OpenWifi {
Poco::Net::HTTPRequestHandler * RESTAPI_IntRouter(const std::string &Path, RESTAPIHandler::BindingMap &Bindings,
Poco::Logger & L, RESTAPI_GenericServerAccounting & S, uint64_t Id);
class IntRequestHandlerFactory : public Poco::Net::HTTPRequestHandlerFactory {
public:
inline IntRequestHandlerFactory() = default;
Poco::Net::HTTPRequestHandler *createRequestHandler(const Poco::Net::HTTPServerRequest &Request) override;
private:
static inline std::atomic_uint64_t NextTransactionId_ = 1;
};
class RESTAPI_IntServer : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new RESTAPI_IntServer;
return instance_;
}
inline int Start() override {
poco_information(Logger(),"Starting.");
Server_.InitLogging();
for(const auto & Svr: ConfigServersList_) {
if(MicroServiceNoAPISecurity()) {
poco_information(Logger(),fmt::format("Starting: {}:{}. Security has been disabled for APIs.", Svr.Address(), Svr.Port()));
} else {
poco_information(Logger(),fmt::format("Starting: {}:{}. Keyfile:{} CertFile: {}", Svr.Address(), Svr.Port(),
Svr.KeyFile(),Svr.CertFile()));
Svr.LogCert(Logger());
if (!Svr.RootCA().empty())
Svr.LogCas(Logger());
}
auto Params = new Poco::Net::HTTPServerParams;
Params->setKeepAlive(true);
Params->setName("ws:irest");
std::unique_ptr<Poco::Net::HTTPServer> NewServer;
if(MicroServiceNoAPISecurity()) {
auto Sock{Svr.CreateSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory, Pool_, Sock, Params);
} else {
auto Sock{Svr.CreateSecureSocket(Logger())};
NewServer = std::make_unique<Poco::Net::HTTPServer>(new IntRequestHandlerFactory, Pool_, Sock, Params);
};
NewServer->start();
RESTServers_.push_back(std::move(NewServer));
}
return 0;
}
inline void Stop() override {
poco_information(Logger(),"Stopping...");
for( const auto & svr : RESTServers_ )
svr->stopAll(true);
Pool_.stopAll();
Pool_.joinAll();
poco_information(Logger(),"Stopped...");
}
inline void reinitialize([[maybe_unused]] Poco::Util::Application &self) override {
MicroServiceLoadConfigurationFile();
poco_information(Logger(),"Reinitializing.");
Stop();
Start();
}
inline Poco::Net::HTTPRequestHandler *CallServer(const std::string &Path, uint64_t Id) {
RESTAPIHandler::BindingMap Bindings;
Utils::SetThreadName(fmt::format("i-rest:{}",Id).c_str());
return RESTAPI_IntRouter(Path, Bindings, Logger(), Server_, Id);
}
const Poco::ThreadPool & Pool() { return Pool_; }
private:
std::vector<std::unique_ptr<Poco::Net::HTTPServer>> RESTServers_;
Poco::ThreadPool Pool_{"i-rest",4,64};
RESTAPI_GenericServerAccounting Server_;
RESTAPI_IntServer() noexcept:
SubSystemServer("RESTAPI_IntServer", "REST-ISRV", "openwifi.internal.restapi")
{
}
};
inline auto RESTAPI_IntServer() { return RESTAPI_IntServer::instance(); };
} // namespace OpenWifi

View File

@@ -0,0 +1,66 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include <string>
#include "Poco/Net/PartHandler.h"
#include "Poco/Net/MessageHeader.h"
#include "Poco/CountingStream.h"
#include "Poco/NullStream.h"
#include "Poco/StreamCopier.h"
namespace OpenWifi {
class RESTAPI_PartHandler: public Poco::Net::PartHandler {
public:
RESTAPI_PartHandler():
_length(0)
{
}
inline void handlePart(const Poco::Net::MessageHeader& header, std::istream& stream) override
{
_type = header.get("Content-Type", "(unspecified)");
if (header.has("Content-Disposition"))
{
std::string disp;
Poco::Net::NameValueCollection params;
Poco::Net::MessageHeader::splitParameters(header["Content-Disposition"], disp, params);
_name = params.get("name", "(unnamed)");
_fileName = params.get("filename", "(unnamed)");
}
Poco::CountingInputStream istr(stream);
Poco::NullOutputStream ostr;
Poco::StreamCopier::copyStream(istr, ostr);
_length = (int)istr.chars();
}
[[nodiscard]] inline int length() const
{
return _length;
}
[[nodiscard]] inline const std::string& name() const
{
return _name;
}
[[nodiscard]] inline const std::string& fileName() const
{
return _fileName;
}
[[nodiscard]] inline const std::string& contentType() const
{
return _type;
}
private:
int _length;
std::string _type;
std::string _name;
std::string _fileName;
};
}

View File

@@ -0,0 +1,75 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/SubSystemServer.h"
#include "Poco/URI.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/ExpireLRUCache.h"
#include "fmt/format.h"
namespace OpenWifi {
class RESTAPI_RateLimiter : public SubSystemServer {
public:
struct ClientCacheEntry {
int64_t Start=0;
int Count=0;
};
static auto instance() {
static auto instance_ = new RESTAPI_RateLimiter;
return instance_;
}
inline int Start() final { return 0;};
inline void Stop() final { };
inline bool IsRateLimited(const Poco::Net::HTTPServerRequest &R, int64_t Period, int64_t MaxCalls) {
Poco::URI uri(R.getURI());
auto H = str_hash(uri.getPath() + R.clientAddress().host().toString());
auto E = Cache_.get(H);
auto Now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
if(E.isNull()) {
Cache_.add(H,ClientCacheEntry{.Start=Now, .Count=1});
return false;
}
if((Now-E->Start)<Period) {
E->Count++;
Cache_.update(H,E);
if(E->Count > MaxCalls) {
poco_warning(Logger(),fmt::format("RATE-LIMIT-EXCEEDED: from '{}'", R.clientAddress().toString()));
return true;
}
return false;
}
E->Start = Now;
E->Count = 1;
Cache_.update(H,E);
return false;
}
inline void Clear() {
Cache_.clear();
}
private:
Poco::ExpireLRUCache<uint64_t,ClientCacheEntry> Cache_{2048};
std::hash<std::string> str_hash;
RESTAPI_RateLimiter() noexcept:
SubSystemServer("RateLimiter", "RATE-LIMITER", "rate.limiter")
{
}
};
inline auto RESTAPI_RateLimiter() { return RESTAPI_RateLimiter::instance(); }
}

View File

@@ -0,0 +1,157 @@
//
// Created by stephane bourque on 2022-10-25.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "Poco/Environment.h"
using namespace std::chrono_literals;
namespace OpenWifi {
class RESTAPI_system_command : public RESTAPIHandler {
public:
RESTAPI_system_command(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting & Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server,
TransactionId,
Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/system"};}
inline void DoGet() {
std::string Arg;
if(HasParameter("command",Arg) && Arg=="info") {
Poco::JSON::Object Answer;
Answer.set(RESTAPI::Protocol::VERSION, MicroServiceVersion());
Answer.set(RESTAPI::Protocol::UPTIME, MicroServiceUptimeTotalSeconds());
Answer.set(RESTAPI::Protocol::START, MicroServiceStartTimeEpochTime());
Answer.set(RESTAPI::Protocol::OS, Poco::Environment::osName());
Answer.set(RESTAPI::Protocol::PROCESSORS, Poco::Environment::processorCount());
Answer.set(RESTAPI::Protocol::HOSTNAME, Poco::Environment::nodeName());
Answer.set(RESTAPI::Protocol::UI, MicroServiceGetUIURI());
Poco::JSON::Array Certificates;
auto SubSystems = MicroServiceGetFullSubSystems();
std::set<std::string> CertNames;
for(const auto &i:SubSystems) {
auto Hosts=i->HostSize();
for(uint64_t j=0;j<Hosts;++j) {
auto CertFileName = i->Host(j).CertFile();
if(!CertFileName.empty()) {
Poco::File F1(CertFileName);
if(F1.exists()) {
auto InsertResult = CertNames.insert(CertFileName);
if(InsertResult.second) {
Poco::JSON::Object Inner;
Poco::Path F(CertFileName);
Inner.set("filename", F.getFileName());
Poco::Crypto::X509Certificate C(CertFileName);
auto ExpiresOn = C.expiresOn();
Inner.set("expiresOn", ExpiresOn.timestamp().epochTime());
Certificates.add(Inner);
}
}
}
}
}
Answer.set("certificates", Certificates);
return ReturnObject(Answer);
}
if(GetBoolParameter("extraConfiguration")) {
Poco::JSON::Object Answer;
MicroServiceGetExtraConfiguration(Answer);
return ReturnObject(Answer);
}
BadRequest(RESTAPI::Errors::InvalidCommand);
}
inline void DoPost() final {
const auto & Obj = ParsedBody_;
if (Obj->has(RESTAPI::Protocol::COMMAND)) {
auto Command = Poco::toLower(Obj->get(RESTAPI::Protocol::COMMAND).toString());
if (Command == RESTAPI::Protocol::SETLOGLEVEL) {
if (Obj->has(RESTAPI::Protocol::SUBSYSTEMS) &&
Obj->isArray(RESTAPI::Protocol::SUBSYSTEMS)) {
auto ParametersBlock = Obj->getArray(RESTAPI::Protocol::SUBSYSTEMS);
for (const auto &i : *ParametersBlock) {
Poco::JSON::Parser pp;
auto InnerObj = pp.parse(i).extract<Poco::JSON::Object::Ptr>();
if (InnerObj->has(RESTAPI::Protocol::TAG) &&
InnerObj->has(RESTAPI::Protocol::VALUE)) {
auto Name = GetS(RESTAPI::Protocol::TAG, InnerObj);
auto Value = GetS(RESTAPI::Protocol::VALUE, InnerObj);
MicroServiceSetSubsystemLogLevel(Name, Value);
poco_information(Logger_,
fmt::format("Setting log level for {} at {}", Name, Value));
}
}
return OK();
}
} else if (Command == RESTAPI::Protocol::GETLOGLEVELS) {
auto CurrentLogLevels = MicroServiceGetLogLevels();
Poco::JSON::Object Result;
Poco::JSON::Array Array;
for (auto &[Name, Level] : CurrentLogLevels) {
Poco::JSON::Object Pair;
Pair.set(RESTAPI::Protocol::TAG, Name);
Pair.set(RESTAPI::Protocol::VALUE, Level);
Array.add(Pair);
}
Result.set(RESTAPI::Protocol::TAGLIST, Array);
return ReturnObject(Result);
} else if (Command == RESTAPI::Protocol::GETLOGLEVELNAMES) {
Poco::JSON::Object Result;
Poco::JSON::Array LevelNamesArray;
const Types::StringVec &LevelNames = MicroServiceGetLogLevelNames();
for (const auto &i : LevelNames)
LevelNamesArray.add(i);
Result.set(RESTAPI::Protocol::LIST, LevelNamesArray);
return ReturnObject(Result);
} else if (Command == RESTAPI::Protocol::GETSUBSYSTEMNAMES) {
Poco::JSON::Object Result;
Poco::JSON::Array LevelNamesArray;
const Types::StringVec &SubSystemNames = MicroServiceGetSubSystems();
for (const auto &i : SubSystemNames)
LevelNamesArray.add(i);
Result.set(RESTAPI::Protocol::LIST, LevelNamesArray);
return ReturnObject(Result);
} else if (Command == RESTAPI::Protocol::STATS) {
} else if (Command == RESTAPI::Protocol::RELOAD) {
if (Obj->has(RESTAPI::Protocol::SUBSYSTEMS) &&
Obj->isArray(RESTAPI::Protocol::SUBSYSTEMS)) {
auto SubSystems = Obj->getArray(RESTAPI::Protocol::SUBSYSTEMS);
std::vector<std::string> Names;
for (const auto &i : *SubSystems)
Names.push_back(i.toString());
std::thread ReloadThread([Names](){
std::this_thread::sleep_for(10000ms);
for(const auto &i:Names) {
if(i=="daemon")
MicroServiceReload();
else
MicroServiceReload(i);
}
});
ReloadThread.detach();
}
return OK();
}
} else {
return BadRequest(RESTAPI::Errors::InvalidCommand);
}
BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
void DoPut() final {};
void DoDelete() final {};
};
}

View File

@@ -0,0 +1,52 @@
//
// Created by stephane bourque on 2022-10-31.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "framework/MicroServiceFuncs.h"
using namespace std::chrono_literals;
namespace OpenWifi {
class RESTAPI_system_configuration : public RESTAPIHandler {
public:
RESTAPI_system_configuration(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L,
RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId,
bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_PUT,
Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_DELETE,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal) {}
static auto PathName() { return std::list<std::string>{"/api/v1/systemConfiguration"}; }
inline void DoPost() final {}
inline void DoGet() final {
return OK();
}
inline void DoPut() final{
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
return OK();
};
inline void DoDelete() final{
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) {
return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED);
}
MicroServiceDeleteOverrideConfiguration();
return OK();
};
};
}

View File

@@ -0,0 +1,45 @@
//
// Created by stephane bourque on 2022-10-26.
//
#pragma once
#include "framework/RESTAPI_Handler.h"
#include "Poco/Net/WebSocket.h"
#include "framework/UI_WebSocketClientServer.h"
#include "framework/MicroServiceFuncs.h"
namespace OpenWifi {
class RESTAPI_webSocketServer : public RESTAPIHandler {
public:
inline RESTAPI_webSocketServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServerAccounting &Server, uint64_t TransactionId, bool Internal)
: RESTAPIHandler(bindings, L,
std::vector<std::string>{ Poco::Net::HTTPRequest::HTTP_GET,
Poco::Net::HTTPRequest::HTTP_OPTIONS},
Server, TransactionId, Internal,false) {}
static auto PathName() { return std::list<std::string>{"/api/v1/ws"};}
void DoGet() final {
try
{
if(Request->find("Upgrade") != Request->end() && Poco::icompare((*Request)["Upgrade"], "websocket") == 0) {
try
{
Poco::Net::WebSocket WS(*Request, *Response);
auto Id = MicroServiceCreateUUID();
UI_WebSocketClientServer()->NewClient(WS,Id,UserInfo_.userinfo.email, TransactionId_);
}
catch (...) {
std::cout << "Cannot create websocket client..." << std::endl;
}
}
} catch(...) {
std::cout << "Cannot upgrade connection..." << std::endl;
}
};
void DoDelete() final {};
void DoPost() final {};
void DoPut() final {};
private:
};
}

Some files were not shown because too many files have changed in this diff Show More