Compare commits
375 Commits
mp-2025_01
...
mp-2025_06
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
439e787d37 | ||
|
|
d242d63c2e | ||
|
|
86982d0000 | ||
|
|
f549ef5d27 | ||
|
|
fe2eaafb7b | ||
|
|
caf149fe8b | ||
|
|
c540135705 | ||
|
|
734c237666 | ||
|
|
85d445ec61 | ||
|
|
b059f4a56e | ||
|
|
b56ab22117 | ||
|
|
5bda393b10 | ||
|
|
4ad508eca6 | ||
|
|
7f856dacf6 | ||
|
|
b6ba56a564 | ||
|
|
f930b846c2 | ||
|
|
fc5394a5c9 | ||
|
|
725ff96425 | ||
|
|
bfd0cd77a9 | ||
|
|
548a7634b7 | ||
|
|
3e4637e174 | ||
|
|
20b7c3f50d | ||
|
|
9206341032 | ||
|
|
6383d18e0e | ||
|
|
cfc7dc6320 | ||
|
|
72acef3aaf | ||
|
|
850975a85b | ||
|
|
68ee246216 | ||
|
|
2ba802bb06 | ||
|
|
688129cf08 | ||
|
|
81721ab7eb | ||
|
|
bf50871208 | ||
|
|
cbf88e05fe | ||
|
|
a808450fa2 | ||
|
|
033b7cd4db | ||
|
|
cd6a918533 | ||
|
|
63ebcbadc9 | ||
|
|
b2802a37aa | ||
|
|
1e95b317bf | ||
|
|
78fec171f9 | ||
|
|
8bfaabcf27 | ||
|
|
2b08847cf7 | ||
|
|
9ea722607f | ||
|
|
409155f0d0 | ||
|
|
026a943648 | ||
|
|
aeb6df5685 | ||
|
|
06886e0094 | ||
|
|
b498a445b2 | ||
|
|
876e9ac7b9 | ||
|
|
a89b875872 | ||
|
|
0ce70e48b1 | ||
|
|
bf583a1aa5 | ||
|
|
1533f82ec4 | ||
|
|
8a43bc252f | ||
|
|
ffcc5c0d9f | ||
|
|
c51043d72a | ||
|
|
2cb534df85 | ||
|
|
4f30623f2d | ||
|
|
b9ac7c65fa | ||
|
|
cef487fb3a | ||
|
|
284539fd52 | ||
|
|
08a1313ba5 | ||
|
|
7349014bd6 | ||
|
|
12cfe2ff4b | ||
|
|
ae1892f196 | ||
|
|
dbad237826 | ||
|
|
56e222a97e | ||
|
|
888792a201 | ||
|
|
41867ed01a | ||
|
|
b82e0d02df | ||
|
|
cd1fce313e | ||
|
|
5153bd2f69 | ||
|
|
d4ad6844e3 | ||
|
|
4f610c68a2 | ||
|
|
3582659018 | ||
|
|
1f537849a9 | ||
|
|
e6d0118ff3 | ||
|
|
ff7d47e155 | ||
|
|
8ae50a8d60 | ||
|
|
08411d9430 | ||
|
|
9bd3182bd5 | ||
|
|
c45eb6cca2 | ||
|
|
b229b39ab8 | ||
|
|
87b5e01581 | ||
|
|
8188f33345 | ||
|
|
7403b6650b | ||
|
|
6bbf2ba788 | ||
|
|
06b0ed8551 | ||
|
|
ada19028e0 | ||
|
|
1e5de0da23 | ||
|
|
bb14dd4c22 | ||
|
|
188e7da379 | ||
|
|
982c9bd649 | ||
|
|
fec37bd221 | ||
|
|
120e3e1e6b | ||
|
|
8d1661d8e4 | ||
|
|
18f61f4d63 | ||
|
|
be74442e7f | ||
|
|
061119819f | ||
|
|
0b8cb929b7 | ||
|
|
f1c858e3a7 | ||
|
|
3fc7eff424 | ||
|
|
36050b14c5 | ||
|
|
fa6acd8e52 | ||
|
|
dbf7f76baa | ||
|
|
18be337160 | ||
|
|
0bd6ef8db4 | ||
|
|
7fb1722c70 | ||
|
|
279d92e338 | ||
|
|
a26dd6f2a5 | ||
|
|
785e4ef28c | ||
|
|
dff347bcb7 | ||
|
|
619ac1564e | ||
|
|
581eeff996 | ||
|
|
b4e747c3db | ||
|
|
04dec73988 | ||
|
|
af75532ba7 | ||
|
|
335163f887 | ||
|
|
b3274466a3 | ||
|
|
064e84f5e8 | ||
|
|
18bc231951 | ||
|
|
9a19bf739d | ||
|
|
9e6feecb88 | ||
|
|
baf77ed182 | ||
|
|
b2f7232422 | ||
|
|
961568f721 | ||
|
|
042db13994 | ||
|
|
ba434d88a2 | ||
|
|
d32e2f4b81 | ||
|
|
e40139fee2 | ||
|
|
d8612a01ca | ||
|
|
474e63c395 | ||
|
|
ceaeb756fb | ||
|
|
603a8e93d0 | ||
|
|
4fdfd77a54 | ||
|
|
6b5f5e877d | ||
|
|
77bb64fbb6 | ||
|
|
92d5e30f3c | ||
|
|
349c11d641 | ||
|
|
027edb9aba | ||
|
|
868c2b32f8 | ||
|
|
2acd25e805 | ||
|
|
b730fd068c | ||
|
|
3e9aeeed05 | ||
|
|
158cf994c5 | ||
|
|
391c06e7e5 | ||
|
|
fa5acddcbe | ||
|
|
7d233136eb | ||
|
|
a4975038b4 | ||
|
|
229e68077c | ||
|
|
143180d68b | ||
|
|
c065415713 | ||
|
|
b01e8ff004 | ||
|
|
de94590fa0 | ||
|
|
b3d7d492d7 | ||
|
|
d29147fe57 | ||
|
|
a0898b8327 | ||
|
|
2ca246deca | ||
|
|
c1d347b70b | ||
|
|
381afa97f4 | ||
|
|
cb379d4149 | ||
|
|
aceffdfad2 | ||
|
|
8ece026f2d | ||
|
|
d000c8621e | ||
|
|
cf1eba68f0 | ||
|
|
b6800e538d | ||
|
|
b8fbbb7125 | ||
|
|
4b4753415a | ||
|
|
1c053d0492 | ||
|
|
44b8848996 | ||
|
|
550967c176 | ||
|
|
e713711a61 | ||
|
|
613a7e629d | ||
|
|
5026a7b753 | ||
|
|
75b602811c | ||
|
|
2897aece2c | ||
|
|
2cc260790c | ||
|
|
1ac4b8cad0 | ||
|
|
ab3b2be725 | ||
|
|
10e4aa8f85 | ||
|
|
ea0d426430 | ||
|
|
27a0214b5d | ||
|
|
f9cd1833da | ||
|
|
f8d3d09716 | ||
|
|
484a455df7 | ||
|
|
21c2c60f4f | ||
|
|
5a46db37c1 | ||
|
|
e545251b27 | ||
|
|
d51ca9b1d1 | ||
|
|
dba503df5b | ||
|
|
732dcd74f7 | ||
|
|
930229b969 | ||
|
|
bb4e16cae7 | ||
|
|
f5606554c9 | ||
|
|
d97d2ac08f | ||
|
|
f834a4ecc5 | ||
|
|
92b7d1bb13 | ||
|
|
b775c9b6b2 | ||
|
|
63acb95834 | ||
|
|
faa46c7e38 | ||
|
|
fee3606a61 | ||
|
|
92bcd366cb | ||
|
|
bc54f5bda1 | ||
|
|
30945807d8 | ||
|
|
95a0e6ea9d | ||
|
|
47275556f9 | ||
|
|
25fb6f262d | ||
|
|
147f920eb6 | ||
|
|
b63d625d12 | ||
|
|
11657cef75 | ||
|
|
5dd0e6fd95 | ||
|
|
9a993445c4 | ||
|
|
4baa949a77 | ||
|
|
c7823d3874 | ||
|
|
074a7e5650 | ||
|
|
64e2cf5d25 | ||
|
|
cc7ef0cf30 | ||
|
|
9102d90c34 | ||
|
|
6832487c46 | ||
|
|
f5cf85a931 | ||
|
|
d57d721dbf | ||
|
|
aa97197413 | ||
|
|
d7df84549b | ||
|
|
8feb8982c1 | ||
|
|
f4acc829f7 | ||
|
|
34b2fe4007 | ||
|
|
72f52da17b | ||
|
|
eecb022a0c | ||
|
|
9063962c7d | ||
|
|
9e25cbb183 | ||
|
|
9af57eaac0 | ||
|
|
f31567e785 | ||
|
|
dc62f1fe05 | ||
|
|
868268d116 | ||
|
|
9f663b0ed9 | ||
|
|
827497bb5e | ||
|
|
688f02df47 | ||
|
|
33ec6d0a67 | ||
|
|
b3f19b0432 | ||
|
|
e6ea506a74 | ||
|
|
2ac090cf14 | ||
|
|
46b24bf442 | ||
|
|
9a854977a4 | ||
|
|
e25b0ad69d | ||
|
|
b632a10fff | ||
|
|
e20b1c52d3 | ||
|
|
08e1428902 | ||
|
|
5f220dc86f | ||
|
|
51d32dc505 | ||
|
|
048eccf4c6 | ||
|
|
9e37ebb261 | ||
|
|
de89bc94b6 | ||
|
|
ab9c177793 | ||
|
|
6ce1aac1d7 | ||
|
|
e56f2600e8 | ||
|
|
614a30fd4e | ||
|
|
5981ec44e4 | ||
|
|
8008819989 | ||
|
|
7edaed601b | ||
|
|
06434512c7 | ||
|
|
fa65bc53b5 | ||
|
|
c1a67a36ef | ||
|
|
1e90682605 | ||
|
|
2357b63b42 | ||
|
|
e1b2650221 | ||
|
|
52ae473ad1 | ||
|
|
833819f713 | ||
|
|
155fc9a743 | ||
|
|
a03fc012f4 | ||
|
|
5b93d58309 | ||
|
|
bef677eda4 | ||
|
|
265a1e6043 | ||
|
|
b21c111aa3 | ||
|
|
b9419520f4 | ||
|
|
8925ce23e9 | ||
|
|
feabc76e36 | ||
|
|
f806cf30e5 | ||
|
|
15199a17a5 | ||
|
|
30654509b1 | ||
|
|
ea2162e8f4 | ||
|
|
ebba98ef16 | ||
|
|
b995f1c3fb | ||
|
|
77e573192e | ||
|
|
ba55a2898d | ||
|
|
16a6bb08b5 | ||
|
|
b2a087c959 | ||
|
|
7349dcba8d | ||
|
|
e4145afbfe | ||
|
|
876d1cad0e | ||
|
|
eea0a66b84 | ||
|
|
b4d71a0fad | ||
|
|
89542e06c9 | ||
|
|
3555b49219 | ||
|
|
791afb80f8 | ||
|
|
924c4d27e8 | ||
|
|
cac611deae | ||
|
|
aee2c384c8 | ||
|
|
78fda7727a | ||
|
|
45e668ec88 | ||
|
|
c6f1ac94fa | ||
|
|
8c9fd4574d | ||
|
|
f9a73a61e9 | ||
|
|
0165b02310 | ||
|
|
24dc3e1c0a | ||
|
|
7b6cb4da34 | ||
|
|
c8fcd46325 | ||
|
|
3ffc4a3410 | ||
|
|
52eb92a00c | ||
|
|
ebce002614 | ||
|
|
595f983071 | ||
|
|
8586269033 | ||
|
|
0f598a5552 | ||
|
|
236f6832a3 | ||
|
|
373a553ac8 | ||
|
|
2964347e7b | ||
|
|
3f0e9c9294 | ||
|
|
0b946c5748 | ||
|
|
c808f8640e | ||
|
|
1fa0d976d2 | ||
|
|
091307290e | ||
|
|
7a045abcc2 | ||
|
|
95d589b126 | ||
|
|
d27664d7c9 | ||
|
|
ebf9c6eb30 | ||
|
|
fef6011426 | ||
|
|
daa07428eb | ||
|
|
0d8d684e78 | ||
|
|
bab6721b2c | ||
|
|
d468d2fb1a | ||
|
|
d897f40903 | ||
|
|
9a7a7e75f9 | ||
|
|
a14c2c892c | ||
|
|
cc64f793ec | ||
|
|
32d5287a3a | ||
|
|
4dd3decb06 | ||
|
|
171caacc92 | ||
|
|
2320ba3a69 | ||
|
|
72c8923bfe | ||
|
|
14c9ac17a1 | ||
|
|
7e745c98e6 | ||
|
|
31d8cb10df | ||
|
|
6174233731 | ||
|
|
216a13e90d | ||
|
|
44c5eb65bd | ||
|
|
edb6c90f46 | ||
|
|
58bc39c2fb | ||
|
|
fecaaaf341 | ||
|
|
263ce00a14 | ||
|
|
9cca3af402 | ||
|
|
541b5ee2ca | ||
|
|
dc4a02a8ff | ||
|
|
5011e7e123 | ||
|
|
cf9408b594 | ||
|
|
3e4e3ffe2d | ||
|
|
9c1188b4d1 | ||
|
|
ea564ba101 | ||
|
|
ca2103f7b3 | ||
|
|
58c6d12e36 | ||
|
|
2f468e4f78 | ||
|
|
daba490c09 | ||
|
|
3638378344 | ||
|
|
f26effc8b3 | ||
|
|
8b22e7d22a | ||
|
|
b413b172e5 | ||
|
|
4e85b59ec9 | ||
|
|
c7551512bc | ||
|
|
6b61763d6f | ||
|
|
106f47d465 | ||
|
|
0cfec70025 | ||
|
|
72e32847c7 | ||
|
|
c6f4759530 | ||
|
|
3e9aa7969b | ||
|
|
e308e07b87 | ||
|
|
f2d527cd2f | ||
|
|
d887747b3c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -16,6 +16,7 @@ aqhome-nodes.vg
|
||||
aqhome-tool.vg
|
||||
aqhome-mqtt.pid
|
||||
aqhome-mqtt.devices
|
||||
aqhome-react.pid
|
||||
|
||||
core.*
|
||||
core
|
||||
|
||||
6
0BUILD
6
0BUILD
@@ -2,7 +2,7 @@
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<project name="aqhome" version="0.0.4" so_current="0" so_age="0" so_revision="4" write_config_h="TRUE">
|
||||
<project name="aqhome" version="0.0.11" so_current="0" so_age="0" so_revision="11" write_config_h="TRUE">
|
||||
<setVar name="package">$(project_name)</setVar>
|
||||
<setVar name="version">
|
||||
$(project_vmajor).$(project_vminor).$(project_vpatchlevel)
|
||||
@@ -51,6 +51,8 @@
|
||||
<setVar name="pkgincludedir">$(includedir)/aqhome/$(package)</setVar>
|
||||
<setVar name="pkgdatadir">$(datadir)/$(package)</setVar>
|
||||
|
||||
<setVar name="httpdatadir">/var/www</setVar>
|
||||
|
||||
<option id="enable_testcode" type="string">
|
||||
<default>TRUE</default>
|
||||
<choices>TRUE FALSE</choices>
|
||||
@@ -126,6 +128,7 @@
|
||||
</option>
|
||||
|
||||
|
||||
|
||||
<checkheaders>
|
||||
signal.h
|
||||
sys/stat.h
|
||||
@@ -149,6 +152,7 @@
|
||||
<dep id="gwenhywfar" name="gwenhywfar" minversion="5.11.2" required="TRUE" >
|
||||
<variables>plugindir gwengui-fox16</variables>
|
||||
</dep>
|
||||
<dep id="aqcgi" name="aqcgi" minversion="0.0.1" required="TRUE" />
|
||||
<!-- <dep id="aqdatabase" name="aqdatabase" minversion="1.99.1" required="TRUE" >
|
||||
<variables>aqdatabase_typemakerdir</variables>
|
||||
</dep>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
aqhome-data
|
||||
aqhome-nodes
|
||||
aqhome-react
|
||||
aqhome-cgi
|
||||
</subdirs>
|
||||
|
||||
</gwbuild>
|
||||
|
||||
145
apps/aqhome-cgi/0BUILD
Normal file
145
apps/aqhome-cgi/0BUILD
Normal file
@@ -0,0 +1,145 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
|
||||
<target type="Program" name="aqhome-cgi" install="$(libdir)/cgi-bin" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
$(aqcgi_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
main.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
aqhomecgi
|
||||
aqhcgi_service
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
-lm
|
||||
$(aqcgi_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhomecgi" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
service_file.h
|
||||
service_file_p.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
service_file.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
aqhcgi_service
|
||||
aqhcgi_modules
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
-lm
|
||||
$(aqcgi_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
service
|
||||
modules
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
23
apps/aqhome-cgi/README
Normal file
23
apps/aqhome-cgi/README
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
Modules:
|
||||
- login
|
||||
- signup
|
||||
- main
|
||||
- devices
|
||||
- list
|
||||
- show?name="nodes/12345678"
|
||||
- add
|
||||
- edit
|
||||
- delete
|
||||
- values
|
||||
- rooms
|
||||
|
||||
- users
|
||||
- list
|
||||
- show?alias="admin"
|
||||
- add
|
||||
- edit
|
||||
- delete
|
||||
|
||||
- dashboards
|
||||
0
apps/aqhome-cgi/dummy.c
Normal file
0
apps/aqhome-cgi/dummy.c
Normal file
181
apps/aqhome-cgi/main.c
Normal file
181
apps/aqhome-cgi/main.c
Normal file
@@ -0,0 +1,181 @@
|
||||
|
||||
|
||||
#include "./service_file.h"
|
||||
#include "aqhome-cgi/modules/mroot.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <aqcgi/cgi.h>
|
||||
#include <aqcgi/request.h>
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/nogui.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#define AQHOME_CGI_LOGFILE "/var/www/aqhome-cgi/log/aqhome-cgi.log"
|
||||
|
||||
#define AQHOME_CGI_DEFAULT_STATIC_FILES "0-build/services/static"
|
||||
#define AQHOME_CGI_DEFAULT_RUNTIME_FILES "0-build/services/runtime"
|
||||
|
||||
|
||||
|
||||
void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles);
|
||||
int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles);
|
||||
AQH_MODULE *_loadModule(AQH_SERVICE *sv, AQCGI_REQUEST *rq, AQH_MODULE *mParent, const char *sModuleName);
|
||||
static void logStart(void);
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GWEN_GUI *gui;
|
||||
AQCGI_REQUEST *rq;
|
||||
|
||||
GWEN_Init();
|
||||
gui=GWEN_NoGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
logStart();
|
||||
GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
|
||||
GWEN_Logger_Open(AQH_LOGDOMAIN, "aqhome", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
|
||||
GWEN_Logger_Open(AQCGI_LOGDOMAIN, "aqcgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
|
||||
GWEN_Logger_Open(NULL, "aqhome-cgi", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
|
||||
|
||||
GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug);
|
||||
GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug);
|
||||
GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug);
|
||||
|
||||
DBG_ERROR(NULL, "Init CGI");
|
||||
AQCGI_Init();
|
||||
|
||||
GWEN_Logger_Close(GWEN_LOGDOMAIN);
|
||||
GWEN_Logger_Open(GWEN_LOGDOMAIN, "gwenhywfar", AQHOME_CGI_LOGFILE, GWEN_LoggerType_File, GWEN_LoggerFacility_Daemon);
|
||||
|
||||
GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug);
|
||||
GWEN_Logger_SetLevel(AQCGI_LOGDOMAIN, GWEN_LoggerLevel_Debug);
|
||||
GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug);
|
||||
|
||||
rq=AQCGI_ReadRequest();
|
||||
if (rq) {
|
||||
const char *sPathStaticFiles;
|
||||
const char *sPathRuntimeFiles;
|
||||
|
||||
sPathStaticFiles=getenv("AQHOME_STATIC_FILES");
|
||||
if (!(sPathStaticFiles && *sPathStaticFiles))
|
||||
sPathStaticFiles=AQHOME_CGI_DEFAULT_STATIC_FILES;
|
||||
|
||||
sPathRuntimeFiles=getenv("AQHOME_RUNTIME_FILES");
|
||||
if (!(sPathRuntimeFiles && *sPathRuntimeFiles))
|
||||
sPathRuntimeFiles=AQHOME_CGI_DEFAULT_RUNTIME_FILES;
|
||||
|
||||
_handleRequest(rq, sPathStaticFiles, sPathRuntimeFiles);
|
||||
}
|
||||
else {
|
||||
fprintf(stdout, "Content-type: text/plain\n\n");
|
||||
fprintf(stdout, "Error: No Request!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
AQCGI_Fini();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleRequest(AQCGI_REQUEST *rq, const char *sPathStaticFiles, const char *sPathRuntimeFiles)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
int rv;
|
||||
|
||||
sv=AQH_ServiceFiles_new(sPathRuntimeFiles);
|
||||
|
||||
rv=_handlePath(sv, rq, sPathStaticFiles);
|
||||
if (rv<0) {
|
||||
}
|
||||
AQH_Service_free(sv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePath(AQH_SERVICE *sv, AQCGI_REQUEST *rq, const char *sPathStaticFiles)
|
||||
{
|
||||
AQH_MODULE *mRoot;
|
||||
AQH_MODULE *mParent;
|
||||
const GWEN_STRINGLIST *sl;
|
||||
|
||||
mRoot=AQH_ModRoot_new(sv, sPathStaticFiles);
|
||||
mParent=mRoot;
|
||||
|
||||
sl=AQCGI_Request_GetStringlistPath(rq);
|
||||
if (sl) {
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
while(se) {
|
||||
GWEN_STRINGLISTENTRY *seNext;
|
||||
const char *s;
|
||||
|
||||
seNext=GWEN_StringListEntry_Next(se);
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
if (seNext) {
|
||||
AQH_MODULE *m;
|
||||
|
||||
DBG_ERROR(NULL, "Entry: %s (%s)", s, seNext?"not last":"last");
|
||||
m=AQH_ModService_LoadSubModule(mParent, rq, s);
|
||||
if (m==NULL) {
|
||||
AQH_Module_free(mRoot);
|
||||
AQCGI_SendResponseWithStatus(rq, 404, "Not found");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
mParent=m;
|
||||
}
|
||||
else {
|
||||
int rv;
|
||||
|
||||
/* last, let module handle remaining part */
|
||||
rv=AQH_ModService_HandleRequest(mParent, rq, s);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQH_Module_free(mRoot);
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
se=seNext;
|
||||
}
|
||||
AQH_Module_free(mRoot);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
AQH_Module_free(mRoot);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void logStart()
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f=fopen(AQHOME_CGI_LOGFILE, "a+");
|
||||
if (f!=NULL) {
|
||||
fprintf(f, "Started.\n");
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhipcnodes" >
|
||||
<target type="ConvenienceLibrary" name="aqhcgi_modules" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
@@ -21,7 +25,7 @@
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
<setVar name="tm2flags-INACTIVE" >
|
||||
--api=AQHOME_API
|
||||
</setVar>
|
||||
|
||||
@@ -39,36 +43,28 @@
|
||||
</setVar>
|
||||
|
||||
|
||||
<headers dist="false" install="$(pkgincludedir)/ipc" >
|
||||
<headers dist="false" install="$(pkgincludedir)/service" >
|
||||
$(local/built_headers_pub)
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" install="$(pkgincludedir)/ipc" >
|
||||
ipc_nodes.h
|
||||
msg_ipc_forward.h
|
||||
msg_ipc_getdevices_req.h
|
||||
msg_ipc_getdevices_rsp.h
|
||||
msg_ipc_ping.h
|
||||
msg_ipc_setaccmsggrps.h
|
||||
msg_ipc_value.h
|
||||
<headers dist="true" install="$(pkgincludedir)/service" >
|
||||
mservice.h
|
||||
mroot.h
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" >
|
||||
mservice_p.h
|
||||
mroot_p.h
|
||||
</headers>
|
||||
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
ipc_nodes.c
|
||||
msg_ipc_forward.c
|
||||
msg_ipc_getdevices_req.c
|
||||
msg_ipc_getdevices_rsp.c
|
||||
msg_ipc_ping.c
|
||||
msg_ipc_setaccmsggrps.c
|
||||
msg_ipc_value.c
|
||||
mservice.c
|
||||
mroot.c
|
||||
</sources>
|
||||
|
||||
|
||||
@@ -80,11 +76,9 @@
|
||||
</useTargets>
|
||||
|
||||
<subdirs>
|
||||
static
|
||||
</subdirs>
|
||||
|
||||
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
</gwbuild>
|
||||
246
apps/aqhome-cgi/modules/mroot.c
Normal file
246
apps/aqhome-cgi/modules/mroot.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./mroot_p.h"
|
||||
|
||||
#include "aqhome-cgi/service/module.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/timestamp.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defs and enums
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* global vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
|
||||
static int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
|
||||
static int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq);
|
||||
static int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq);
|
||||
static AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder)
|
||||
{
|
||||
AQH_MODULE *m;
|
||||
|
||||
m=AQH_ModService_new(sv, baseFolder);
|
||||
AQH_ModService_SetHandleRequestFn(m, _handleRequest);
|
||||
AQH_ModService_SetLoadSubModuleFn(m, _loadSubModule);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_MODULE *_loadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem)
|
||||
{
|
||||
if (strcasecmp(sLastPathElem, "login")==0)
|
||||
return _handleRqLogin(m, rq);
|
||||
else if (strcasecmp(sLastPathElem, "signup")==0) {
|
||||
AQCGI_SendResponseWithStatus(rq, 501, "Not Implemented");
|
||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
else if (strcasecmp(sLastPathElem, "confirm")==0) {
|
||||
AQCGI_SendResponseWithStatus(rq, 501, "Not Implemented");
|
||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
else {
|
||||
AQCGI_SendResponseWithStatus(rq, 404, "Not Found");
|
||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleRqLogin(AQH_MODULE *m, AQCGI_REQUEST *rq)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_GET)
|
||||
rv=AQH_ModService_RespondWithFile(m, rq, "en", "login.html");
|
||||
else if (AQCGI_Request_GetRequestMethod(rq)==AQCGI_REQUEST_METHOD_POST)
|
||||
rv=_handleRqLoginPost(m, rq);
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid request method %d", AQCGI_Request_GetRequestMethod(rq));
|
||||
AQCGI_SendResponseWithStatus(rq, 405, "Method No Allowed");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleRqLoginPost(AQH_MODULE *m, AQCGI_REQUEST *rq)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
AQH_USER *user;
|
||||
AQH_SESSION *session;
|
||||
GWEN_BUFFER *dbuf;
|
||||
GWEN_TIMESTAMP *ts;
|
||||
int rv;
|
||||
|
||||
DBG_ERROR(NULL, "Handling request");
|
||||
sv=AQH_ModService_GetService(m);
|
||||
user=_getAndCheckUser(m, rq);
|
||||
if (user==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
ts=GWEN_Timestamp_NowInLocalTime();
|
||||
AQH_User_SetTimestampLastLogin(user, ts);
|
||||
DBG_ERROR(NULL, "Saving user");
|
||||
rv=AQH_Service_SaveUser(sv, user);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error saving user \"%s\"", AQH_User_GetAlias(user));
|
||||
AQCGI_SendResponseWithStatus(rq, 500, "Internal Error");
|
||||
AQH_User_free(user);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* generate session */
|
||||
DBG_ERROR(NULL, "Generating session");
|
||||
dbuf=GWEN_Buffer_new(0, 64, 0, 1);
|
||||
AQCGI_GenerateSessionId(dbuf);
|
||||
session=AQH_Session_new();
|
||||
AQH_Session_SetTimestampCreation(session, ts);
|
||||
AQH_Session_SetTimestampLastAccess(session, ts);
|
||||
AQH_Session_SetUid(session, GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
AQH_Session_SetUserAlias(session, AQH_User_GetAlias(user));
|
||||
rv=AQH_Service_AddSession(sv, session);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error adding session for user \"%s\"", AQH_User_GetAlias(user));
|
||||
AQCGI_SendResponseWithStatus(rq, 500, "Internal Error");
|
||||
AQH_Session_free(session);
|
||||
AQH_User_free(user);
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
/* add Set-Cookie header */
|
||||
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "Set-Cookie: session=%s; max-age=3600", AQH_Session_GetUid(session));
|
||||
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(dbuf));
|
||||
|
||||
/* finish */
|
||||
AQCGI_SendResponseWithStatus(rq, 200, "Ok");
|
||||
AQH_Session_free(session);
|
||||
AQH_User_free(user);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_USER *_getAndCheckUser(AQH_MODULE *m, AQCGI_REQUEST *rq)
|
||||
{
|
||||
GWEN_DB_NODE *dbPost;
|
||||
|
||||
dbPost=AQCGI_Request_GetDbPostBody(rq);
|
||||
if (dbPost) {
|
||||
AQH_SERVICE *sv;
|
||||
const char *sUserName;
|
||||
const char *sPasswd;
|
||||
AQH_USER *user;
|
||||
const char *hashedPaswd;
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
sv=AQH_ModService_GetService(m);
|
||||
sUserName=GWEN_DB_GetCharValue(dbPost, "userid", 0, NULL);
|
||||
sPasswd=GWEN_DB_GetCharValue(dbPost, "password", 0, NULL);
|
||||
if (!(sUserName && *sUserName && sPasswd && *sPasswd)) {
|
||||
DBG_ERROR(NULL, "Either user name or password missing");
|
||||
AQCGI_SendResponseWithStatus(rq, 400, "Bad Request");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DBG_ERROR(NULL, "Loading user \"%s\" (%p)", sUserName, sv);
|
||||
user=AQH_Service_LoadUser(sv, sUserName);
|
||||
if (user==NULL) {
|
||||
DBG_ERROR(NULL, "User \"%s\" not found", sUserName);
|
||||
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
|
||||
return NULL;
|
||||
}
|
||||
DBG_ERROR(NULL, "Loaded user \"%s\"", sUserName);
|
||||
|
||||
if (AQH_User_GetState(user)!=AQH_UserState_Active) {
|
||||
DBG_ERROR(NULL, "User \"%s\" not active", sUserName);
|
||||
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
|
||||
AQH_User_free(user);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hashedPaswd=AQH_User_GetHashedPassword(user);
|
||||
if (!(hashedPaswd && *hashedPaswd)) {
|
||||
DBG_ERROR(NULL, "User \"%s\" has no hashed password", sUserName);
|
||||
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
|
||||
AQH_User_free(user);
|
||||
return NULL;
|
||||
}
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQCGI_HashMd256ToBuffer(sPasswd, buf);
|
||||
DBG_ERROR(NULL, "Hashed password: [%s]", GWEN_Buffer_GetStart(buf));
|
||||
if (strcasecmp(GWEN_Buffer_GetStart(buf), hashedPaswd)!=0) {
|
||||
DBG_ERROR(NULL, "Bad password for user \"%s\"", sUserName);
|
||||
AQCGI_SendResponseWithStatus(rq, 403, "Forbidden");
|
||||
GWEN_Buffer_free(buf);
|
||||
AQH_User_free(user);
|
||||
return NULL;
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
|
||||
DBG_ERROR(NULL, "User \"%s\" accepted", sUserName);
|
||||
return user;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No POST data");
|
||||
AQCGI_SendResponseWithStatus(rq, 400, "Bad Request");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-cgi/modules/mroot.h
Normal file
27
apps/aqhome-cgi/modules/mroot.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_CGI_MROOT_H
|
||||
#define AQHOME_CGI_MROOT_H
|
||||
|
||||
#include <aqhome-cgi/modules/mservice.h>
|
||||
|
||||
#include <aqcgi/request.h>
|
||||
|
||||
#include <gwenhywfar/buffer.h>
|
||||
|
||||
|
||||
AQH_MODULE *AQH_ModRoot_new(AQH_SERVICE *sv, const char *baseFolder);
|
||||
|
||||
AQH_MODULE *AQH_ModRoot_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
|
||||
int AQH_ModRoot_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#ifndef AQHOME_CGI_MROOT_P_H
|
||||
#define AQHOME_CGI_MROOT_P_H
|
||||
|
||||
#include "aqhome-cgi/modules/mroot.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include <aqhome/ipc/nodes/ipc_nodes.h>
|
||||
|
||||
|
||||
291
apps/aqhome-cgi/modules/mservice.c
Normal file
291
apps/aqhome-cgi/modules/mservice.c
Normal file
@@ -0,0 +1,291 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./mservice_p.h"
|
||||
|
||||
#include "aqhome-cgi/service/module.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defs and enums
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQH_MOD_SERVICE_HEADERFILE "header.html"
|
||||
#define AQH_MOD_SERVICE_FOOTERFILE "footer.html"
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* global vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
GWEN_INHERIT(AQH_MODULE, AQH_MOD_SERVICE)
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQH_MODULE *AQH_ModService_new(AQH_SERVICE *sv, const char *baseFolder)
|
||||
{
|
||||
AQH_MODULE *m;
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
m=AQH_Module_new();
|
||||
GWEN_NEW_OBJECT(AQH_MOD_SERVICE, xm);
|
||||
GWEN_INHERIT_SETDATA(AQH_MODULE, AQH_MOD_SERVICE, m, xm, _freeData);
|
||||
|
||||
xm->service=sv;
|
||||
xm->baseFolder=(baseFolder && *baseFolder)?strdup(baseFolder):NULL;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _freeData(GWEN_UNUSED void *bp, void *p)
|
||||
{
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=(AQH_MOD_SERVICE*) p;
|
||||
free(xm->baseFolder);
|
||||
GWEN_FREE_OBJECT(xm);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m)
|
||||
{
|
||||
if (m) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm) {
|
||||
return xm->service;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m)
|
||||
{
|
||||
if (m) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm) {
|
||||
return xm->baseFolder;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn)
|
||||
{
|
||||
if (m) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm) {
|
||||
xm->handleRequestFn=fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn)
|
||||
{
|
||||
if (m) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm) {
|
||||
xm->loadSubModuleFn=fn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
if (m && dbuf) {
|
||||
AQH_MODULE *mParent;
|
||||
|
||||
mParent=AQH_Module_Tree2_GetParent(m);
|
||||
if (mParent) {
|
||||
int rv;
|
||||
|
||||
rv=AQH_ModService_AddHeader(mParent, lang, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_HEADERFILE, dbuf);
|
||||
}
|
||||
DBG_ERROR(NULL, "Argument missing");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
if (m && dbuf) {
|
||||
AQH_MODULE *mParent;
|
||||
int rv;
|
||||
|
||||
rv=AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_FOOTERFILE, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
mParent=AQH_Module_Tree2_GetParent(m);
|
||||
if (mParent) {
|
||||
int rv;
|
||||
|
||||
rv=AQH_ModService_AddFooter(mParent, lang, dbuf);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Argument missing");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
int rv;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
rv=AQH_ModService_AddHeader(m, lang, buf);
|
||||
if (rv<0) {
|
||||
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
|
||||
GWEN_Buffer_free(buf);
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
rv=AQH_ModService_ReadStaticFile(m, lang, sFilename, buf);
|
||||
if (rv<0) {
|
||||
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
|
||||
GWEN_Buffer_free(buf);
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
rv=AQH_ModService_AddFooter(m, lang, buf);
|
||||
if (rv<0) {
|
||||
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
|
||||
GWEN_Buffer_free(buf);
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
AQCGI_Request_SetBufferResponseBody(rq, buf);
|
||||
AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html");
|
||||
AQCGI_SendResponseWithStatus(rq, 200, "Ok");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem)
|
||||
{
|
||||
if (m) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm && xm->handleRequestFn)
|
||||
return xm->handleRequestFn(m, rq, sLastPathElem);
|
||||
}
|
||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName)
|
||||
{
|
||||
if (m) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm && xm->loadSubModuleFn)
|
||||
return xm->loadSubModuleFn(m, rq, sModuleName);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
if (m && filename && dbuf) {
|
||||
AQH_MOD_SERVICE *xm;
|
||||
|
||||
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
|
||||
if (xm) {
|
||||
GWEN_BUFFER *fbuf;
|
||||
int rv;
|
||||
|
||||
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(fbuf, xm->baseFolder);
|
||||
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
|
||||
GWEN_Buffer_AppendString(fbuf, (lang && *lang)?lang:"en");
|
||||
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
|
||||
GWEN_Buffer_AppendString(fbuf, filename);
|
||||
DBG_ERROR(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(fbuf));
|
||||
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), dbuf);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Read(%s): %d", GWEN_Buffer_GetStart(fbuf), rv);
|
||||
GWEN_Buffer_free(fbuf);
|
||||
return rv;
|
||||
}
|
||||
GWEN_Buffer_free(fbuf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
DBG_ERROR(NULL, "Any arg is missing (or is not a AQH_MOD_SERVICE object)");
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
46
apps/aqhome-cgi/modules/mservice.h
Normal file
46
apps/aqhome-cgi/modules/mservice.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_CGI_MSERVICE_H
|
||||
#define AQHOME_CGI_MSERVICE_H
|
||||
|
||||
#include <aqhome-cgi/service/module.h>
|
||||
#include <aqhome-cgi/service/service.h>
|
||||
|
||||
#include <aqcgi/request.h>
|
||||
|
||||
#include <gwenhywfar/buffer.h>
|
||||
|
||||
|
||||
typedef int (*AQH_MODSERVICE_HANDLEREQUEST_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
|
||||
typedef AQH_MODULE* (*AQH_MODSERVICE_LOADSUBMODULE_FN)(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
|
||||
|
||||
|
||||
|
||||
AQH_MODULE *AQH_ModService_new(AQH_SERVICE *sv, const char *baseFolder);
|
||||
|
||||
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m);
|
||||
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m);
|
||||
|
||||
|
||||
int AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
|
||||
int AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf);
|
||||
|
||||
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sModuleName);
|
||||
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *sLastPathElem);
|
||||
|
||||
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename);
|
||||
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn);
|
||||
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
27
apps/aqhome-cgi/modules/mservice_p.h
Normal file
27
apps/aqhome-cgi/modules/mservice_p.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_CGI_MSERVICE_P_H
|
||||
#define AQHOME_CGI_MSERVICE_P_H
|
||||
|
||||
#include "aqhome-cgi/modules/mservice.h"
|
||||
|
||||
|
||||
typedef struct AQH_MOD_SERVICE AQH_MOD_SERVICE;
|
||||
struct AQH_MOD_SERVICE {
|
||||
AQH_SERVICE *service;
|
||||
char *baseFolder;
|
||||
|
||||
AQH_MODSERVICE_HANDLEREQUEST_FN handleRequestFn;
|
||||
AQH_MODSERVICE_LOADSUBMODULE_FN loadSubModuleFn;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
7
apps/aqhome-cgi/modules/static/0BUILD
Normal file
7
apps/aqhome-cgi/modules/static/0BUILD
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
<subdirs>
|
||||
en
|
||||
</subdirs>
|
||||
</gwbuild>
|
||||
13
apps/aqhome-cgi/modules/static/en/0BUILD
Normal file
13
apps/aqhome-cgi/modules/static/en/0BUILD
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<data dist="true" install="$(httpdatadir)/aqhome-cgi/static/en">
|
||||
header.html
|
||||
footer.html
|
||||
login.html
|
||||
</data>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
4
apps/aqhome-cgi/modules/static/en/footer.html
Normal file
4
apps/aqhome-cgi/modules/static/en/footer.html
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
17
apps/aqhome-cgi/modules/static/en/header.html
Normal file
17
apps/aqhome-cgi/modules/static/en/header.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<!-- copyright (c) 2025 by martin@libchipcard.de -->
|
||||
<meta name="generator" content="FTE 1.1" />
|
||||
<meta name="revised" content="martin,2025-06-12" />
|
||||
<meta name="keywords" content="" />
|
||||
<meta name="description" content="" />
|
||||
<meta name="author" content="martin" />
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
|
||||
<title>AqHome</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
25
apps/aqhome-cgi/modules/static/en/login.html
Normal file
25
apps/aqhome-cgi/modules/static/en/login.html
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
<div class="main">
|
||||
<h1>AqHome</h1>
|
||||
<h3>Enter your login credentials</h3>
|
||||
|
||||
<form action="login" method="post">
|
||||
<label for="userid">Username:</label>
|
||||
<input type="text" id="userid" name="userid" placeholder="Enter your Username" required>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" placeholder="Enter your Password" required>
|
||||
|
||||
<div class="wrap">
|
||||
<button type="submit">Submit</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p>Not registered?
|
||||
<a href="signup" style="text-decoration: none;">
|
||||
Create an account
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhservice" >
|
||||
<target type="ConvenienceLibrary" name="aqhcgi_service" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
-I$(builddir)
|
||||
-I$(srcdir)
|
||||
</includes>
|
||||
|
||||
<includes type="tm2" >
|
||||
@@ -21,7 +25,7 @@
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
|
||||
<setVar name="tm2flags" >
|
||||
<setVar name="tm2flags-INACTIVE" >
|
||||
--api=AQHOME_API
|
||||
</setVar>
|
||||
|
||||
20
apps/aqhome-cgi/service/README
Normal file
20
apps/aqhome-cgi/service/README
Normal file
@@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
- service:
|
||||
- userList
|
||||
- rootModule
|
||||
- sessionList
|
||||
|
||||
- user:
|
||||
- modulePerms
|
||||
|
||||
- module:
|
||||
- roleList
|
||||
- permDefList
|
||||
|
||||
- session
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
with_tree2
|
||||
nodup
|
||||
nocopy
|
||||
</flags>
|
||||
@@ -22,8 +23,8 @@
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/error.h</header>
|
||||
<header type="sys" loc="post">aqhome/service/role.h</header>
|
||||
<header type="sys" loc="post">aqhome/service/permdef.h</header>
|
||||
<header type="sys" loc="post">aqhome-cgi/service/role.h</header>
|
||||
<header type="sys" loc="post">aqhome-cgi/service/permdef.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
@@ -31,6 +32,13 @@
|
||||
|
||||
</lang>
|
||||
|
||||
<defines>
|
||||
<define id="AQH_MODULE_FLAGS" prefix="AQH_MODULE_FLAGS_">
|
||||
<item name="ACTIVE" value="0x00000001" />
|
||||
</define>
|
||||
|
||||
</defines>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
@@ -41,6 +49,13 @@
|
||||
<flags>with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="flags" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>with_flags</flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="16">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
@@ -20,7 +20,7 @@
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/error.h</header>
|
||||
<header type="sys" loc="post">aqhome/service/role.h</header>
|
||||
<header type="sys" loc="post">aqhome-cgi/service/role.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
355
apps/aqhome-cgi/service/service.c
Normal file
355
apps/aqhome-cgi/service/service.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
//#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
#include "aqhome-cgi/service/service_p.h"
|
||||
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
GWEN_INHERIT_FUNCTIONS(AQH_SERVICE);
|
||||
GWEN_LIST_FUNCTIONS(AQH_SERVICE, AQH_Service);
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_Service_new(void)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
|
||||
GWEN_NEW_OBJECT(AQH_SERVICE, sv);
|
||||
GWEN_INHERIT_INIT(AQH_SERVICE, sv);
|
||||
GWEN_LIST_INIT(AQH_SERVICE, sv);
|
||||
|
||||
return sv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_free(AQH_SERVICE *sv)
|
||||
{
|
||||
if (sv) {
|
||||
GWEN_LIST_FINI(AQH_SERVICE, sv);
|
||||
GWEN_INHERIT_FINI(AQH_SERVICE, sv);
|
||||
|
||||
GWEN_FREE_OBJECT(sv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
AQH_MODULE *AQH_Service_GetModuleByPath(const AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
if (sv && s && *s) {
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
sl=GWEN_StringList_fromString2(s, "/", 0,
|
||||
GWEN_TEXT_FLAGS_DEL_QUOTES |
|
||||
GWEN_TEXT_FLAGS_DEL_LEADING_BLANKS |
|
||||
GWEN_TEXT_FLAGS_DEL_MULTIPLE_BLANKS |
|
||||
GWEN_TEXT_FLAGS_DEL_TRAILING_BLANKS);
|
||||
if (sl) {
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
AQH_MODULE *m;
|
||||
|
||||
m=sv->rootModule;
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
while(se && m) {
|
||||
const char *sWantedName;
|
||||
|
||||
sWantedName=GWEN_StringListEntry_Data(se);
|
||||
if (sWantedName && *sWantedName) {
|
||||
AQH_MODULE *mTemp;
|
||||
|
||||
mTemp=AQH_Module_Tree2_GetFirstChild(m);
|
||||
while(mTemp) {
|
||||
const char *sModName;
|
||||
|
||||
sModName=AQH_Module_GetName(mTemp);
|
||||
if (sModName && *sModName && 0==strcasecmp(sModName, sWantedName))
|
||||
break;
|
||||
mTemp=AQH_Module_Tree2_GetNext(mTemp);
|
||||
}
|
||||
if (mTemp==NULL) {
|
||||
DBG_ERROR(NULL, "Module \%s\" not found", sWantedName);
|
||||
GWEN_StringList_free(sl);
|
||||
return NULL;
|
||||
}
|
||||
m=mTemp;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Empty path element in \"%s\"", s);
|
||||
GWEN_StringList_free(sl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
} /* while(se && m) */
|
||||
GWEN_StringList_free(sl);
|
||||
return m;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Bad path \"%s\"", s);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
int AQH_Service_HandleRequest(AQH_SERVICE *sv, AQCGI_REQUEST *req)
|
||||
{
|
||||
return (sv && sv->handleRequestFn)?(sv->handleRequestFn(sv, req)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_USER *AQH_Service_LoadUser(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return (sv && sv->loadUserFn)?(sv->loadUserFn(sv, s)):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_SaveUser(AQH_SERVICE *sv, AQH_USER *user)
|
||||
{
|
||||
return (sv && sv->saveUserFn)?(sv->saveUserFn(sv, user)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_AddUser(AQH_SERVICE *sv, AQH_USER *user)
|
||||
{
|
||||
return (sv && sv->addUserFn)?(sv->addUserFn(sv, user)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_DelUser(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return (sv && sv->delUserFn)?(sv->delUserFn(sv, s)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *AQH_Service_ListUsers(AQH_SERVICE *sv)
|
||||
{
|
||||
return (sv && sv->listUsersFn)?(sv->listUsersFn(sv)):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_MODULE *AQH_Service_LoadModule(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return (sv && sv->loadModuleFn)?(sv->loadModuleFn(sv, s)):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_SaveModule(AQH_SERVICE *sv, AQH_MODULE *module)
|
||||
{
|
||||
return (sv && sv->saveModuleFn)?(sv->saveModuleFn(sv, module)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_AddModule(AQH_SERVICE *sv, AQH_MODULE *module)
|
||||
{
|
||||
return (sv && sv->addModuleFn)?(sv->addModuleFn(sv, module)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_DelModule(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return (sv && sv->delModuleFn)?(sv->delModuleFn(sv, s)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *AQH_Service_ListModules(AQH_SERVICE *sv)
|
||||
{
|
||||
return (sv && sv->listModulesFn)?(sv->listModulesFn(sv)):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_SESSION* AQH_Service_LoadSession(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return (sv && sv->loadSessionFn)?(sv->loadSessionFn(sv, s)):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_SaveSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
||||
{
|
||||
return (sv && sv->saveSessionFn)?(sv->saveSessionFn(sv, session)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
||||
{
|
||||
return (sv && sv->addSessionFn)?(sv->addSessionFn(sv, session)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AQH_Service_DelSession(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return (sv && sv->delSessionFn)?(sv->delSessionFn(sv, s)):GWEN_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetHandleRequestFn(AQH_SERVICE *sv, AQH_SERVICE_HANDLEREQUEST_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->handleRequestFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetLoadUserFn(AQH_SERVICE *sv, AQH_SERVICE_LOADUSER_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->loadUserFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetSaveUserFn(AQH_SERVICE *sv, AQH_SERVICE_SAVEUSER_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->saveUserFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetAddUserFn(AQH_SERVICE *sv, AQH_SERVICE_ADDUSER_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->addUserFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetDelUserFn(AQH_SERVICE *sv, AQH_SERVICE_DELUSER_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->delUserFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetListUsersFn(AQH_SERVICE *sv, AQH_SERVICE_LISTUSERS_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->listUsersFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetLoadModuleFn(AQH_SERVICE *sv, AQH_SERVICE_LOADMODULE_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->loadModuleFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetSaveModuleFn(AQH_SERVICE *sv, AQH_SERVICE_SAVEMODULE_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->saveModuleFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetAddModuleFn(AQH_SERVICE *sv, AQH_SERVICE_ADDMODULE_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->addModuleFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetDelModuleFn(AQH_SERVICE *sv, AQH_SERVICE_DELMODULE_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->delModuleFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetListModulesFn(AQH_SERVICE *sv, AQH_SERVICE_LISTMODULES_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->listModulesFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetLoadSessionFn(AQH_SERVICE *sv, AQH_SERVICE_LOADSESSION_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->loadSessionFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetSaveSessionFn(AQH_SERVICE *sv, AQH_SERVICE_SAVESESSION_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->saveSessionFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetAddSessionFn(AQH_SERVICE *sv, AQH_SERVICE_ADDSESSION_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->addSessionFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetDelSessionFn(AQH_SERVICE *sv, AQH_SERVICE_DELSESSION_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->delSessionFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetListSessionsFn(AQH_SERVICE *sv, AQH_SERVICE_LISTSESSIONS_FN f)
|
||||
{
|
||||
if (sv)
|
||||
sv->listSessionsFn=f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
104
apps/aqhome-cgi/service/service.h
Normal file
104
apps/aqhome-cgi/service/service.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_SERVICE_H
|
||||
#define AQHOME_SERVICE_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/list.h>
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
|
||||
|
||||
typedef struct AQH_SERVICE AQH_SERVICE;
|
||||
GWEN_INHERIT_FUNCTION_DEFS(AQH_SERVICE);
|
||||
GWEN_LIST_FUNCTION_DEFS(AQH_SERVICE, AQH_Service);
|
||||
|
||||
|
||||
#include "aqhome-cgi/service/user.h"
|
||||
#include "aqhome-cgi/service/module.h"
|
||||
#include "aqhome-cgi/service/session.h"
|
||||
|
||||
#include <aqcgi/cgi.h>
|
||||
|
||||
|
||||
typedef int (*AQH_SERVICE_HANDLEREQUEST_FN)(AQH_SERVICE *sv, AQCGI_REQUEST *req);
|
||||
|
||||
typedef AQH_USER* (*AQH_SERVICE_LOADUSER_FN)(AQH_SERVICE *sv, const char *s);
|
||||
typedef int (*AQH_SERVICE_SAVEUSER_FN)(AQH_SERVICE *sv, AQH_USER *user);
|
||||
typedef int (*AQH_SERVICE_ADDUSER_FN)(AQH_SERVICE *sv, AQH_USER *user);
|
||||
typedef int (*AQH_SERVICE_DELUSER_FN)(AQH_SERVICE *sv, const char *s);
|
||||
typedef GWEN_STRINGLIST* (*AQH_SERVICE_LISTUSERS_FN)(AQH_SERVICE *sv);
|
||||
|
||||
typedef AQH_MODULE* (*AQH_SERVICE_LOADMODULE_FN)(AQH_SERVICE *sv, const char *s);
|
||||
typedef int (*AQH_SERVICE_SAVEMODULE_FN)(AQH_SERVICE *sv, AQH_MODULE *module);
|
||||
typedef int (*AQH_SERVICE_ADDMODULE_FN)(AQH_SERVICE *sv, AQH_MODULE *module);
|
||||
typedef int (*AQH_SERVICE_DELMODULE_FN)(AQH_SERVICE *sv, const char *s);
|
||||
typedef GWEN_STRINGLIST* (*AQH_SERVICE_LISTMODULES_FN)(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
typedef AQH_SESSION* (*AQH_SERVICE_LOADSESSION_FN)(AQH_SERVICE *sv, const char *s);
|
||||
typedef int (*AQH_SERVICE_SAVESESSION_FN)(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
typedef int (*AQH_SERVICE_ADDSESSION_FN)(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
typedef int (*AQH_SERVICE_DELSESSION_FN)(AQH_SERVICE *sv, const char *s);
|
||||
typedef GWEN_STRINGLIST* (*AQH_SERVICE_LISTSESSIONS_FN)(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_Service_new(void);
|
||||
void AQH_Service_free(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
|
||||
int AQH_Service_HandleRequest(AQH_SERVICE *sv, AQCGI_REQUEST *req);
|
||||
|
||||
AQH_USER *AQH_Service_LoadUser(AQH_SERVICE *sv, const char *s);
|
||||
int AQH_Service_SaveUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
int AQH_Service_AddUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
int AQH_Service_DelUser(AQH_SERVICE *sv, const char *s);
|
||||
GWEN_STRINGLIST *AQH_Service_ListUsers(AQH_SERVICE *sv);
|
||||
|
||||
AQH_MODULE *AQH_Service_LoadModule(AQH_SERVICE *sv, const char *s);
|
||||
int AQH_Service_SaveModule(AQH_SERVICE *sv, AQH_MODULE *module);
|
||||
int AQH_Service_AddModule(AQH_SERVICE *sv, AQH_MODULE *module);
|
||||
int AQH_Service_DelModule(AQH_SERVICE *sv, const char *s);
|
||||
GWEN_STRINGLIST *AQH_Service_ListModules(AQH_SERVICE *sv);
|
||||
|
||||
AQH_SESSION* AQH_Service_LoadSession(AQH_SERVICE *sv, const char *s);
|
||||
int AQH_Service_SaveSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
int AQH_Service_AddSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
int AQH_Service_DelSession(AQH_SERVICE *sv, const char *s);
|
||||
GWEN_STRINGLIST *AQH_Service_ListSessions(AQH_SERVICE *sv);
|
||||
|
||||
|
||||
|
||||
void AQH_Service_SetHandleRequestFn(AQH_SERVICE *sv, AQH_SERVICE_HANDLEREQUEST_FN f);
|
||||
|
||||
void AQH_Service_SetLoadUserFn(AQH_SERVICE *sv, AQH_SERVICE_LOADUSER_FN f);
|
||||
void AQH_Service_SetSaveUserFn(AQH_SERVICE *sv, AQH_SERVICE_SAVEUSER_FN f);
|
||||
void AQH_Service_SetAddUserFn(AQH_SERVICE *sv, AQH_SERVICE_ADDUSER_FN f);
|
||||
void AQH_Service_SetDelUserFn(AQH_SERVICE *sv, AQH_SERVICE_DELUSER_FN f);
|
||||
void AQH_Service_SetListUsersFn(AQH_SERVICE *sv, AQH_SERVICE_LISTUSERS_FN f);
|
||||
|
||||
void AQH_Service_SetLoadModuleFn(AQH_SERVICE *sv, AQH_SERVICE_LOADMODULE_FN f);
|
||||
void AQH_Service_SetSaveModuleFn(AQH_SERVICE *sv, AQH_SERVICE_SAVEMODULE_FN f);
|
||||
void AQH_Service_SetAddModuleFn(AQH_SERVICE *sv, AQH_SERVICE_ADDMODULE_FN f);
|
||||
void AQH_Service_SetDelModuleFn(AQH_SERVICE *sv, AQH_SERVICE_DELMODULE_FN f);
|
||||
void AQH_Service_SetListModulesFn(AQH_SERVICE *sv, AQH_SERVICE_LISTMODULES_FN f);
|
||||
|
||||
void AQH_Service_SetLoadSessionFn(AQH_SERVICE *sv, AQH_SERVICE_LOADSESSION_FN f);
|
||||
void AQH_Service_SetSaveSessionFn(AQH_SERVICE *sv, AQH_SERVICE_SAVESESSION_FN f);
|
||||
void AQH_Service_SetAddSessionFn(AQH_SERVICE *sv, AQH_SERVICE_ADDSESSION_FN f);
|
||||
void AQH_Service_SetDelSessionFn(AQH_SERVICE *sv, AQH_SERVICE_DELSESSION_FN f);
|
||||
void AQH_Service_SetListSessionsFn(AQH_SERVICE *sv, AQH_SERVICE_LISTSESSIONS_FN f);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
45
apps/aqhome-cgi/service/service_p.h
Normal file
45
apps/aqhome-cgi/service/service_p.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_SERVICE_P_H
|
||||
#define AQHOME_SERVICE_P_H
|
||||
|
||||
|
||||
#include "aqhome-cgi/service/service.h"
|
||||
|
||||
|
||||
struct AQH_SERVICE {
|
||||
GWEN_INHERIT_ELEMENT(AQH_SERVICE);
|
||||
GWEN_LIST_ELEMENT(AQH_SERVICE);
|
||||
|
||||
AQH_SERVICE_HANDLEREQUEST_FN handleRequestFn;
|
||||
|
||||
AQH_SERVICE_LOADUSER_FN loadUserFn;
|
||||
AQH_SERVICE_SAVEUSER_FN saveUserFn;
|
||||
AQH_SERVICE_ADDUSER_FN addUserFn;
|
||||
AQH_SERVICE_DELUSER_FN delUserFn;
|
||||
AQH_SERVICE_LISTUSERS_FN listUsersFn;
|
||||
|
||||
AQH_SERVICE_LOADMODULE_FN loadModuleFn;
|
||||
AQH_SERVICE_SAVEMODULE_FN saveModuleFn;
|
||||
AQH_SERVICE_ADDMODULE_FN addModuleFn;
|
||||
AQH_SERVICE_DELMODULE_FN delModuleFn;
|
||||
AQH_SERVICE_LISTMODULES_FN listModulesFn;
|
||||
|
||||
AQH_SERVICE_LOADSESSION_FN loadSessionFn;
|
||||
AQH_SERVICE_SAVESESSION_FN saveSessionFn;
|
||||
AQH_SERVICE_ADDSESSION_FN addSessionFn;
|
||||
AQH_SERVICE_DELSESSION_FN delSessionFn;
|
||||
AQH_SERVICE_LISTSESSIONS_FN listSessionsFn;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -22,7 +22,7 @@
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/error.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/timestamp.h</header>
|
||||
<header type="sys" loc="post">aqhome/service/user.h</header>
|
||||
<header type="sys" loc="post">aqhome-cgi/service/user.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
@@ -23,7 +23,7 @@
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/error.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/timestamp.h</header>
|
||||
<header type="sys" loc="post">aqhome/service/moduleperms.h</header>
|
||||
<header type="sys" loc="post">aqhome-cgi/service/moduleperms.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
@@ -54,6 +54,10 @@
|
||||
<descr>Waiting for approval by admin</descr>
|
||||
</item>
|
||||
|
||||
<item name="active">
|
||||
<descr>User active</descr>
|
||||
</item>
|
||||
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
611
apps/aqhome-cgi/service_file.c
Normal file
611
apps/aqhome-cgi/service_file.c
Normal file
@@ -0,0 +1,611 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
//#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
#include "./service_file_p.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defs and enums
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQH_SERVICE_FILE_GROUP_USERS "users"
|
||||
#define AQH_SERVICE_FILE_GROUP_MODULES "modules"
|
||||
#define AQH_SERVICE_FILE_GROUP_SESSIONS "sessions"
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* global vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
GWEN_INHERIT(AQH_SERVICE, AQH_SERVICE_FILE)
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||
|
||||
static AQH_USER *_loadUser(AQH_SERVICE *sv, const char *s);
|
||||
static int _saveUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
static int _addUser(AQH_SERVICE *sv, AQH_USER *user);
|
||||
static int _delUser(AQH_SERVICE *sv, const char *s);
|
||||
static GWEN_STRINGLIST *_listUsers(AQH_SERVICE *sv);
|
||||
|
||||
static AQH_MODULE *_loadModule(AQH_SERVICE *sv, const char *s);
|
||||
static int _saveModule(AQH_SERVICE *sv, AQH_MODULE *module);
|
||||
static int _addModule(AQH_SERVICE *sv, AQH_MODULE *module);
|
||||
static int _delModule(AQH_SERVICE *sv, const char *s);
|
||||
static GWEN_STRINGLIST *_listModules(AQH_SERVICE *sv);
|
||||
|
||||
static AQH_SESSION* _loadSession(AQH_SERVICE *sv, const char *s);
|
||||
static int _saveSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
static int _addSession(AQH_SERVICE *sv, AQH_SESSION *session);
|
||||
static int _delSession(AQH_SERVICE *sv, const char *s);
|
||||
static GWEN_STRINGLIST *_listSessions(AQH_SERVICE *sv);
|
||||
|
||||
static GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName);
|
||||
static int _saveGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName, GWEN_DB_NODE *db);
|
||||
static int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName, GWEN_DB_NODE *db);
|
||||
static int _deleteGroup(AQH_SERVICE *sv, const char *groupName, const char *subGroupName);
|
||||
static GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName);
|
||||
|
||||
//static void _logGroup(const char *groupName, const char *subGroupName, GWEN_DB_NODE *db);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder)
|
||||
{
|
||||
AQH_SERVICE *sv;
|
||||
AQH_SERVICE_FILE *xs;
|
||||
GWEN_BUFFER *dbuf;
|
||||
|
||||
sv=AQH_Service_new();
|
||||
GWEN_NEW_OBJECT(AQH_SERVICE_FILE, xs);
|
||||
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv, xs, _freeData);
|
||||
xs->baseFolder=strdup(baseFolder);
|
||||
|
||||
AQH_Service_SetLoadUserFn(sv, _loadUser);
|
||||
AQH_Service_SetSaveUserFn(sv, _saveUser);
|
||||
AQH_Service_SetAddUserFn(sv, _addUser);
|
||||
AQH_Service_SetDelUserFn(sv, _delUser);
|
||||
AQH_Service_SetListUsersFn(sv, _listUsers);
|
||||
|
||||
AQH_Service_SetLoadModuleFn(sv, _loadModule);
|
||||
AQH_Service_SetSaveModuleFn(sv, _saveModule);
|
||||
AQH_Service_SetAddModuleFn(sv, _addModule);
|
||||
AQH_Service_SetDelModuleFn(sv, _delModule);
|
||||
AQH_Service_SetListModulesFn(sv, _listModules);
|
||||
|
||||
AQH_Service_SetLoadSessionFn(sv, _loadSession);
|
||||
AQH_Service_SetSaveSessionFn(sv, _saveSession);
|
||||
AQH_Service_SetAddSessionFn(sv, _addSession);
|
||||
AQH_Service_SetDelSessionFn(sv, _delSession);
|
||||
AQH_Service_SetListSessionsFn(sv, _listSessions);
|
||||
|
||||
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "dir://%s", baseFolder);
|
||||
DBG_ERROR(NULL, "Creating config mgr \"%s\"", GWEN_Buffer_GetStart(dbuf));
|
||||
xs->configMgr=GWEN_ConfigMgr_Factory(GWEN_Buffer_GetStart(dbuf));
|
||||
if (xs->configMgr==NULL) {
|
||||
DBG_ERROR(NULL, "Error creating config mgr \"%s\"", GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
AQH_Service_free(sv);
|
||||
return NULL;
|
||||
}
|
||||
GWEN_Buffer_free(dbuf);
|
||||
|
||||
return sv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p)
|
||||
{
|
||||
AQH_SERVICE_FILE *xs;
|
||||
|
||||
xs=(AQH_SERVICE_FILE*) p;
|
||||
GWEN_ConfigMgr_free(xs->configMgr);
|
||||
free(xs->baseFolder);
|
||||
GWEN_FREE_OBJECT(xs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_USER *_loadUser(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
GWEN_DB_NODE *db;
|
||||
|
||||
db=_loadGroupLocked(sv, AQH_SERVICE_FILE_GROUP_USERS, s);
|
||||
if (db) {
|
||||
AQH_USER *user;
|
||||
|
||||
user=AQH_User_fromDb(db);
|
||||
GWEN_DB_Group_free(db);
|
||||
return user;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _saveUser(AQH_SERVICE *sv, AQH_USER *user)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=AQH_User_GetAlias(user);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
db=GWEN_DB_Group_new(s);
|
||||
rv=AQH_User_toDb(user, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
|
||||
//_logGroup(AQH_SERVICE_FILE_GROUP_USERS, s, db);
|
||||
|
||||
rv=_saveGroupLocked(sv, AQH_SERVICE_FILE_GROUP_USERS, s, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
GWEN_DB_Group_free(db);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addUser(AQH_SERVICE *sv, AQH_USER *user)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=AQH_User_GetAlias(user);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
db=GWEN_DB_Group_new(s);
|
||||
rv=AQH_User_toDb(user, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
rv=_addGroupLocked(sv, AQH_SERVICE_FILE_GROUP_USERS, s, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
GWEN_DB_Group_free(db);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _delUser(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return _deleteGroup(sv, AQH_SERVICE_FILE_GROUP_USERS, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *_listUsers(AQH_SERVICE *sv)
|
||||
{
|
||||
return _listGroup(sv, AQH_SERVICE_FILE_GROUP_USERS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_MODULE *_loadModule(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
GWEN_DB_NODE *db;
|
||||
|
||||
db=_loadGroupLocked(sv, AQH_SERVICE_FILE_GROUP_MODULES, s);
|
||||
if (db) {
|
||||
AQH_MODULE *module;
|
||||
|
||||
module=AQH_Module_fromDb(db);
|
||||
GWEN_DB_Group_free(db);
|
||||
return module;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _saveModule(AQH_SERVICE *sv, AQH_MODULE *module)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=AQH_Module_GetName(module);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
db=GWEN_DB_Group_new(s);
|
||||
rv=AQH_Module_toDb(module, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
rv=_saveGroupLocked(sv, AQH_SERVICE_FILE_GROUP_MODULES, s, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
GWEN_DB_Group_free(db);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addModule(AQH_SERVICE *sv, AQH_MODULE *module)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=AQH_Module_GetName(module);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
db=GWEN_DB_Group_new(s);
|
||||
rv=AQH_Module_toDb(module, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
rv=_addGroupLocked(sv, AQH_SERVICE_FILE_GROUP_MODULES, s, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
GWEN_DB_Group_free(db);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _delModule(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return _deleteGroup(sv, AQH_SERVICE_FILE_GROUP_MODULES, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *_listModules(AQH_SERVICE *sv)
|
||||
{
|
||||
return _listGroup(sv, AQH_SERVICE_FILE_GROUP_MODULES);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
AQH_SESSION* _loadSession(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
GWEN_DB_NODE *db;
|
||||
|
||||
db=_loadGroupLocked(sv, AQH_SERVICE_FILE_GROUP_SESSIONS, s);
|
||||
if (db) {
|
||||
AQH_SESSION *session;
|
||||
|
||||
session=AQH_Session_fromDb(db);
|
||||
GWEN_DB_Group_free(db);
|
||||
return session;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _saveSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=AQH_Session_GetUid(session);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
db=GWEN_DB_Group_new(s);
|
||||
rv=AQH_Session_toDb(session, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
rv=_saveGroupLocked(sv, AQH_SERVICE_FILE_GROUP_SESSIONS, s, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
GWEN_DB_Group_free(db);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addSession(AQH_SERVICE *sv, AQH_SESSION *session)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s=AQH_Session_GetUid(session);
|
||||
if (s && *s) {
|
||||
GWEN_DB_NODE *db;
|
||||
int rv;
|
||||
|
||||
db=GWEN_DB_Group_new(s);
|
||||
rv=AQH_Session_toDb(session, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
rv=_addGroupLocked(sv, AQH_SERVICE_FILE_GROUP_SESSIONS, s, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "here (%d)", rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return rv;
|
||||
}
|
||||
GWEN_DB_Group_free(db);
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _delSession(AQH_SERVICE *sv, const char *s)
|
||||
{
|
||||
return _deleteGroup(sv, AQH_SERVICE_FILE_GROUP_SESSIONS, s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *_listSessions(AQH_SERVICE *sv)
|
||||
{
|
||||
return _listGroup(sv, AQH_SERVICE_FILE_GROUP_SESSIONS);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *_loadGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName)
|
||||
{
|
||||
DBG_ERROR(NULL, "Lock and load group %s/%s", groupName, subGroupName);
|
||||
if (sv && groupName && subGroupName) {
|
||||
AQH_SERVICE_FILE *xs;
|
||||
|
||||
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
|
||||
if (xs) {
|
||||
GWEN_DB_NODE *db=NULL;
|
||||
int rv;
|
||||
|
||||
DBG_ERROR(NULL, "Locking group %s/%s", groupName, subGroupName);
|
||||
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return NULL;
|
||||
}
|
||||
DBG_ERROR(NULL, "Loading group %s/%s", groupName, subGroupName);
|
||||
rv=GWEN_ConfigMgr_GetGroup(xs->configMgr, groupName, subGroupName, &db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
|
||||
return NULL;
|
||||
}
|
||||
DBG_ERROR(NULL, "Unlocking group %s/%s", groupName, subGroupName);
|
||||
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
GWEN_DB_Group_free(db);
|
||||
return NULL;
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Missing argument");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _saveGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName, GWEN_DB_NODE *db)
|
||||
{
|
||||
if (sv && groupName && subGroupName && db) {
|
||||
AQH_SERVICE_FILE *xs;
|
||||
|
||||
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
|
||||
if (xs) {
|
||||
int rv;
|
||||
|
||||
DBG_ERROR(NULL, "Locking group %s/%s", groupName, subGroupName);
|
||||
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
DBG_ERROR(NULL, "Writing group %s/%s", groupName, subGroupName);
|
||||
rv=GWEN_ConfigMgr_SetGroup(xs->configMgr, groupName, subGroupName, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error writing group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
DBG_ERROR(NULL, "Unlocking group %s/%s", groupName, subGroupName);
|
||||
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _addGroupLocked(AQH_SERVICE *sv, const char *groupName, const char *subGroupName, GWEN_DB_NODE *db)
|
||||
{
|
||||
if (sv && groupName && subGroupName && db) {
|
||||
AQH_SERVICE_FILE *xs;
|
||||
|
||||
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
|
||||
if (xs) {
|
||||
int rv;
|
||||
|
||||
rv=GWEN_ConfigMgr_HasGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv>=0) {
|
||||
DBG_ERROR(NULL, "Group \"%s/%s\" already exists", groupName, subGroupName);
|
||||
return GWEN_ERROR_FOUND;
|
||||
}
|
||||
|
||||
rv=GWEN_ConfigMgr_LockGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error locking group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=GWEN_ConfigMgr_SetGroup(xs->configMgr, groupName, subGroupName, db);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error writing group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=GWEN_ConfigMgr_UnlockGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error unlocking group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _deleteGroup(AQH_SERVICE *sv, const char *groupName, const char *subGroupName)
|
||||
{
|
||||
if (sv && groupName && subGroupName) {
|
||||
AQH_SERVICE_FILE *xs;
|
||||
|
||||
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
|
||||
if (xs) {
|
||||
int rv;
|
||||
|
||||
rv=GWEN_ConfigMgr_DeleteGroup(xs->configMgr, groupName, subGroupName);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error writing group \"%s/%s\": %d", groupName, subGroupName, rv);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_STRINGLIST *_listGroup(AQH_SERVICE *sv, const char *groupName)
|
||||
{
|
||||
if (sv && groupName) {
|
||||
AQH_SERVICE_FILE *xs;
|
||||
|
||||
xs=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQH_SERVICE_FILE, sv);
|
||||
if (xs) {
|
||||
GWEN_STRINGLIST *sl;
|
||||
int rv;
|
||||
|
||||
sl=GWEN_StringList_new();
|
||||
rv=GWEN_ConfigMgr_ListSubGroups(xs->configMgr, groupName, sl);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error listing group \"%s\": %d", groupName, rv);
|
||||
GWEN_StringList_free(sl);
|
||||
return NULL;
|
||||
}
|
||||
if (GWEN_StringList_Count(sl)==0) {
|
||||
GWEN_StringList_free(sl);
|
||||
return NULL;
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
void _logGroup(const char *groupName, const char *subGroupName, GWEN_DB_NODE *db)
|
||||
{
|
||||
if (db) {
|
||||
GWEN_BUFFER *dbuf;
|
||||
|
||||
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_DB_WriteToBuffer(db, dbuf, GWEN_DB_FLAGS_DEFAULT);
|
||||
DBG_ERROR(NULL, "Group %s/%s:\n%s", groupName?groupName:"<empty>", subGroupName?subGroupName:"<empty>",
|
||||
GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Group %s/%s empty", groupName?groupName:"<empty>", subGroupName?subGroupName:"<empty>");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_INIT_H
|
||||
#define AQHOME_DATA_INIT_H
|
||||
#ifndef AQHOME_SERVICE_FILE_H
|
||||
#define AQHOME_SERVICE_FILE_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
#include "aqhome-cgi/service/service.h"
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder);
|
||||
|
||||
int AqHomeData_Init(AQHOME_DATA *aqh, int argc, char **argv);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -6,24 +6,23 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_ENDPOINT_MQTT_P_H
|
||||
#define AQH_ENDPOINT_MQTT_P_H
|
||||
#ifndef AQHOME_SERVICE_FILE_P_H
|
||||
#define AQHOME_SERVICE_FILE_P_H
|
||||
|
||||
|
||||
#include "aqhome/mqtt/endpoint_mqtt.h"
|
||||
#include "aqhome-cgi/service_file.h"
|
||||
|
||||
#include <gwenhywfar/configmgr.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_ENDPOINT_MQTT AQH_ENDPOINT_MQTT;
|
||||
struct AQH_ENDPOINT_MQTT {
|
||||
char *clientId;
|
||||
uint16_t lastPacketId;
|
||||
uint16_t keepAliveTime;
|
||||
typedef struct AQH_SERVICE_FILE AQH_SERVICE_FILE;
|
||||
struct AQH_SERVICE_FILE {
|
||||
char *baseFolder;
|
||||
GWEN_CONFIGMGR *configMgr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,40 +35,32 @@
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
aqhome_data.h
|
||||
aqhome_data_p.h
|
||||
fini.h
|
||||
init.h
|
||||
loop.h
|
||||
c_connect.h
|
||||
c_updatedata.h
|
||||
c_getvalues.h
|
||||
c_getdevices.h
|
||||
c_getdatapoints.h
|
||||
c_getlastdatapoint.h
|
||||
c_setdata.h
|
||||
c_addvalue.h
|
||||
c_annvalue.h
|
||||
c_moddevice.h
|
||||
server.h
|
||||
server_p.h
|
||||
s_connect.h
|
||||
s_getdevices.h
|
||||
s_getvalues.h
|
||||
s_addvalue.h
|
||||
s_annvalue.h
|
||||
s_updatedata.h
|
||||
s_setdata.h
|
||||
s_getdatapoints.h
|
||||
s_moddevice.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
aqhome_data.c
|
||||
fini.c
|
||||
init.c
|
||||
loop.c
|
||||
c_connect.c
|
||||
c_updatedata.c
|
||||
c_getvalues.c
|
||||
c_getdevices.c
|
||||
c_getdatapoints.c
|
||||
c_getlastdatapoint.c
|
||||
c_setdata.c
|
||||
c_addvalue.c
|
||||
c_annvalue.c
|
||||
c_moddevice.c
|
||||
server.c
|
||||
s_connect.c
|
||||
s_getdevices.c
|
||||
s_getvalues.c
|
||||
s_addvalue.c
|
||||
s_annvalue.c
|
||||
s_updatedata.c
|
||||
s_setdata.c
|
||||
s_getdatapoints.c
|
||||
s_moddevice.c
|
||||
main.c
|
||||
</sources>
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQHOME_DATA *AqHomeData_new()
|
||||
{
|
||||
AQHOME_DATA *aqh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHOME_DATA, aqh);
|
||||
aqh->storageMutex=GWEN_Mutex_new();
|
||||
aqh->requestTree=GWEN_MsgRequest_new();
|
||||
|
||||
return aqh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeData_free(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_Mutex_free(aqh->storageMutex);
|
||||
|
||||
GWEN_MsgRequest_free(aqh->requestTree);
|
||||
GWEN_MsgEndpoint_free(aqh->ipcdEndpoint);
|
||||
GWEN_DB_Group_free(aqh->dbArgs);
|
||||
AQH_Storage_free(aqh->storage);
|
||||
free(aqh->pidFile);
|
||||
|
||||
GWEN_FREE_OBJECT(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?(aqh->ipcdEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?(aqh->dbArgs):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?(aqh->storage):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_REQUEST *AqHomeData_GetRequestTree(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?aqh->requestTree:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeData_AddRequestToTree(AQHOME_DATA *aqh, GWEN_MSG_REQUEST *rq)
|
||||
{
|
||||
if (aqh && rq)
|
||||
GWEN_MsgRequest_Tree2_AddChild(aqh->requestTree, rq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeData_GetPidFile(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?aqh->pidFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_GetTimeout(const AQHOME_DATA *aqh)
|
||||
{
|
||||
return aqh?aqh->timeout:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_LockStorage(AQHOME_DATA *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Mutex_Lock(aqh->storageMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_UnlockStorage(AQHOME_DATA *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Mutex_Unlock(aqh->storageMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_IpcEndpoint_GetServiceName(ep);
|
||||
if (s && *s && strcasecmp(s, serviceName)==0)
|
||||
return ep;
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_H
|
||||
#define AQHOME_DATA_H
|
||||
|
||||
|
||||
#include "aqhome/data/storage.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/request.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQHOME_DATA AQHOME_DATA;
|
||||
|
||||
|
||||
AQHOME_DATA *AqHomeData_new();
|
||||
void AqHomeData_free(AQHOME_DATA *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcdEndpoint(const AQHOME_DATA *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeData_GetIpcEndpointByServiceName(const AQHOME_DATA *aqh, const char *serviceName);
|
||||
|
||||
GWEN_DB_NODE *AqHomeData_GetDbArgs(const AQHOME_DATA *aqh);
|
||||
|
||||
AQH_STORAGE *AqHomeData_GetStorage(const AQHOME_DATA *aqh);
|
||||
|
||||
const char *AqHomeData_GetPidFile(const AQHOME_DATA *aqh);
|
||||
|
||||
int AqHomeData_GetTimeout(const AQHOME_DATA *aqh);
|
||||
|
||||
int AqHomeData_LockStorage(AQHOME_DATA *aqh);
|
||||
int AqHomeData_UnlockStorage(AQHOME_DATA *aqh);
|
||||
|
||||
GWEN_MSG_REQUEST *AqHomeData_GetRequestTree(const AQHOME_DATA *aqh);
|
||||
void AqHomeData_AddRequestToTree(AQHOME_DATA *aqh, GWEN_MSG_REQUEST *rq);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_addvalue.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
AQH_ValuesDataIpcMsg_Parse(msg, 0);
|
||||
recvdValue=AQH_ValuesDataIpcMsg_ReadFirstValue(msg);
|
||||
if (recvdValue) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
|
||||
if (value==NULL)
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_ADDVALUE_H
|
||||
#define AQHOME_DATA_C_ADDVALUE_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleAddValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_annvalue.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleAnnounceValue(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
AQH_ValuesDataIpcMsg_Parse(msg, 0);
|
||||
recvdValue=AQH_ValuesDataIpcMsg_ReadFirstValue(msg);
|
||||
if (recvdValue) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
|
||||
if (value==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Could not create announced value");
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_connect.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/data/msg_data_connect.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleConnect(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
char *clientId=NULL;
|
||||
char *userId=NULL;
|
||||
char *passw=NULL;
|
||||
uint32_t flags;
|
||||
|
||||
AQH_ConnectDataIpcMsg_Parse(msg, 0);
|
||||
clientId=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_CLIENTID, NULL);
|
||||
userId=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_USERID, NULL);
|
||||
flags=AQH_Tag16IpcMsg_GetTagDataAsUint32(msg, AQH_MSGDATA_CONNECT_TAGS_FLAGS, 0);
|
||||
passw=AQH_Tag16IpcMsg_GetTagDataAsNewString(msg, AQH_MSGDATA_CONNECT_TAGS_PASSWORD, NULL);
|
||||
|
||||
if (clientId)
|
||||
AQH_IpcEndpoint_SetServiceName(ep, clientId);
|
||||
if (userId)
|
||||
AQH_IpcEndpoint_SetUserName(ep, userId);
|
||||
|
||||
if (flags & AQH_MSGDATA_CONNECT_FLAGS_WANTUPDATES)
|
||||
GWEN_MsgEndpoint_AddFlags(ep, AQH_IPCENDPOINT_FLAGS_WANTUPDATES);
|
||||
|
||||
/* TODO: add user management, for now we allow all */
|
||||
AQH_IpcEndpoint_SetPermissions(ep,
|
||||
AQH_IPCENDPOINT_PERMS_LISTVALUES |
|
||||
AQH_IPCENDPOINT_PERMS_READVALUE |
|
||||
AQH_IPCENDPOINT_PERMS_ADDVALUE |
|
||||
AQH_IPCENDPOINT_PERMS_LISTDATA |
|
||||
AQH_IPCENDPOINT_PERMS_READDATA |
|
||||
AQH_IPCENDPOINT_PERMS_ADDDATA |
|
||||
AQH_IPCENDPOINT_PERMS_LISTDEVICES |
|
||||
AQH_IPCENDPOINT_PERMS_READDEVICE |
|
||||
AQH_IPCENDPOINT_PERMS_ADDDEVICE |
|
||||
AQH_IPCENDPOINT_PERMS_MODDEVICE);
|
||||
free(passw);
|
||||
free(userId);
|
||||
free(clientId);
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(msg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getdatapoints.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/data/msg_data_getdata.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 2048
|
||||
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 1024
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _getAndSendDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep,
|
||||
const AQH_VALUE *value,
|
||||
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsNoNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
|
||||
uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsWithNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
|
||||
static void _sendDataPointsResponse(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
|
||||
uint32_t refMsgId);
|
||||
static void _getAndSendLastDatapoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeData_HandleGetDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
|
||||
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
|
||||
AQH_VALUE *value;
|
||||
char *valueName;
|
||||
uint64_t tsBegin;
|
||||
uint64_t tsEnd;
|
||||
uint64_t numRequested;
|
||||
|
||||
AQH_GetDataDataIpcMsg_Parse(recvdMsg, 0);
|
||||
valueName=AQH_Tag16IpcMsg_GetTagDataAsNewString(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
|
||||
tsBegin=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0);
|
||||
tsEnd=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_END, 0);
|
||||
numRequested=AQH_Tag16IpcMsg_GetTagDataAsUint64(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NUM, 0);
|
||||
|
||||
value=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
|
||||
if (value) {
|
||||
resultCode=_getAndSendDataPoints(aqh, ep, value, tsBegin, tsEnd, numRequested, GWEN_IpcMsg_GetMsgId(recvdMsg));
|
||||
if (resultCode==AQH_MSG_IPC_SUCCESS)
|
||||
return;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Value \"%s\" does not exist", valueName);
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
free(valueName);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPoints(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
if (num==0)
|
||||
return _getAndSendDataPointsNoNum(aqh, ep, value, tsBegin, tsEnd, refMsgId);
|
||||
else if (num==1) {
|
||||
_getAndSendLastDatapoint(aqh, ep, value, refMsgId);
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else
|
||||
return _getAndSendDataPointsWithNum(aqh, ep, value, num, refMsgId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsNoNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
valueId=AQH_Value_GetId(value);
|
||||
tablePtr=AQH_Storage_GetDataPoints(aqh->storage, valueId, tsBegin, tsEnd, AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(aqh, ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSG_IPC_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsWithNum(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
|
||||
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
|
||||
valueId=AQH_Value_GetId(value);
|
||||
tablePtr=AQH_Storage_GetLastNDataPoints(aqh->storage, valueId, num);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(aqh, ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSG_IPC_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataPointsResponse(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
int numTableEntries;
|
||||
int numDataPoints;
|
||||
GWEN_MSG *outMsg;
|
||||
|
||||
numTableEntries=(int)(tablePtr[0]);
|
||||
numDataPoints=numTableEntries/2;
|
||||
outMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
value, &(tablePtr[1]), numDataPoints);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _getAndSendLastDatapoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE *value, uint32_t refMsgId)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
int rv;
|
||||
uint64_t timestamp=0;
|
||||
double data=0.0;
|
||||
|
||||
rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(value), ×tamp, &data);
|
||||
if (rv<0) {
|
||||
switch(rv) {
|
||||
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
|
||||
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
|
||||
default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
outMsg=AQH_MultiDataDataIpcMsg_newForOne(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
value, timestamp, data);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getdevices.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_devices.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_DEVICESPERMSG 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendDeviceList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleGetDevices(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
const AQH_DEVICE_LIST *origDeviceList;
|
||||
|
||||
DBG_INFO(NULL, "HandleGetDevices");
|
||||
origDeviceList=AQH_Storage_GetDeviceList(aqh->storage);
|
||||
if (origDeviceList) {
|
||||
DBG_INFO(NULL, "Have a list of %d devices", AQH_Device_List_GetCount(origDeviceList));
|
||||
if (AQH_Device_List_GetCount(origDeviceList)<AQHOMEDATA_DEVICESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending all entries in one message");
|
||||
_sendDeviceList(aqh, ep, origDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
else {
|
||||
AQH_DEVICE_LIST *tmpDeviceList;
|
||||
const AQH_DEVICE *v;
|
||||
|
||||
DBG_INFO(NULL, "Sending entries in multiple messages");
|
||||
tmpDeviceList=AQH_Device_List_new();
|
||||
v=AQH_Device_List_First(origDeviceList);
|
||||
while(v) {
|
||||
const AQH_DEVICE *next;
|
||||
AQH_DEVICE *copyOfDevice;
|
||||
|
||||
next=AQH_Device_List_Next(v);
|
||||
copyOfDevice=AQH_Device_dup(v);
|
||||
AQH_Device_List_Add(copyOfDevice, tmpDeviceList);
|
||||
if (AQH_Device_List_GetCount(tmpDeviceList)>=AQHOMEDATA_DEVICESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
|
||||
_sendDeviceList(aqh, ep, tmpDeviceList, next?0:AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
AQH_Device_List_Clear(tmpDeviceList);
|
||||
}
|
||||
v=next;
|
||||
}
|
||||
if (AQH_Device_List_GetCount(tmpDeviceList)) {
|
||||
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
|
||||
_sendDeviceList(aqh, ep, tmpDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg)); /* send remaining */
|
||||
}
|
||||
AQH_Device_List_free(tmpDeviceList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
_sendDeviceList(aqh, ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDeviceList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
msg=AQH_DevicesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
flags, vl);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETDEVICES_H
|
||||
#define AQHOME_DATA_C_GETDEVICES_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetDevices(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getlastdatapoint.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_getdata.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
|
||||
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_READDATA) {
|
||||
char *valueName;
|
||||
|
||||
AQH_GetDataDataIpcMsg_Parse(recvdMsg, 0);
|
||||
valueName=AQH_Tag16IpcMsg_GetTagDataAsNewString(recvdMsg, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
|
||||
if (valueName && *valueName) {
|
||||
const AQH_VALUE *storedValue;
|
||||
|
||||
storedValue=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
|
||||
if (storedValue) {
|
||||
uint64_t timestamp=0;
|
||||
double data=0.0;
|
||||
int rv;
|
||||
|
||||
rv=AQH_Storage_GetLastDataPoint(aqh->storage, AQH_Value_GetId(storedValue), ×tamp, &data);
|
||||
if (rv<0) {
|
||||
switch(rv) {
|
||||
case GWEN_ERROR_INVALID: resultCode=AQH_MSG_IPC_ERROR_INVALID; break;
|
||||
case GWEN_ERROR_NO_DATA: resultCode=AQH_MSG_IPC_ERROR_NODATA; break;
|
||||
default: resultCode=AQH_MSG_IPC_ERROR_GENERIC; break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
outMsg=AQH_MultiDataDataIpcMsg_newForOne(AQH_MSGTYPE_IPC_DATA_GETLASTDATA_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
storedValue, timestamp, data);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
free(valueName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Value \"%s\" not found", valueName);
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
free(valueName);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No name for value");
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETLASTDATAPOINT_H
|
||||
#define AQHOME_DATA_C_GETLASTDATAPOINT_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetLastDataPoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getvalues.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_VALUESPERMSG 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
const AQH_VALUE_LIST *origValueList;
|
||||
|
||||
DBG_INFO(NULL, "HandleGetValues");
|
||||
origValueList=AQH_Storage_GetValueList(aqh->storage);
|
||||
if (origValueList) {
|
||||
DBG_INFO(NULL, "Have a list of %d values", AQH_Value_List_GetCount(origValueList));
|
||||
if (AQH_Value_List_GetCount(origValueList)<AQHOMEDATA_VALUESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending all entries in one message");
|
||||
_sendValueList(aqh, ep, origValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
else {
|
||||
AQH_VALUE_LIST *tmpValueList;
|
||||
const AQH_VALUE *v;
|
||||
|
||||
DBG_INFO(NULL, "Sending entries in multiple messages");
|
||||
tmpValueList=AQH_Value_List_new();
|
||||
v=AQH_Value_List_First(origValueList);
|
||||
while(v) {
|
||||
const AQH_VALUE *next;
|
||||
AQH_VALUE *copyOfValue;
|
||||
|
||||
next=AQH_Value_List_Next(v);
|
||||
copyOfValue=AQH_Value_dup(v);
|
||||
AQH_Value_List_Add(copyOfValue, tmpValueList);
|
||||
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
|
||||
_sendValueList(aqh, ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
AQH_Value_List_Clear(tmpValueList);
|
||||
}
|
||||
v=next;
|
||||
}
|
||||
if (AQH_Value_List_GetCount(tmpValueList)) {
|
||||
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
|
||||
_sendValueList(aqh, ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg)); /* send remaining */
|
||||
}
|
||||
AQH_Value_List_free(tmpValueList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
_sendValueList(aqh, ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, GWEN_IpcMsg_GetMsgId(msg));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueList(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
msg=AQH_ValuesDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), refMsgId,
|
||||
flags, vl);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_GETVALUES_H
|
||||
#define AQHOME_DATA_C_GETVALUES_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleGetValues(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_getlastdatapoint.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_devices.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
|
||||
if (AQH_IpcEndpoint_GetPermissions(ep) & AQH_IPCENDPOINT_PERMS_MODDEVICE) {
|
||||
AQH_DEVICE *device;
|
||||
|
||||
AQH_DevicesDataIpcMsg_Parse(recvdMsg, 0);
|
||||
device=AQH_DevicesDataIpcMsg_ReadFirstDevice(recvdMsg);
|
||||
if (device) {
|
||||
const char *deviceNameForSystem;
|
||||
|
||||
deviceNameForSystem=AQH_Device_GetNameForSystem(device);
|
||||
if (deviceNameForSystem && *deviceNameForSystem) {
|
||||
AQH_DEVICE *storedDevice;
|
||||
|
||||
storedDevice=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, deviceNameForSystem);
|
||||
if (storedDevice) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_Device_GetNameForGui(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetNameForGui(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetRoomName(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetRoomName(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetLocation(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetLocation(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetDescription(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetDescription(storedDevice, s);
|
||||
|
||||
AQH_Storage_AddRuntimeFlags(aqh->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
|
||||
resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device \"%s\" not found", deviceNameForSystem);
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No name for value");
|
||||
resultCode=AQH_MSG_IPC_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No device info in message");
|
||||
resultCode=AQH_MSG_IPC_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_MODDEVICE_H
|
||||
#define AQHOME_DATA_C_MODDEVICE_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleModDevice(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,258 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_setdata.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_set.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
|
||||
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epSrc, uint32_t requestMsgId,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *v, const char *data);
|
||||
static void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason);
|
||||
static void _rqAbort(GWEN_MSG_REQUEST *rq, int reason);
|
||||
|
||||
static GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const AQH_VALUE *v, const char *data);
|
||||
static int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg);
|
||||
static void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
uint32_t msgId;
|
||||
AQH_VALUE *recvdValue;
|
||||
const char *valueName;
|
||||
char *valueDataFreeable;
|
||||
AQH_VALUE *systemValue;
|
||||
|
||||
msgId=GWEN_IpcMsg_GetMsgId(recvdMsg);
|
||||
DBG_INFO(NULL, "Received IPC SetDataRequest message (msgId=%d)", msgId);
|
||||
|
||||
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||
valueName=recvdValue?AQH_Value_GetNameForSystem(recvdValue):NULL;
|
||||
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||
|
||||
systemValue=AQH_Storage_GetValueByNameForSystem(aqh->storage, valueName);
|
||||
if (systemValue) {
|
||||
if (AQH_Value_GetValueType(systemValue)==AQH_ValueType_Actor) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=AQH_Value_GetDriver(systemValue);
|
||||
if (driverName && *driverName) {
|
||||
GWEN_MSG_ENDPOINT *epDriver;
|
||||
|
||||
epDriver=AqHomeData_GetIpcEndpointByServiceName(aqh, driverName);
|
||||
if (epDriver) {
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
|
||||
DBG_DEBUG(NULL, "Creating SETDATA request for driver endpoint (%s)", GWEN_MsgEndpoint_GetName(epDriver));
|
||||
rq=_mkRequest_SetData(aqh, epSrc, msgId, epDriver, systemValue, valueDataFreeable);
|
||||
AqHomeData_AddRequestToTree(aqh, rq);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Driver \"%s\" not available", driverName);
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No driver name");
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Value \"%s\" is not an actor", valueName);
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unknown value \"%s\"", valueName);
|
||||
AQH_IpcEndpoint_SendResponseResult(epSrc, msgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_NOTFOUND);
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
free(valueDataFreeable);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* IPC Request SETDATA
|
||||
*/
|
||||
|
||||
GWEN_MSG_REQUEST *_mkRequest_SetData(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epSrc, uint32_t requestMsgId,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *v, const char *data)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
GWEN_MSG_REQUEST *subRq;
|
||||
|
||||
rq=GWEN_MsgRequest_new();
|
||||
GWEN_MsgRequest_SetPrivateData(rq, aqh);
|
||||
GWEN_MsgRequest_SetEndpoint(rq, epSrc);
|
||||
GWEN_MsgRequest_SetRequestMsgId(rq, requestMsgId);
|
||||
GWEN_MsgRequest_SetSubRequestFinishedFn(rq, _rqSubRequestFinished);
|
||||
GWEN_MsgRequest_SetAbortFn(rq, _rqAbort);
|
||||
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_REQUEST_EXPIRE_SECS);
|
||||
|
||||
subRq=_mkSubRequest_SetData(aqh, epDriver, v, data);
|
||||
GWEN_MsgRequest_Tree2_AddChild(rq, subRq);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqSubRequestFinished(GWEN_MSG_REQUEST *rq, GWEN_MSG_REQUEST *subRq, int reason)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
uint32_t refMsgId;
|
||||
int result;
|
||||
|
||||
DBG_DEBUG(NULL, "SubRequest finished (reason: %d)", reason);
|
||||
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=GWEN_MsgRequest_GetEndpoint(rq);
|
||||
result=GWEN_MsgRequest_GetResult(subRq);
|
||||
|
||||
if (reason==GWEN_MSG_REQUEST_REASON_ABORTED)
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
else
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, result);
|
||||
|
||||
GWEN_MsgRequest_SetResult(rq, result);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqAbort(GWEN_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
uint32_t refMsgId;
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
refMsgId=GWEN_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=GWEN_MsgRequest_GetEndpoint(rq);
|
||||
AQH_IpcEndpoint_SendResponseResult(ep, refMsgId, AQH_MSGTYPE_IPC_DATA_RESULT, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Driver Request SETDATA
|
||||
*/
|
||||
|
||||
|
||||
GWEN_MSG_REQUEST *_mkSubRequest_SetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const AQH_VALUE *v, const char *data)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rq;
|
||||
uint16_t msgId;
|
||||
GWEN_MSG *driverMsg;
|
||||
|
||||
rq=GWEN_MsgRequest_new();
|
||||
GWEN_MsgRequest_SetPrivateData(rq, aqh);
|
||||
GWEN_MsgRequest_SetEndpoint(rq, epDriver);
|
||||
|
||||
GWEN_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
|
||||
GWEN_MsgRequest_SetAbortFn(rq, _subRqAbort);
|
||||
|
||||
msgId=GWEN_MsgEndpoint_GetNextMessageId(epDriver);
|
||||
GWEN_MsgRequest_SetRequestMsgId(rq, msgId);
|
||||
GWEN_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
|
||||
|
||||
driverMsg=AQH_SetDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_SETDATA, msgId, 0, v, data);
|
||||
GWEN_MsgEndpoint_AddSendMessage(epDriver, driverMsg);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _subRqHandleResponse(GWEN_MSG_REQUEST *rq, GWEN_MSG *msg)
|
||||
{
|
||||
DBG_DEBUG(NULL, "Checking message from driver");
|
||||
if (GWEN_IpcMsg_GetCode(msg)==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||
uint32_t result;
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
result=AQH_ResultIpcMsg_GetResultCode(msg);
|
||||
DBG_INFO(NULL, "Received result for request: %d", result);
|
||||
GWEN_MsgRequest_SetResult(rq, result);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, GWEN_MSG_REQUEST_REASON_DONE);
|
||||
return GWEN_MSG_REQUEST_RESULT_HANDLED;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unexpected response message %d", GWEN_IpcMsg_GetCode(msg));
|
||||
}
|
||||
|
||||
return GWEN_MSG_REQUEST_RESULT_NOT_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _subRqAbort(GWEN_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
GWEN_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
|
||||
GWEN_MsgRequest_SetResult(rq, AQH_MSG_IPC_ERROR_GENERIC);
|
||||
GWEN_MsgRequest_SetState(rq, GWEN_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=GWEN_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
GWEN_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_SETDATA_H
|
||||
#define AQHOME_DATA_C_SETDATA_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleSetData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./c_updatedata.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "./loop.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/msg_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues);
|
||||
static void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
|
||||
const uint64_t *dataPoints, uint32_t numValues);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
GWEN_MSG *outMsg;
|
||||
int resultCode=AQH_MSG_IPC_SUCCESS;
|
||||
const GWEN_TAG16 *tag;
|
||||
AQH_VALUE *recvdValue;
|
||||
const char *valueName;
|
||||
const uint64_t *dataPoints=NULL;
|
||||
unsigned int numberOfPoints=0;
|
||||
|
||||
AQH_MultiDataDataIpcMsg_Parse(recvdMsg, 0);
|
||||
|
||||
recvdValue=AQH_MultiDataDataIpcMsg_ReadValue(recvdMsg);
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
tag=AQH_Tag16IpcMsg_FindFirstTagByType(recvdMsg, AQH_MSGDATA_MULTIDATA_TAGS_DATA);
|
||||
dataPoints=tag?((const uint64_t*)GWEN_Tag16_GetTagData(tag)):NULL;
|
||||
numberOfPoints=(tag?GWEN_Tag16_GetTagLength(tag):0)/(2*sizeof(uint64_t));
|
||||
|
||||
if (numberOfPoints>0) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeData_GetOrCreateValueForDriverWithTemplate(aqh, ep, recvdValue);
|
||||
if (value) {
|
||||
resultCode=_storeDataPoints(aqh, value, dataPoints, numberOfPoints);
|
||||
if (resultCode==AQH_MSG_IPC_SUCCESS)
|
||||
_sendDataChangedMsgToAllClients(aqh, ep, value, dataPoints, numberOfPoints);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No permissions to add datapoint for value \"%s\"", valueName);
|
||||
resultCode=AQH_MSG_IPC_ERROR_PERMS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No datapoints");
|
||||
resultCode=AQH_MSG_IPC_ERROR_INVALID;
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
|
||||
outMsg=AQH_ResultIpcMsg_new(AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), GWEN_IpcMsg_GetMsgId(recvdMsg),
|
||||
resultCode);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _storeDataPoints(AQHOME_DATA *aqh, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i=0; i<numValues; i++) {
|
||||
uint64_t timestamp;
|
||||
union {double f; uint64_t i;} u;
|
||||
int rv;
|
||||
|
||||
timestamp=*(dataPoints++);
|
||||
u.i=*(dataPoints++);
|
||||
rv=AQH_Storage_AddDatapoint(aqh->storage, AQH_Value_GetId(v), timestamp, u.f);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return AQH_MSG_IPC_ERROR_GENERIC;
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
|
||||
}
|
||||
} /* for */
|
||||
|
||||
return AQH_MSG_IPC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataChangedMsgToAllClients(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epSrc, const AQH_VALUE *v,
|
||||
const uint64_t *dataPoints, uint32_t numValues)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
if (ep!=epSrc) {
|
||||
if (GWEN_MsgEndpoint_GetFlags(ep) & AQH_IPCENDPOINT_FLAGS_WANTUPDATES) {
|
||||
GWEN_MSG *msg;
|
||||
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint %s", GWEN_MsgEndpoint_GetName(ep));
|
||||
msg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(ep), 0,
|
||||
v, dataPoints, numValues);
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msg);
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Endpoint %s doesn't want updates", GWEN_MsgEndpoint_GetName(ep));
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
|
||||
}
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_C_UPDATEDATA_H
|
||||
#define AQHOME_DATA_C_UPDATEDATA_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_HandleUpdateData(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./fini.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_Fini(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
if (aqh->ipcdEndpoint) {
|
||||
_disconnectTree(aqh->ipcdEndpoint);
|
||||
GWEN_MsgEndpoint_Disconnect(aqh->ipcdEndpoint);
|
||||
}
|
||||
GWEN_MsgEndpoint_free(aqh->ipcdEndpoint);
|
||||
aqh->ipcdEndpoint=NULL;
|
||||
|
||||
if (aqh->pidFile)
|
||||
remove(aqh->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epChild;
|
||||
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
||||
while(epChild) {
|
||||
_disconnectTree(epChild);
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
||||
} /* while */
|
||||
|
||||
GWEN_MsgEndpoint_Disconnect(ep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_FINI_H
|
||||
#define AQHOME_DATA_FINI_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
|
||||
void AqHomeData_Fini(AQHOME_DATA *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,341 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./init.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/endpoint_msgio.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _setupStorage(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static void _setupIpc(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
||||
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AqHomeData_Init(AQHOME_DATA *aqh, int argc, char **argv)
|
||||
{
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
int rv;
|
||||
const char *s;
|
||||
|
||||
dbArgs=GWEN_DB_Group_new("args");
|
||||
rv=_readArgs(argc, argv, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
|
||||
aqh->dbArgs=dbArgs;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_LOGGER_LEVEL ll;
|
||||
|
||||
ll=GWEN_Logger_Name2Level(s);
|
||||
GWEN_Logger_SetLevel(NULL, ll);
|
||||
}
|
||||
|
||||
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_DATA_DEFAULT_PIDFILE);
|
||||
if (s && *s) {
|
||||
free(aqh->pidFile);
|
||||
aqh->pidFile=strdup(s);
|
||||
rv=_createPidFile(s);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv=_setupStorage(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
_setupIpc(aqh, dbArgs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupStorage(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *dataFolder;
|
||||
GWEN_BUFFER *nameBuf;
|
||||
AQH_STORAGE *sto;
|
||||
int rv;
|
||||
|
||||
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_DATA_DEFAULT_DATADIR);
|
||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(nameBuf, "%s%s%s", dataFolder, GWEN_DIR_SEPARATOR_S, AQHOME_DATA_STATEFILENAME);
|
||||
|
||||
sto=AQH_Storage_new();
|
||||
AQH_Storage_SetStateFile(sto, GWEN_Buffer_GetStart(nameBuf));
|
||||
AQH_Storage_SetDataFileFolder(sto, dataFolder);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
|
||||
rv=AQH_Storage_Init(sto);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQH_Storage_free(sto);
|
||||
return rv;
|
||||
}
|
||||
aqh->storage=sto;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setupIpc(AQHOME_DATA *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
|
||||
if (!(tcpAddress && *tcpAddress))
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, NULL);
|
||||
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
|
||||
if (tcpPort<0)
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_DATA_DEFAULT_IPC_PORT);
|
||||
|
||||
if (tcpAddress && *tcpAddress && tcpPort>0) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
DBG_INFO(NULL, "Starting TCP service on \"%s\":%d", tcpAddress, tcpPort);
|
||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
|
||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
|
||||
|
||||
aqh->ipcdEndpoint=ep;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
|
||||
GWEN_SOCKET *sk,
|
||||
const GWEN_INETADDRESS *addr,
|
||||
GWEN_UNUSED void *data)
|
||||
{
|
||||
/* AQHOME_DATA *aqh;
|
||||
*
|
||||
* aqh=(AQHOME_DATA*) data;
|
||||
*/
|
||||
DBG_INFO(NULL, "Incoming IPC connection");
|
||||
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
int pidfd;
|
||||
|
||||
if (remove(pidFilename)==0) {
|
||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (pidfd < 0) {
|
||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
f = fdopen(pidfd, "w");
|
||||
#else /* HAVE_STAT_H */
|
||||
f=fopen(pidFilename,"w+");
|
||||
#endif /* HAVE_STAT_H */
|
||||
|
||||
/* write pid */
|
||||
#ifdef HAVE_GETPID
|
||||
fprintf(f,"%d\n",getpid());
|
||||
#else
|
||||
fprintf(f,"-1\n");
|
||||
#endif
|
||||
if (fclose(f)) {
|
||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
int rv;
|
||||
const GWEN_ARGS args[]= {
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"loglevel", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"L", /* short option */
|
||||
"loglevel", /* long option */
|
||||
I18S("Specify loglevel"), /* short description */
|
||||
I18S("Specify loglevel") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"tcpAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"t", /* short option */
|
||||
"tcpaddress", /* long option */
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)"),
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"tcpPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"P", /* short option */
|
||||
"tcpport", /* long option */
|
||||
I18S("Specify the TCP port to listen on"),
|
||||
I18S("Specify the TCP port to listen on")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"datafolder", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"datafolder", /* long option */
|
||||
I18S("Folder where data files are stored"),
|
||||
I18S("Folder where data files are stored")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"pidfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"p", /* short option */
|
||||
"pidfile", /* long option */
|
||||
I18S("Specify the PID file"),
|
||||
I18S("Specify the PID file")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"timeout", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"T", /* short option */
|
||||
"timeout", /* long option */
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"help", /* name */
|
||||
0, /* minnum */
|
||||
0, /* maxnum */
|
||||
"h", /* short option */
|
||||
"help",
|
||||
I18S("Show this help screen."),
|
||||
I18S("Show this help screen.")
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
||||
GWEN_BUFFER *ubuf;
|
||||
|
||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(ubuf,
|
||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
||||
AQHOME_VERSION_STRING,
|
||||
argv[0]);
|
||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
||||
return 1;
|
||||
}
|
||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
||||
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./loop.h"
|
||||
#include "./c_connect.h"
|
||||
#include "./c_updatedata.h"
|
||||
#include "./c_getdatapoints.h"
|
||||
#include "./c_getlastdatapoint.h"
|
||||
#include "./c_getvalues.h"
|
||||
#include "./c_getdevices.h"
|
||||
#include "./c_setdata.h"
|
||||
#include "./c_addvalue.h"
|
||||
#include "./c_annvalue.h"
|
||||
#include "./c_moddevice.h"
|
||||
#include "./aqhome_data_p.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/data/msg_data_datapoints.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/msg_ipc_result.h"
|
||||
#include "aqhome/ipc/requests.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint_tcpd.h>
|
||||
#include <gwenhywfar/msg_ipc.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _readAndHandleIpcMessages(AQHOME_DATA *aqh);
|
||||
static void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep);
|
||||
static void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
static AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const char *nameForDriver);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeData_Loop(AQHOME_DATA *aqh, int timeoutInMsecs)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgEndpoint_IoLoop(aqh->ipcdEndpoint, timeoutInMsecs);
|
||||
_readAndHandleIpcMessages(aqh);
|
||||
|
||||
AQH_Requests_CheckTimeouts(aqh->requestTree);
|
||||
AQH_Requests_Cleanup(aqh->requestTree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeData_WriteStorageIfChanged(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (AQH_Storage_GetRuntimeFlags(aqh->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Storage modified, writing statefile");
|
||||
rv=AqHomeData_LockStorage(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error locking storage (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
rv=AQH_Storage_WriteState(aqh->storage);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing state file (%d)", rv);
|
||||
AqHomeData_UnlockStorage(aqh);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AqHomeData_UnlockStorage(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_VALUE *AqHomeData_GetOrCreateValueForDriverWithTemplate(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *valueTemplate)
|
||||
{
|
||||
const char *serviceName;
|
||||
AQH_VALUE *v;
|
||||
GWEN_BUFFER *buf;
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
serviceName=AQH_IpcEndpoint_GetServiceName(epDriver);
|
||||
valueName=AQH_Value_GetName(valueTemplate);
|
||||
deviceName=AQH_Value_GetDeviceName(valueTemplate);
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
if (deviceName && *deviceName)
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName, valueName);
|
||||
else
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", valueName);
|
||||
|
||||
v=AQH_Storage_GetValueByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
|
||||
if (v==NULL) {
|
||||
if (AQH_IpcEndpoint_GetPermissions(epDriver) & AQH_IPCENDPOINT_PERMS_ADDVALUE) {
|
||||
AQH_DEVICE *device;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
device=(deviceName && *deviceName)?_getOrCreateDeviceForDriver(aqh, epDriver, deviceName):NULL;
|
||||
|
||||
v=AQH_Value_new();
|
||||
AQH_Value_SetDriver(v, serviceName);
|
||||
AQH_Value_SetName(v, AQH_Value_GetName(valueTemplate));
|
||||
AQH_Value_SetNameForSystem(v, GWEN_Buffer_GetStart(buf));
|
||||
AQH_Value_SetValueUnits(v, AQH_Value_GetValueUnits(valueTemplate));
|
||||
AQH_Value_SetValueType(v, AQH_Value_GetValueType(valueTemplate));
|
||||
AQH_Value_SetModality(v, AQH_Value_GetModality(valueTemplate));
|
||||
AQH_Value_SetTimestampCreation(v, (uint64_t) time(NULL));
|
||||
if (device) {
|
||||
AQH_Value_SetDeviceNameForSystem(v, AQH_Device_GetNameForSystem(device));
|
||||
AQH_Value_SetDeviceName(v, AQH_Device_GetName(device));
|
||||
}
|
||||
AQH_Storage_AddValue(aqh->storage, v);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create value \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *epDriver, const char *deviceName)
|
||||
{
|
||||
const char *serviceName;
|
||||
AQH_DEVICE *device;
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
serviceName=AQH_IpcEndpoint_GetServiceName(epDriver);
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName);
|
||||
|
||||
device=AQH_Storage_GetDeviceByNameForSystem(aqh->storage, GWEN_Buffer_GetStart(buf));
|
||||
if (device==NULL) {
|
||||
if (AQH_IpcEndpoint_GetPermissions(epDriver) & AQH_IPCENDPOINT_PERMS_ADDDEVICE) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Creating device \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
device=AQH_Device_new();
|
||||
AQH_Device_SetDriver(device, serviceName);
|
||||
AQH_Device_SetName(device, deviceName);
|
||||
AQH_Device_SetNameForSystem(device, GWEN_Buffer_GetStart(buf));
|
||||
AQH_Device_SetTimestampCreation(device, (uint64_t) time(NULL));
|
||||
AQH_Storage_AddDevice(aqh->storage, device);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create device \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _readAndHandleIpcMessages(AQHOME_DATA *aqh)
|
||||
{
|
||||
if (aqh->ipcdEndpoint) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->ipcdEndpoint);
|
||||
while(ep) {
|
||||
_handleIpcEndpoint(aqh, ep);
|
||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcEndpoint(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG *msg;
|
||||
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
|
||||
DBG_INFO(NULL, "Got IPS message %d (msgId=%d, refMsgId=%d) [%s]",
|
||||
GWEN_IpcMsg_GetCode(msg),
|
||||
GWEN_IpcMsg_GetMsgId(msg),
|
||||
GWEN_IpcMsg_GetRefMsgId(msg),
|
||||
GWEN_MsgEndpoint_GetName(ep));
|
||||
if (AQH_Requests_HandleIpcMsg(aqh->requestTree, ep, msg)!=GWEN_MSG_REQUEST_RESULT_HANDLED)
|
||||
_handleIpcMsg(aqh, ep, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsg(AQHOME_DATA *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
uint16_t code;
|
||||
uint8_t protoId;
|
||||
|
||||
/* exec IPC message */
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
protoId=GWEN_IpcMsg_GetProtoId(msg);
|
||||
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeData_HandleConnect(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeData_HandleUpdateData(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeData_HandleGetValues(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeData_HandleGetDataPoints(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETLASTDATA_REQ: AqHomeData_HandleGetLastDataPoint(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeData_HandleSetData(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeData_HandleAddValue(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: AqHomeData_HandleAnnounceValue(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeData_HandleGetDevices(aqh, ep, msg); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeData_HandleModDevice(aqh, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_LOOP_H
|
||||
#define AQHOME_DATA_LOOP_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
|
||||
|
||||
void AqHomeData_Loop(AQHOME_DATA *aqh, int timeoutInMsecs);
|
||||
|
||||
int AqHomeData_WriteStorageIfChanged(AQHOME_DATA *aqh);
|
||||
|
||||
AQH_VALUE *AqHomeData_GetOrCreateValueForDriverWithTemplate(AQHOME_DATA *aqh,
|
||||
GWEN_MSG_ENDPOINT *epDriver,
|
||||
const AQH_VALUE *valueTemplate);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
#include "./init.h"
|
||||
#include "./fini.h"
|
||||
#include "./loop.h"
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
@@ -58,8 +55,9 @@ static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
#endif
|
||||
|
||||
static void _runService(AQHOME_DATA *aqh);
|
||||
static void _writeCurrentState(AQHOME_DATA *aqh);
|
||||
static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop);
|
||||
static void _writeCurrentState(AQH_OBJECT *aqh);
|
||||
static int _diffInSeconds(time_t t1, time_t t0);
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +67,7 @@ static void _writeCurrentState(AQHOME_DATA *aqh);
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
|
||||
#endif
|
||||
|
||||
static int stopService=0;
|
||||
@@ -84,7 +82,8 @@ static int stopService=0;
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
AQHOME_DATA *aqh;
|
||||
AQH_EVENT_LOOP *eventLoop;
|
||||
AQH_OBJECT *aqh;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
@@ -111,17 +110,19 @@ int main(int argc, char **argv)
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
aqh=AqHomeData_new();
|
||||
rv=AqHomeData_Init(aqh, argc, argv);
|
||||
eventLoop=AQH_EventLoop_new();
|
||||
aqh=AqHomeDataServer_new(eventLoop);
|
||||
rv=AqHomeDataServer_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
_runService(aqh);
|
||||
_runService(aqh, eventLoop);
|
||||
|
||||
AqHomeData_Fini(aqh);
|
||||
AqHomeData_free(aqh);
|
||||
AqHomeDataServer_Fini(aqh);
|
||||
AQH_Object_free(aqh);
|
||||
AQH_EventLoop_free(eventLoop);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
@@ -131,14 +132,14 @@ int main(int argc, char **argv)
|
||||
|
||||
|
||||
|
||||
void _runService(AQHOME_DATA *aqh)
|
||||
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
{
|
||||
time_t timeStart;
|
||||
time_t timeLastWrite;
|
||||
time_t timeLastConnectionCleanup;
|
||||
int timeout;
|
||||
|
||||
timeout=AqHomeData_GetTimeout(aqh);
|
||||
timeout=AqHomeDataServer_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastWrite=time(NULL);
|
||||
timeLastConnectionCleanup=time(NULL);
|
||||
@@ -146,25 +147,26 @@ void _runService(AQHOME_DATA *aqh)
|
||||
while(!stopService) {
|
||||
time_t now;
|
||||
|
||||
DBG_DEBUG(NULL, "Next loop");
|
||||
AqHomeData_Loop(aqh, 2000);
|
||||
DBG_INFO(NULL, "Next loop (%d clients)", AqHomeDataServer_GetClientNum(aqh));
|
||||
AQH_EventLoop_Run(eventLoop, 2000);
|
||||
AqHomeDataServer_HandleClientMsgs(aqh);
|
||||
|
||||
now=time(NULL);
|
||||
|
||||
if (((int)difftime(now, timeLastConnectionCleanup))>CONNCLEAN_INTERVAL_IN_SECS) {
|
||||
DBG_DEBUG(NULL, "Cleanup connections");
|
||||
GWEN_MsgEndpoint_RemoveUnconnectedAndEmptyChildren(AqHomeData_GetIpcdEndpoint(aqh));
|
||||
if (_diffInSeconds(now, timeLastConnectionCleanup)>CONNCLEAN_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Cleanup connections");
|
||||
AqHomeDataServer_CleanupClients(aqh);
|
||||
timeLastConnectionCleanup=now;
|
||||
}
|
||||
|
||||
if (((int)difftime(now, timeLastWrite))>WRITE_INTERVAL_IN_SECS) {
|
||||
DBG_DEBUG(NULL, "Write time");
|
||||
if (_diffInSeconds(now, timeLastWrite)>WRITE_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Write time");
|
||||
_writeCurrentState(aqh);
|
||||
timeLastWrite=now;
|
||||
}
|
||||
|
||||
if (timeout && ((int)difftime(now, timeStart))>timeout) {
|
||||
DBG_INFO(NULL, "Timeout");
|
||||
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
|
||||
DBG_ERROR(NULL, "Timeout");
|
||||
_writeCurrentState(aqh);
|
||||
break;
|
||||
}
|
||||
@@ -173,11 +175,17 @@ void _runService(AQHOME_DATA *aqh)
|
||||
|
||||
|
||||
|
||||
void _writeCurrentState(AQHOME_DATA *aqh)
|
||||
int _diffInSeconds(time_t t1, time_t t0)
|
||||
{
|
||||
return t1-t0;
|
||||
}
|
||||
|
||||
|
||||
void _writeCurrentState(AQH_OBJECT *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=AqHomeData_WriteStorageIfChanged(aqh);
|
||||
rv=AqHomeDataServer_WriteStorageIfChanged(aqh);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "ATTENTION: Could not write storage statefile (%d)", rv);
|
||||
}
|
||||
@@ -203,6 +211,10 @@ int _setSignalHandlers(void)
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saPIPE, SIGPIPE);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
@@ -244,6 +256,9 @@ void _signalHandler(int s)
|
||||
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
|
||||
stopService=1;
|
||||
break;
|
||||
case SIGPIPE:
|
||||
DBG_WARN(0, "Received PIPE signal");
|
||||
break;
|
||||
default:
|
||||
DBG_WARN(0, "Unknown signal %d",s);
|
||||
break;
|
||||
|
||||
67
apps/aqhome-data/s_addvalue.c
Normal file
67
apps/aqhome-data/s_addvalue.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_addvalue.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleAddValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
recvdValue=AQH_IpcdMessageValues_ReadFirstValue(tagList);
|
||||
if (recvdValue) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
|
||||
if (value==NULL)
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
else
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_BADDATA;
|
||||
|
||||
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID,
|
||||
AQH_IPC_PROTOCOL_DATA_VERSION,
|
||||
AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
resultCode, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_addvalue.h
Normal file
27
apps/aqhome-data/s_addvalue.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_ADDVALUE_H
|
||||
#define AQHOME_DATA_S_ADDVALUE_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleAddValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
50
apps/aqhome-data/s_annvalue.c
Normal file
50
apps/aqhome-data/s_annvalue.c
Normal file
@@ -0,0 +1,50 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_annvalue.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleAnnounceValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
recvdValue=AQH_IpcdMessageValues_ReadFirstValue(tagList);
|
||||
if (recvdValue) {
|
||||
AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_annvalue.h
Normal file
27
apps/aqhome-data/s_annvalue.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_ANNVALUE_H
|
||||
#define AQHOME_DATA_S_ANNVALUE_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleAnnounceValue(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
82
apps/aqhome-data/s_connect.c
Normal file
82
apps/aqhome-data/s_connect.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_connect.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_connect.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleConnect(GWEN_UNUSED AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
char *clientId=NULL;
|
||||
char *userId=NULL;
|
||||
char *passw=NULL;
|
||||
uint32_t flags;
|
||||
|
||||
clientId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_CLIENTID, NULL);
|
||||
userId=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_USERID, NULL);
|
||||
flags=AQH_Tag16_GetTagDataAsUint32(tagList, AQH_MSG_CONNECT_TAGS_FLAGS, 0);
|
||||
passw=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSG_CONNECT_TAGS_PASSWORD, NULL);
|
||||
|
||||
if (clientId)
|
||||
AQH_Endpoint_SetServiceName(ep, clientId);
|
||||
if (userId)
|
||||
AQH_Endpoint_SetUserName(ep, userId);
|
||||
|
||||
if (flags & AQH_MSG_CONNECT_FLAGS_WANTUPDATES)
|
||||
AQH_Endpoint_AddFlags(ep, AQH_ENDPOINT_FLAGS_WANTUPDATES);
|
||||
|
||||
/* TODO: add user management, for now we allow all */
|
||||
AQH_Endpoint_SetPermissions(ep,
|
||||
AQH_ENDPOINT_PERMS_LISTVALUES |
|
||||
AQH_ENDPOINT_PERMS_READVALUE |
|
||||
AQH_ENDPOINT_PERMS_ADDVALUE |
|
||||
AQH_ENDPOINT_PERMS_LISTDATA |
|
||||
AQH_ENDPOINT_PERMS_READDATA |
|
||||
AQH_ENDPOINT_PERMS_ADDDATA |
|
||||
AQH_ENDPOINT_PERMS_LISTDEVICES |
|
||||
AQH_ENDPOINT_PERMS_READDEVICE |
|
||||
AQH_ENDPOINT_PERMS_ADDDEVICE |
|
||||
AQH_ENDPOINT_PERMS_MODDEVICE);
|
||||
free(passw);
|
||||
free(userId);
|
||||
free(clientId);
|
||||
|
||||
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID,
|
||||
AQH_IPC_PROTOCOL_DATA_VERSION,
|
||||
AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
resultCode, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_connect.h
Normal file
27
apps/aqhome-data/s_connect.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_CONNECT_H
|
||||
#define AQHOME_DATA_S_CONNECT_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleConnect(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
224
apps/aqhome-data/s_getdatapoints.c
Normal file
224
apps/aqhome-data/s_getdatapoints.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_getdatapoints.h"
|
||||
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_getdata.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES 1024
|
||||
#define AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS 512
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
||||
const AQH_VALUE *value,
|
||||
int mode,
|
||||
uint64_t tsBegin, uint64_t tsEnd, uint64_t num, uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value,
|
||||
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
|
||||
uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
|
||||
static int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep, const AQH_VALUE *value, uint64_t num, uint32_t refMsgId);
|
||||
static void _sendDataPointsResponse(AQH_OBJECT *ep, const AQH_VALUE *value, const uint64_t *tablePtr,
|
||||
uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
uint32_t refMsgId;
|
||||
|
||||
refMsgId=AQH_IpcMessage_GetMsgId(recvdMsg);
|
||||
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_READDATA) {
|
||||
char *valueName;
|
||||
|
||||
valueName=AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETDATA_TAGS_NAME, NULL);
|
||||
if (valueName && *valueName) {
|
||||
AQH_VALUE *value;
|
||||
uint64_t tsBegin;
|
||||
uint64_t tsEnd;
|
||||
uint64_t numRequested;
|
||||
int mode;
|
||||
|
||||
tsBegin=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_BEGIN, 0);
|
||||
tsEnd=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_END, 0);
|
||||
numRequested=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_NUM, 0);
|
||||
mode=AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETDATA_TAGS_MODE, AQH_MSGDATA_GETDATA_MODE_FIRST);
|
||||
|
||||
value=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
|
||||
if (value) {
|
||||
int resultCode;
|
||||
|
||||
resultCode=_getAndSendDataPoints(xo->storage, ep, value, mode, tsBegin, tsEnd, numRequested, refMsgId);
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, resultCode);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Value \"%s\" does not exist", valueName);
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_NOTFOUND);
|
||||
}
|
||||
free(valueName);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Missing value name");
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_BADDATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to read data");
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_PERMS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPoints(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
||||
const AQH_VALUE *value,
|
||||
int mode,
|
||||
uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
switch(mode) {
|
||||
case AQH_MSGDATA_GETDATA_MODE_FIRST: return _getAndSendDataPointsFirst(storage, ep, value, num, refMsgId);
|
||||
case AQH_MSGDATA_GETDATA_MODE_PERIOD: return _getAndSendDataPointsPeriod(storage, ep, value, tsBegin, tsEnd, num, refMsgId);
|
||||
default:
|
||||
case AQH_MSGDATA_GETDATA_MODE_LAST: return _getAndSendDataPointsLast(storage, ep, value, num, refMsgId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsPeriod(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
||||
const AQH_VALUE *value, uint64_t tsBegin, uint64_t tsEnd, uint64_t num,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
valueId=AQH_Value_GetId(value);
|
||||
if (num==0 || num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES)
|
||||
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXTABLEENTRIES;
|
||||
tablePtr=AQH_Storage_GetDataPoints(storage, valueId, tsBegin, tsEnd, num);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSGDATA_RESULT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSGDATA_RESULT_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsLast(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
||||
const AQH_VALUE *value, uint64_t num,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
|
||||
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
|
||||
valueId=AQH_Value_GetId(value);
|
||||
tablePtr=AQH_Storage_GetLastNDataPoints(storage, valueId, num);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSGDATA_RESULT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSGDATA_RESULT_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _getAndSendDataPointsFirst(AQH_STORAGE *storage, AQH_OBJECT *ep,
|
||||
const AQH_VALUE *value, uint64_t num,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
uint64_t valueId;
|
||||
uint64_t *tablePtr;
|
||||
|
||||
if (num>AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS)
|
||||
num=AQHOMEDATA_HANDLEGETDATAPOINTS_MAXDATAPOINTS;
|
||||
valueId=AQH_Value_GetId(value);
|
||||
tablePtr=AQH_Storage_GetFirstNDataPoints(storage, valueId, num);
|
||||
if (tablePtr) {
|
||||
_sendDataPointsResponse(ep, value, tablePtr, refMsgId);
|
||||
free(tablePtr);
|
||||
return AQH_MSGDATA_RESULT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No matching datapoints for value \"%s\"", AQH_Value_GetNameForSystem(value));
|
||||
return AQH_MSGDATA_RESULT_ERROR_NODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataPointsResponse(AQH_OBJECT *ep,
|
||||
const AQH_VALUE *value, const uint64_t *tablePtr,
|
||||
uint32_t refMsgId)
|
||||
{
|
||||
int numTableEntries;
|
||||
int numDataPoints;
|
||||
AQH_MESSAGE *outMsg;
|
||||
|
||||
numTableEntries=(int)(tablePtr[0]);
|
||||
numDataPoints=numTableEntries/2;
|
||||
outMsg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_GETDATA_RSP,
|
||||
AQH_Endpoint_GetNextMessageId(ep), refMsgId,
|
||||
value, &(tablePtr[1]), numDataPoints);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_getdatapoints.h
Normal file
27
apps/aqhome-data/s_getdatapoints.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_GETDATAPOINTS_H
|
||||
#define AQHOME_DATA_S_GETDATAPOINTS_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleGetDataPoints(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
116
apps/aqhome-data/s_getdevices.c
Normal file
116
apps/aqhome-data/s_getdevices.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_getdevices.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_devices.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_DEVICESPERMSG 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleGetDevices(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, GWEN_UNUSED const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
const AQH_DEVICE_LIST *origDeviceList;
|
||||
uint32_t refMsgId;
|
||||
|
||||
refMsgId=AQH_IpcMessage_GetMsgId(msg);
|
||||
|
||||
DBG_INFO(NULL, "HandleGetDevices");
|
||||
origDeviceList=AQH_Storage_GetDeviceList(xo->storage);
|
||||
if (origDeviceList) {
|
||||
DBG_INFO(NULL, "Have a list of %d devices", AQH_Device_List_GetCount(origDeviceList));
|
||||
if (AQH_Device_List_GetCount(origDeviceList)<AQHOMEDATA_DEVICESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending all entries in one message");
|
||||
_sendDeviceList(ep, origDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
|
||||
}
|
||||
else {
|
||||
AQH_DEVICE_LIST *tmpDeviceList;
|
||||
const AQH_DEVICE *v;
|
||||
|
||||
DBG_INFO(NULL, "Sending entries in multiple messages");
|
||||
tmpDeviceList=AQH_Device_List_new();
|
||||
v=AQH_Device_List_First(origDeviceList);
|
||||
while(v) {
|
||||
const AQH_DEVICE *next;
|
||||
AQH_DEVICE *copyOfDevice;
|
||||
|
||||
next=AQH_Device_List_Next(v);
|
||||
copyOfDevice=AQH_Device_dup(v);
|
||||
AQH_Device_List_Add(copyOfDevice, tmpDeviceList);
|
||||
if (AQH_Device_List_GetCount(tmpDeviceList)>=AQHOMEDATA_DEVICESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
|
||||
_sendDeviceList(ep, tmpDeviceList, next?0:AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
|
||||
AQH_Device_List_Clear(tmpDeviceList);
|
||||
}
|
||||
v=next;
|
||||
}
|
||||
if (AQH_Device_List_GetCount(tmpDeviceList)) {
|
||||
DBG_INFO(NULL, "Sending %d devices", AQH_Device_List_GetCount(tmpDeviceList));
|
||||
_sendDeviceList(ep, tmpDeviceList, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId); /* send remaining */
|
||||
}
|
||||
AQH_Device_List_free(tmpDeviceList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
_sendDeviceList(ep, NULL, AQH_MSGDATA_DEVICES_FLAGS_LASTMSG, refMsgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDeviceList(AQH_OBJECT *ep, const AQH_DEVICE_LIST *vl, uint32_t flags, uint32_t refMsgId)
|
||||
{
|
||||
AQH_MESSAGE *msg;
|
||||
|
||||
DBG_INFO(NULL, "Sending msg (refMsgId=%d)", refMsgId);
|
||||
msg=AQH_IpcdMessageDevices_new(AQH_MSGTYPE_IPC_DATA_GETDEVICES_RSP, AQH_Endpoint_GetNextMessageId(ep), refMsgId, flags, vl);
|
||||
AQH_Endpoint_AddMsgOut(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,23 +6,22 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_ENDPOINT_HTTP_H
|
||||
#define AQH_ENDPOINT_HTTP_H
|
||||
#ifndef AQHOME_DATA_S_GETDEVICES_H
|
||||
#define AQHOME_DATA_S_GETDEVICES_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
#define AQH_ENDPOINT_HTTP_FLAGS_PASSIVE 0x0001
|
||||
|
||||
|
||||
|
||||
AQHOME_API void AQH_HttpEndpoint_Extend(GWEN_MSG_ENDPOINT *ep, uint32_t flags);
|
||||
|
||||
void AqHomeDataServer_HandleGetDevices(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
183
apps/aqhome-data/s_getvalues.c
Normal file
183
apps/aqhome-data/s_getvalues.c
Normal file
@@ -0,0 +1,183 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_getvalues.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_getvalues.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define AQHOMEDATA_VALUESPERMSG 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQH_VALUE_LIST *_getMatchingValueList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList);
|
||||
static void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t refMsgId);
|
||||
static void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId);
|
||||
static int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modality);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_VALUE_LIST *valueList;
|
||||
uint32_t refMsgId;
|
||||
|
||||
refMsgId=AQH_IpcMessage_GetMsgId(msg);
|
||||
|
||||
DBG_INFO(NULL, "HandleGetValues");
|
||||
valueList=_getMatchingValueList(xo, tagList);
|
||||
if (valueList) {
|
||||
_sendValueList(ep, valueList, refMsgId);
|
||||
AQH_Value_List_free(valueList);
|
||||
}
|
||||
else {
|
||||
/* empty list */
|
||||
_sendValueListMsg(ep, NULL, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_VALUE_LIST *_getMatchingValueList(AQHOME_SERVER *xo, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
const AQH_VALUE_LIST *origValueList;
|
||||
AQH_VALUE_LIST *tmpValueList=NULL;
|
||||
char *deviceName;
|
||||
int modality;
|
||||
|
||||
deviceName=tagList?AQH_Tag16_GetTagDataAsNewString(tagList, AQH_MSGDATA_GETVALUES_TAGS_DEVICENAME, NULL):NULL;
|
||||
modality=tagList?AQH_Tag16_GetTagDataAsUint64(tagList, AQH_MSGDATA_GETVALUES_TAGS_MODALITY, 0):0;
|
||||
|
||||
origValueList=AQH_Storage_GetValueList(xo->storage);
|
||||
if (origValueList) {
|
||||
const AQH_VALUE *v;
|
||||
|
||||
tmpValueList=AQH_Value_List_new();
|
||||
v=AQH_Value_List_First(origValueList);
|
||||
while(v) {
|
||||
if (_valueMatches(v, deviceName, modality)) {
|
||||
AQH_VALUE *copyOfValue;
|
||||
|
||||
copyOfValue=AQH_Value_dup(v);
|
||||
AQH_Value_List_Add(copyOfValue, tmpValueList);
|
||||
}
|
||||
v=AQH_Value_List_Next(v);
|
||||
}
|
||||
if (AQH_Value_List_GetCount(tmpValueList)<1) {
|
||||
AQH_Value_List_free(tmpValueList);
|
||||
tmpValueList=NULL;
|
||||
}
|
||||
}
|
||||
free(deviceName);
|
||||
|
||||
return tmpValueList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueList(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t refMsgId)
|
||||
{
|
||||
AQH_VALUE_LIST *tmpValueList;
|
||||
const AQH_VALUE *v;
|
||||
|
||||
tmpValueList=AQH_Value_List_new();
|
||||
v=AQH_Value_List_First(vl);
|
||||
while(v) {
|
||||
const AQH_VALUE *next;
|
||||
AQH_VALUE *copyOfValue;
|
||||
|
||||
next=AQH_Value_List_Next(v);
|
||||
copyOfValue=AQH_Value_dup(v);
|
||||
AQH_Value_List_Add(copyOfValue, tmpValueList);
|
||||
if (AQH_Value_List_GetCount(tmpValueList)>=AQHOMEDATA_VALUESPERMSG) {
|
||||
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
|
||||
_sendValueListMsg(ep, tmpValueList, next?0:AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId);
|
||||
AQH_Value_List_Clear(tmpValueList);
|
||||
}
|
||||
v=next;
|
||||
}
|
||||
if (AQH_Value_List_GetCount(tmpValueList)) {
|
||||
DBG_INFO(NULL, "Sending %d values", AQH_Value_List_GetCount(tmpValueList));
|
||||
_sendValueListMsg(ep, tmpValueList, AQH_MSGDATA_VALUES_FLAGS_LASTMSG, refMsgId); /* send remaining */
|
||||
}
|
||||
AQH_Value_List_free(tmpValueList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueListMsg(AQH_OBJECT *ep, const AQH_VALUE_LIST *vl, uint32_t flags, uint32_t refMsgId)
|
||||
{
|
||||
AQH_MESSAGE *msg;
|
||||
|
||||
DBG_INFO(NULL, "Sending msg (refMsgId=%d)", refMsgId);
|
||||
msg=AQH_IpcdMessageValues_new(AQH_MSGTYPE_IPC_DATA_GETVALUES_RSP, AQH_Endpoint_GetNextMessageId(ep), refMsgId, flags, vl);
|
||||
AQH_Endpoint_AddMsgOut(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _valueMatches(const AQH_VALUE *v, const char *deviceName, int modality)
|
||||
{
|
||||
if (modality!=AQH_ValueModality_Unknown) {
|
||||
int valModality;
|
||||
|
||||
valModality=AQH_Value_GetModality(v);
|
||||
if (valModality!=modality)
|
||||
return 0;
|
||||
}
|
||||
if (deviceName && *deviceName) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_Value_GetDeviceNameForSystem(v);
|
||||
if (s && *s && GWEN_Text_ComparePattern(s, deviceName, 0)==-1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_getvalues.h
Normal file
27
apps/aqhome-data/s_getvalues.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_GETVALUES_H
|
||||
#define AQHOME_DATA_S_GETVALUES_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleGetValues(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
105
apps/aqhome-data/s_moddevice.c
Normal file
105
apps/aqhome-data/s_moddevice.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_moddevice.h"
|
||||
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_devices.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleModDevice(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
|
||||
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_MODDEVICE) {
|
||||
AQH_DEVICE *device;
|
||||
|
||||
device=AQH_IpcdMessageDevices_ReadFirstDevice(tagList);
|
||||
if (device) {
|
||||
const char *deviceNameForSystem;
|
||||
|
||||
deviceNameForSystem=AQH_Device_GetNameForSystem(device);
|
||||
if (deviceNameForSystem && *deviceNameForSystem) {
|
||||
AQH_DEVICE *storedDevice;
|
||||
|
||||
storedDevice=AQH_Storage_GetDeviceByNameForSystem(xo->storage, deviceNameForSystem);
|
||||
if (storedDevice) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_Device_GetNameForGui(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetNameForGui(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetRoomName(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetRoomName(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetLocation(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetLocation(storedDevice, s);
|
||||
|
||||
s=AQH_Device_GetDescription(device);
|
||||
if (s && *s)
|
||||
AQH_Device_SetDescription(storedDevice, s);
|
||||
|
||||
AQH_Storage_AddRuntimeFlags(xo->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
|
||||
resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device \"%s\" not found", deviceNameForSystem);
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No name for value");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_NOTFOUND;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No device info in message");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No permissions to read data");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
|
||||
}
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, AQH_IpcMessage_GetMsgId(recvdMsg), resultCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_moddevice.h
Normal file
27
apps/aqhome-data/s_moddevice.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_MODDEVICE_H
|
||||
#define AQHOME_DATA_S_MODDEVICE_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleModDevice(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
282
apps/aqhome-data/s_setdata.c
Normal file
282
apps/aqhome-data/s_setdata.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_setdata.h"
|
||||
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_setdata.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
|
||||
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o,
|
||||
AQH_OBJECT *epSrc, uint32_t requestMsgId,
|
||||
AQH_OBJECT *epDriver,
|
||||
const AQH_VALUE *v, const char *data);
|
||||
static void _rqSubRequestFinished(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST *subRq, int reason);
|
||||
static void _rqAbort(AQH_MSG_REQUEST *rq, int reason);
|
||||
|
||||
static AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data);
|
||||
static int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg);
|
||||
static void _subRqAbort(AQH_MSG_REQUEST *rq, int reason);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
uint32_t msgId;
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
msgId=AQH_IpcMessage_GetMsgId(recvdMsg);
|
||||
DBG_INFO(NULL, "Received IPC SetDataRequest message (msgId=%d)", msgId);
|
||||
|
||||
recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList);
|
||||
if (recvdValue) {
|
||||
const char *valueName;
|
||||
char *valueDataFreeable;
|
||||
AQH_VALUE *systemValue;
|
||||
|
||||
valueName=AQH_Value_GetNameForSystem(recvdValue);
|
||||
valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList);
|
||||
|
||||
systemValue=AQH_Storage_GetValueByNameForSystem(xo->storage, valueName);
|
||||
if (systemValue) {
|
||||
if (AQH_Value_GetValueType(systemValue)==AQH_ValueType_Actor) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=AQH_Value_GetDriver(systemValue);
|
||||
if (driverName && *driverName) {
|
||||
AQH_OBJECT *epDriver;
|
||||
|
||||
epDriver=AqHomeDataServer_GetIpcEndpointByServiceName(o, driverName);
|
||||
if (epDriver) {
|
||||
AQH_MSG_REQUEST *rq;
|
||||
|
||||
DBG_ERROR(NULL, "Creating SETDATA request for driver endpoint (%s)", AQH_Endpoint_GetServiceName(epDriver));
|
||||
rq=_mkRequest_SetData(o, epSrc, msgId, epDriver, systemValue, valueDataFreeable);
|
||||
AqHomeDataServer_AddRequestToTree(o, rq);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Driver \"%s\" not available", driverName);
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No driver name");
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
|
||||
}
|
||||
} /* if actor */
|
||||
else {
|
||||
DBG_ERROR(NULL, "Value \"%s\" is not an actor", valueName);
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unknown value \"%s\"", valueName);
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_NOTFOUND);
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
free(valueDataFreeable);
|
||||
} /* if recvdValue */
|
||||
else {
|
||||
DBG_ERROR(NULL, "No value in message");
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(epSrc, msgId, AQH_MSGDATA_RESULT_ERROR_BADDATA);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* IPC Request SETDATA
|
||||
*/
|
||||
|
||||
AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o,
|
||||
AQH_OBJECT *epSrc, uint32_t requestMsgId,
|
||||
AQH_OBJECT *epDriver,
|
||||
const AQH_VALUE *v, const char *data)
|
||||
{
|
||||
AQH_MSG_REQUEST *rq;
|
||||
AQH_MSG_REQUEST *subRq;
|
||||
|
||||
rq=AQH_MsgRequest_new();
|
||||
AQH_MsgRequest_SetPrivateData(rq, o);
|
||||
AQH_MsgRequest_SetEndpoint(rq, epSrc);
|
||||
AQH_MsgRequest_SetRequestMsgId(rq, requestMsgId);
|
||||
AQH_MsgRequest_SetSubRequestFinishedFn(rq, _rqSubRequestFinished);
|
||||
AQH_MsgRequest_SetAbortFn(rq, _rqAbort);
|
||||
AQH_MsgRequest_SetTimestamps(rq, R_SETDATA_REQUEST_EXPIRE_SECS);
|
||||
|
||||
subRq=_mkSubRequest_SetData(o, epDriver, v, data);
|
||||
AQH_MsgRequest_Tree2_AddChild(rq, subRq);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqSubRequestFinished(AQH_MSG_REQUEST *rq, AQH_MSG_REQUEST *subRq, int reason)
|
||||
{
|
||||
AQH_OBJECT *ep;
|
||||
uint32_t refMsgId;
|
||||
int result;
|
||||
|
||||
DBG_DEBUG(NULL, "SubRequest finished (reason: %d)", reason);
|
||||
refMsgId=AQH_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=AQH_MsgRequest_GetEndpoint(rq);
|
||||
result=AQH_MsgRequest_GetResult(subRq);
|
||||
|
||||
if (reason==AQH_MSG_REQUEST_REASON_ABORTED)
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
|
||||
else
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, result);
|
||||
|
||||
AQH_MsgRequest_SetResult(rq, result);
|
||||
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _rqAbort(AQH_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
AQH_OBJECT *ep;
|
||||
uint32_t refMsgId;
|
||||
AQH_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
refMsgId=AQH_MsgRequest_GetRequestMsgId(rq);
|
||||
ep=AQH_MsgRequest_GetEndpoint(rq);
|
||||
AqHomeDataServer_SendResponseResultToEndpoint(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
|
||||
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=AQH_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
AQH_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Driver Request SETDATA
|
||||
*/
|
||||
|
||||
|
||||
AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *v, const char *data)
|
||||
{
|
||||
AQH_MSG_REQUEST *rq;
|
||||
uint16_t msgId;
|
||||
AQH_MESSAGE *driverMsg;
|
||||
|
||||
rq=AQH_MsgRequest_new();
|
||||
AQH_MsgRequest_SetPrivateData(rq, o);
|
||||
AQH_MsgRequest_SetEndpoint(rq, epDriver);
|
||||
|
||||
AQH_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
|
||||
AQH_MsgRequest_SetAbortFn(rq, _subRqAbort);
|
||||
|
||||
msgId=AQH_Endpoint_GetNextMessageId(epDriver);
|
||||
AQH_MsgRequest_SetRequestMsgId(rq, msgId);
|
||||
AQH_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
|
||||
|
||||
driverMsg=AQH_IpcdMessageSetData_new(AQH_MSGTYPE_IPC_DATA_SETDATA, msgId, 0, v, data);
|
||||
AQH_Endpoint_AddMsgOut(epDriver, driverMsg);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg)
|
||||
{
|
||||
DBG_DEBUG(NULL, "Checking message from driver");
|
||||
if (AQH_IpcMessage_GetCode(msg)==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
|
||||
if (tagList) {
|
||||
uint32_t result;
|
||||
AQH_MSG_REQUEST *rqParent;
|
||||
|
||||
result=AQH_IpcMessageResult_GetResult(tagList);
|
||||
DBG_INFO(NULL, "Received result for request: %d", result);
|
||||
AQH_MsgRequest_SetResult(rq, result);
|
||||
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
|
||||
rqParent=AQH_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
AQH_MsgRequest_SubRequestFinished(rqParent, rq, AQH_MSG_REQUEST_REASON_DONE);
|
||||
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
return AQH_MSG_REQUEST_RESULT_HANDLED;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Bad message %d (no TAG16 data)", AQH_IpcMessage_GetCode(msg));
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unexpected response message %d", AQH_IpcMessage_GetCode(msg));
|
||||
}
|
||||
|
||||
return AQH_MSG_REQUEST_RESULT_NOT_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _subRqAbort(AQH_MSG_REQUEST *rq, int reason)
|
||||
{
|
||||
AQH_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL, "Aborting request");
|
||||
|
||||
AQH_MsgRequest_SetResult(rq, AQH_MSGDATA_RESULT_ERROR_GENERIC);
|
||||
AQH_MsgRequest_SetState(rq, AQH_MSG_REQUEST_STATE_DONE);
|
||||
|
||||
rqParent=AQH_MsgRequest_Tree2_GetParent(rq);
|
||||
if (rqParent)
|
||||
AQH_MsgRequest_SubRequestFinished(rqParent, rq, reason);
|
||||
}
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_setdata.h
Normal file
27
apps/aqhome-data/s_setdata.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_SETDATA_H
|
||||
#define AQHOME_DATA_S_SETDATA_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *epSrc, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
171
apps/aqhome-data/s_updatedata.c
Normal file
171
apps/aqhome-data/s_updatedata.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./s_updatedata.h"
|
||||
|
||||
#include "./server_p.h"
|
||||
#include <aqhome/data/value.h>
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_multidata.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_result.h"
|
||||
#include "aqhome/msg/ipc/m_ipc_tag16.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _storeDataPoints(AQHOME_SERVER *xo, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues);
|
||||
static void _sendDataChangedMsgToAllClients(AQHOME_SERVER *xo, AQH_OBJECT *epSrc,
|
||||
const AQH_VALUE *v, const uint64_t *dataPoints, int numValues);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_HandleUpdateData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (tagList) {
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=AqHomeDataServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
recvdValue=AQH_IpcdMessageMultiData_ReadValue(tagList);
|
||||
if (recvdValue) {
|
||||
const char *valueName;
|
||||
const uint64_t *dataPoints=NULL;
|
||||
uint64_t numberOfPoints=0;
|
||||
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
AQH_IpcdMessageMultiData_ReadDatapoints(tagList, &dataPoints, &numberOfPoints);
|
||||
if (numberOfPoints>0) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(o, ep, recvdValue);
|
||||
if (value) {
|
||||
if (AQH_Endpoint_GetPermissions(ep) & AQH_ENDPOINT_PERMS_ADDDATA) {
|
||||
resultCode=_storeDataPoints(xo, value, dataPoints, numberOfPoints);
|
||||
if (resultCode==AQH_MSGDATA_RESULT_SUCCESS)
|
||||
_sendDataChangedMsgToAllClients(xo, ep, value, dataPoints, numberOfPoints);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No permissions to add data to value \"%s\"", valueName);
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No permissions to add/create value \"%s\"", valueName);
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_PERMS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No datapoints");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID;
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No value");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_INVALID;
|
||||
}
|
||||
|
||||
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID,
|
||||
AQH_IPC_PROTOCOL_DATA_VERSION,
|
||||
AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
resultCode, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _storeDataPoints(AQHOME_SERVER *xo, const AQH_VALUE *v, const uint64_t *dataPoints, unsigned int numValues)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i=0; i<numValues; i++) {
|
||||
uint64_t timestamp;
|
||||
union {double f; uint64_t i;} u;
|
||||
int rv;
|
||||
|
||||
timestamp=*(dataPoints++);
|
||||
u.i=*(dataPoints++);
|
||||
rv=AQH_Storage_AddDatapoint(xo->storage, AQH_Value_GetId(v), timestamp, u.f);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return AQH_MSGDATA_RESULT_ERROR_GENERIC;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Datapoint added for value \"%s\"", AQH_Value_GetNameForSystem(v));
|
||||
}
|
||||
} /* for */
|
||||
|
||||
return AQH_MSGDATA_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataChangedMsgToAllClients(AQHOME_SERVER *xo, AQH_OBJECT *epSrc, const AQH_VALUE *v, const uint64_t *dataPoints, int numValues)
|
||||
{
|
||||
AQH_OBJECT *ep;
|
||||
|
||||
ep=AQH_Object_List_First(xo->tcpClientList);
|
||||
while(ep) {
|
||||
if (ep!=epSrc) {
|
||||
if (AQH_Endpoint_GetFlags(ep) & AQH_ENDPOINT_FLAGS_WANTUPDATES) {
|
||||
AQH_MESSAGE *msg;
|
||||
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Sending update msg to endpoint");
|
||||
msg=AQH_IpcdMessageMultiData_new(AQH_MSGTYPE_IPC_DATA_DATACHANGED,
|
||||
AQH_Endpoint_GetNextMessageId(ep), 0,
|
||||
v, dataPoints, numValues);
|
||||
AQH_Endpoint_AddMsgOut(ep, msg);
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Endpoint doesn't want updates");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Not sending update msg to source of updates");
|
||||
}
|
||||
ep=AQH_Object_List_Next(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-data/s_updatedata.h
Normal file
27
apps/aqhome-data/s_updatedata.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_S_UPDATEDATA_H
|
||||
#define AQHOME_DATA_S_UPDATEDATA_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleUpdateData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
876
apps/aqhome-data/server.c
Normal file
876
apps/aqhome-data/server.c
Normal file
@@ -0,0 +1,876 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./server_p.h"
|
||||
#include "./s_connect.h"
|
||||
#include "./s_getdevices.h"
|
||||
#include "./s_getvalues.h"
|
||||
#include "./s_addvalue.h"
|
||||
#include "./s_annvalue.h"
|
||||
#include "./s_updatedata.h"
|
||||
#include "./s_setdata.h"
|
||||
#include "./s_getdatapoints.h"
|
||||
#include "./s_moddevice.h"
|
||||
|
||||
#include <aqhome/aqhome.h>
|
||||
#include <aqhome/ipc2/ipc_server.h>
|
||||
#include <aqhome/ipc2/tcpd_object.h>
|
||||
#include <aqhome/msg/ipc/m_ipc.h>
|
||||
#include <aqhome/msg/ipc/m_ipc_result.h>
|
||||
#include <aqhome/msg/ipc/m_ipc_tag16.h>
|
||||
#include <aqhome/msg/ipc/data/m_ipcd.h>
|
||||
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
AQH_AQHOME_SERVER_SLOT_NEWCLIENT=1,
|
||||
AQH_AQHOME_SERVER_SLOT_CLOSED
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* global vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
GWEN_INHERIT(AQH_OBJECT, AQHOME_SERVER)
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
||||
static int _setupStorage(AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs);
|
||||
static int _setupIpc(AQH_OBJECT *o, AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs);
|
||||
static int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, int param1, void *param2);
|
||||
static int _handleNewClient(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint);
|
||||
static int _handleClientDown(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint);
|
||||
static void _handleMsgsFromClient(AQH_OBJECT *o, AQHOME_SERVER *xo, AQH_OBJECT *ep);
|
||||
static void _handleMsgFromClient(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
|
||||
static AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_SERVER *xo, AQH_OBJECT *epDriver, const char *deviceName);
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementation
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQH_OBJECT *AqHomeDataServer_new(AQH_EVENT_LOOP *eventLoop)
|
||||
{
|
||||
AQH_OBJECT *o;
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
o=AQH_Object_new(eventLoop);
|
||||
GWEN_NEW_OBJECT(AQHOME_SERVER, xo);
|
||||
GWEN_INHERIT_SETDATA(AQH_OBJECT, AQHOME_SERVER, o, xo, _freeData);
|
||||
xo->storageMutex=GWEN_Mutex_new();
|
||||
xo->tcpClientList=AQH_Object_List_new();
|
||||
xo->requestTree=AQH_MsgRequest_new();
|
||||
|
||||
AQH_Object_SetSignalHandlerFn(o, _handleSignal);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GWENHYWFAR_CB _freeData(GWEN_UNUSED void *bp, void *p)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=(AQHOME_SERVER*) p;
|
||||
GWEN_Mutex_free(xo->storageMutex);
|
||||
if (xo->ipcServer) {
|
||||
AQH_Object_Disable(xo->ipcServer);
|
||||
AQH_Object_free(xo->ipcServer);
|
||||
xo->ipcServer=NULL;
|
||||
}
|
||||
if (xo->tcpClientList) {
|
||||
AQH_Object_List_free(xo->tcpClientList);
|
||||
xo->tcpClientList=NULL;
|
||||
}
|
||||
GWEN_DB_Group_free(xo->dbArgs);
|
||||
AQH_Storage_free(xo->storage);
|
||||
AQH_MsgRequest_free(xo->requestTree);
|
||||
free(xo->pidFile);
|
||||
|
||||
GWEN_FREE_OBJECT(xo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* getters, setters
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
AQHOME_SERVER *AqHomeDataServer_GetServerData(const AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
return xo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeDataServer_GetTimeout(const AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo)
|
||||
return xo->timeout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeDataServer_GetClientNum(const AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo)
|
||||
return AQH_Object_List_GetCount(xo->tcpClientList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* init
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
int AqHomeDataServer_Init(AQH_OBJECT *o, int argc, char **argv)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
int rv;
|
||||
const char *s;
|
||||
|
||||
dbArgs=GWEN_DB_Group_new("args");
|
||||
rv=_readArgs(argc, argv, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
|
||||
xo->dbArgs=dbArgs;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_LOGGER_LEVEL ll;
|
||||
|
||||
ll=GWEN_Logger_Name2Level(s);
|
||||
GWEN_Logger_SetLevel(NULL, ll);
|
||||
}
|
||||
|
||||
xo->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_DATA_DEFAULT_PIDFILE);
|
||||
if (s && *s) {
|
||||
free(xo->pidFile);
|
||||
xo->pidFile=strdup(s);
|
||||
rv=_createPidFile(s);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv=_setupStorage(xo, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_setupIpc(o, xo, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Not of type AQHOME_SERVER object");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupStorage(AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *dataFolder;
|
||||
GWEN_BUFFER *nameBuf;
|
||||
AQH_STORAGE *sto;
|
||||
int rv;
|
||||
|
||||
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_DATA_DEFAULT_DATADIR);
|
||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(nameBuf, "%s%s%s", dataFolder, GWEN_DIR_SEPARATOR_S, AQHOME_DATA_STATEFILENAME);
|
||||
|
||||
sto=AQH_Storage_new();
|
||||
AQH_Storage_SetStateFile(sto, GWEN_Buffer_GetStart(nameBuf));
|
||||
AQH_Storage_SetDataFileFolder(sto, dataFolder);
|
||||
GWEN_Buffer_free(nameBuf);
|
||||
|
||||
rv=AQH_Storage_Init(sto);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQH_Storage_free(sto);
|
||||
return rv;
|
||||
}
|
||||
xo->storage=sto;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupIpc(AQH_OBJECT *o, AQHOME_SERVER *xo, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
|
||||
if (!(tcpAddress && *tcpAddress))
|
||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, NULL);
|
||||
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, -1);
|
||||
if (tcpPort<0)
|
||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_DATA_DEFAULT_IPC_PORT);
|
||||
|
||||
if (tcpAddress && *tcpAddress && tcpPort>0) {
|
||||
int fd;
|
||||
|
||||
DBG_ERROR(NULL, "Starting TCP service on \"%s\":%d", tcpAddress, tcpPort);
|
||||
fd=AQH_TcpdObject_CreateListeningSocket(tcpAddress, tcpPort);
|
||||
if (fd<0) {
|
||||
DBG_INFO(NULL, "here");
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
xo->ipcServer=AQH_IpcServerObject_new(AQH_Object_GetEventLoop(o), fd);
|
||||
AQH_Object_AddLink(xo->ipcServer, AQH_IPC_SERVER_SIGNAL_NEWCLIENT, AQH_AQHOME_SERVER_SLOT_NEWCLIENT, o);
|
||||
AQH_Object_Enable(xo->ipcServer);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Missing server address");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* fini
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_Fini(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
if (xo->pidFile)
|
||||
remove(xo->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* signal handler
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
int _handleSignal(AQH_OBJECT *o, uint32_t slotId, AQH_OBJECT *senderObject, GWEN_UNUSED int param1, void *param2)
|
||||
{
|
||||
switch(slotId) {
|
||||
case AQH_AQHOME_SERVER_SLOT_NEWCLIENT: return _handleNewClient(o, (AQH_OBJECT*) param2);
|
||||
case AQH_AQHOME_SERVER_SLOT_CLOSED: return _handleClientDown(o, senderObject);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0; /* not handled */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleNewClient(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
DBG_INFO(NULL, "New IPC client");
|
||||
AQH_Object_AddLink(clientEndpoint, AQH_ENDPOINT_SIGNAL_CLOSED, AQH_AQHOME_SERVER_SLOT_CLOSED, o);
|
||||
AQH_Object_List_Add(clientEndpoint, xo->tcpClientList);
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
return 0; /* not handled */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handleClientDown(AQH_OBJECT *o, AQH_OBJECT *clientEndpoint)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
DBG_INFO(NULL, "IPC client down");
|
||||
AQH_Object_AddFlags(clientEndpoint, AQH_OBJECT_FLAGS_DELETE);
|
||||
return 1; /* handled */
|
||||
}
|
||||
|
||||
return 0; /* not handled */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* client management functions
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
void AqHomeDataServer_CleanupClients(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
AQH_OBJECT *ep;
|
||||
|
||||
ep=AQH_Object_List_First(xo->tcpClientList);
|
||||
while(ep) {
|
||||
AQH_OBJECT *epNext;
|
||||
|
||||
epNext=AQH_Object_List_Next(ep);
|
||||
if (AQH_Object_GetFlags(ep) & AQH_OBJECT_FLAGS_DELETE) {
|
||||
AQH_Object_List_Del(ep);
|
||||
AQH_Object_free(ep);
|
||||
}
|
||||
ep=epNext;
|
||||
} /* while */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeDataServer_HandleClientMsgs(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
AQH_OBJECT *ep;
|
||||
|
||||
ep=AQH_Object_List_First(xo->tcpClientList);
|
||||
while(ep) {
|
||||
AQH_OBJECT *epNext;
|
||||
|
||||
epNext=AQH_Object_List_Next(ep);
|
||||
_handleMsgsFromClient(o, xo, ep);
|
||||
ep=epNext;
|
||||
} /* while */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgsFromClient(AQH_OBJECT *o, AQHOME_SERVER *xo, AQH_OBJECT *ep)
|
||||
{
|
||||
AQH_MESSAGE *msg;
|
||||
|
||||
while( (msg=AQH_Endpoint_GetNextMsgIn(ep)) ) {
|
||||
AQH_Message_SetObject(msg, ep);
|
||||
if (AQH_Request_Tree2_HandleIpcMsg(xo->requestTree, ep, msg)!=AQH_MSG_REQUEST_RESULT_HANDLED)
|
||||
_handleMsgFromClient(o, ep, msg);
|
||||
AQH_Message_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgFromClient(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg)
|
||||
{
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
uint16_t code;
|
||||
uint8_t protoId;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(msg, 0);
|
||||
|
||||
code=AQH_IpcMessage_GetCode(msg);
|
||||
protoId=AQH_IpcMessage_GetProtoId(msg);
|
||||
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
|
||||
DBG_INFO(NULL, "Received IPC packet %d (%x)", (int) code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_CONNECT_REQ: AqHomeDataServer_HandleConnect(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_UPDATEDATA: AqHomeDataServer_HandleUpdateData(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETVALUES_REQ: AqHomeDataServer_HandleGetValues(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDATA_REQ: AqHomeDataServer_HandleGetDataPoints(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeDataServer_HandleSetData(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ADDVALUE: AqHomeDataServer_HandleAddValue(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE: AqHomeDataServer_HandleAnnounceValue(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_GETDEVICES_REQ: AqHomeDataServer_HandleGetDevices(o, ep, msg, tagList); break;
|
||||
case AQH_MSGTYPE_IPC_DATA_MODDEVICE_REQ: AqHomeDataServer_HandleModDevice(o, ep, msg, tagList); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_OBJECT *AqHomeDataServer_GetIpcEndpointByServiceName(const AQH_OBJECT *o, const char *serviceName)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
AQH_OBJECT *ep;
|
||||
|
||||
ep=AQH_Object_List_First(xo->tcpClientList);
|
||||
while(ep) {
|
||||
const char *s;
|
||||
|
||||
s=AQH_Endpoint_GetServiceName(ep);
|
||||
if (s && *s && strcasecmp(s, serviceName)==0)
|
||||
return ep;
|
||||
ep=AQH_Object_List_Next(ep);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeDataServer_SendResponseResultToEndpoint(AQH_OBJECT *ep, uint32_t refMsgId, int result)
|
||||
{
|
||||
AQH_MESSAGE *msg;
|
||||
|
||||
msg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_DATA_ID, AQH_IPC_PROTOCOL_DATA_VERSION, AQH_MSGTYPE_IPC_DATA_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep), refMsgId, result, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* request management functions
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
AQH_MSG_REQUEST *AqHomeDataServer_GetRequestTree(const AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo)
|
||||
return xo->requestTree;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeDataServer_AddRequestToTree(AQH_OBJECT *o, AQH_MSG_REQUEST *rq)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo && rq)
|
||||
AQH_MsgRequest_Tree2_AddChild(xo->requestTree, rq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeDataServer_CleanupRequests(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
AQH_Request_Tree2_CheckTimeouts(xo->requestTree);
|
||||
AQH_Request_Tree2_Cleanup(xo->requestTree);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* storage management functions
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
int AqHomeDataServer_LockStorage(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Mutex_Lock(xo->storageMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeDataServer_UnlockStorage(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Mutex_Unlock(xo->storageMutex);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
|
||||
return rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeDataServer_WriteStorageIfChanged(AQH_OBJECT *o)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
if (AQH_Storage_GetRuntimeFlags(xo->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Storage modified, writing statefile");
|
||||
rv=AqHomeDataServer_LockStorage(o);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error locking storage (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
rv=AQH_Storage_WriteState(xo->storage);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing state file (%d)", rv);
|
||||
AqHomeDataServer_UnlockStorage(o);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AqHomeDataServer_UnlockStorage(o);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_VALUE *AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *valueTemplate)
|
||||
{
|
||||
AQHOME_SERVER *xo;
|
||||
|
||||
xo=GWEN_INHERIT_GETDATA(AQH_OBJECT, AQHOME_SERVER, o);
|
||||
if (xo) {
|
||||
const char *serviceName;
|
||||
AQH_VALUE *v;
|
||||
GWEN_BUFFER *buf;
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
serviceName=AQH_Endpoint_GetServiceName(epDriver);
|
||||
valueName=AQH_Value_GetName(valueTemplate);
|
||||
deviceName=AQH_Value_GetDeviceName(valueTemplate);
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
if (deviceName && *deviceName)
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName, valueName);
|
||||
else
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", valueName);
|
||||
|
||||
v=AQH_Storage_GetValueByNameForSystem(xo->storage, GWEN_Buffer_GetStart(buf));
|
||||
if (v==NULL) {
|
||||
if (AQH_Endpoint_GetPermissions(epDriver) & AQH_ENDPOINT_PERMS_ADDVALUE) {
|
||||
AQH_DEVICE *device;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Creating value \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
device=(deviceName && *deviceName)?_getOrCreateDeviceForDriver(xo, epDriver, deviceName):NULL;
|
||||
|
||||
v=AQH_Value_new();
|
||||
AQH_Value_SetDriver(v, serviceName);
|
||||
AQH_Value_SetName(v, AQH_Value_GetName(valueTemplate));
|
||||
AQH_Value_SetNameForSystem(v, GWEN_Buffer_GetStart(buf));
|
||||
AQH_Value_SetValueUnits(v, AQH_Value_GetValueUnits(valueTemplate));
|
||||
AQH_Value_SetValueType(v, AQH_Value_GetValueType(valueTemplate));
|
||||
AQH_Value_SetModality(v, AQH_Value_GetModality(valueTemplate));
|
||||
AQH_Value_SetTimestampCreation(v, (uint64_t) time(NULL));
|
||||
if (device) {
|
||||
AQH_Value_SetDeviceNameForSystem(v, AQH_Device_GetNameForSystem(device));
|
||||
AQH_Value_SetDeviceName(v, AQH_Device_GetName(device));
|
||||
}
|
||||
AQH_Storage_AddValue(xo->storage, v);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create value \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
return v;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_DEVICE *_getOrCreateDeviceForDriver(AQHOME_SERVER *xo, AQH_OBJECT *epDriver, const char *deviceName)
|
||||
{
|
||||
const char *serviceName;
|
||||
AQH_DEVICE *device;
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
serviceName=AQH_Endpoint_GetServiceName(epDriver);
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(buf, "%s/%s", (serviceName && *serviceName)?serviceName:"unknown", deviceName);
|
||||
|
||||
device=AQH_Storage_GetDeviceByNameForSystem(xo->storage, GWEN_Buffer_GetStart(buf));
|
||||
if (device==NULL) {
|
||||
if (AQH_Endpoint_GetPermissions(epDriver) & AQH_ENDPOINT_PERMS_ADDDEVICE) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Creating device \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
device=AQH_Device_new();
|
||||
AQH_Device_SetDriver(device, serviceName);
|
||||
AQH_Device_SetName(device, deviceName);
|
||||
AQH_Device_SetNameForSystem(device, GWEN_Buffer_GetStart(buf));
|
||||
AQH_Device_SetTimestampCreation(device, (uint64_t) time(NULL));
|
||||
AQH_Storage_AddDevice(xo->storage, device);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "No permissions to create device \"%s\"", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
* helper functions
|
||||
* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
*/
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
int pidfd;
|
||||
|
||||
if (remove(pidFilename)==0) {
|
||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (pidfd < 0) {
|
||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
f = fdopen(pidfd, "w");
|
||||
#else /* HAVE_STAT_H */
|
||||
f=fopen(pidFilename,"w+");
|
||||
#endif /* HAVE_STAT_H */
|
||||
|
||||
/* write pid */
|
||||
#ifdef HAVE_GETPID
|
||||
fprintf(f,"%d\n",getpid());
|
||||
#else
|
||||
fprintf(f,"-1\n");
|
||||
#endif
|
||||
if (fclose(f)) {
|
||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
int rv;
|
||||
const GWEN_ARGS args[]= {
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"loglevel", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"L", /* short option */
|
||||
"loglevel", /* long option */
|
||||
I18S("Specify loglevel"), /* short description */
|
||||
I18S("Specify loglevel") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"tcpAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"t", /* short option */
|
||||
"tcpaddress", /* long option */
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)"),
|
||||
I18S("Specify the TCP address to listen on (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"tcpPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"P", /* short option */
|
||||
"tcpport", /* long option */
|
||||
I18S("Specify the TCP port to listen on"),
|
||||
I18S("Specify the TCP port to listen on")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"datafolder", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"datafolder", /* long option */
|
||||
I18S("Folder where data files are stored"),
|
||||
I18S("Folder where data files are stored")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"pidfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"p", /* short option */
|
||||
"pidfile", /* long option */
|
||||
I18S("Specify the PID file"),
|
||||
I18S("Specify the PID file")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"timeout", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"T", /* short option */
|
||||
"timeout", /* long option */
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"help", /* name */
|
||||
0, /* minnum */
|
||||
0, /* maxnum */
|
||||
"h", /* short option */
|
||||
"help",
|
||||
I18S("Show this help screen."),
|
||||
I18S("Show this help screen.")
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
||||
GWEN_BUFFER *ubuf;
|
||||
|
||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(ubuf,
|
||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
||||
AQHOME_VERSION_STRING,
|
||||
argv[0]);
|
||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
||||
return 1;
|
||||
}
|
||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
||||
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
60
apps/aqhome-data/server.h
Normal file
60
apps/aqhome-data/server.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_SERVER_H
|
||||
#define AQHOME_DATA_SERVER_H
|
||||
|
||||
|
||||
#include <aqhome/data/storage.h>
|
||||
#include <aqhome/events2/object.h>
|
||||
#include <aqhome/ipc2/msgrequest.h>
|
||||
|
||||
|
||||
#define AQH_ENDPOINT_PERMS_LISTVALUES 0x0001
|
||||
#define AQH_ENDPOINT_PERMS_READVALUE 0x0002
|
||||
#define AQH_ENDPOINT_PERMS_ADDVALUE 0x0004
|
||||
|
||||
#define AQH_ENDPOINT_PERMS_LISTDATA 0x0010
|
||||
#define AQH_ENDPOINT_PERMS_READDATA 0x0020
|
||||
#define AQH_ENDPOINT_PERMS_ADDDATA 0x0040
|
||||
#define AQH_ENDPOINT_PERMS_SETDATA 0x0080
|
||||
|
||||
#define AQH_ENDPOINT_PERMS_LISTDEVICES 0x0100
|
||||
#define AQH_ENDPOINT_PERMS_READDEVICE 0x0200
|
||||
#define AQH_ENDPOINT_PERMS_ADDDEVICE 0x0400
|
||||
#define AQH_ENDPOINT_PERMS_MODDEVICE 0x0800
|
||||
|
||||
|
||||
|
||||
AQH_OBJECT *AqHomeDataServer_new(AQH_EVENT_LOOP *eventLoop);
|
||||
int AqHomeDataServer_Init(AQH_OBJECT *o, int argc, char **argv);
|
||||
void AqHomeDataServer_Fini(AQH_OBJECT *o);
|
||||
|
||||
int AqHomeDataServer_GetTimeout(const AQH_OBJECT *o);
|
||||
int AqHomeDataServer_GetClientNum(const AQH_OBJECT *o);
|
||||
|
||||
void AqHomeDataServer_CleanupClients(AQH_OBJECT *o);
|
||||
void AqHomeDataServer_HandleClientMsgs(AQH_OBJECT *o);
|
||||
AQH_OBJECT *AqHomeDataServer_GetIpcEndpointByServiceName(const AQH_OBJECT *o, const char *serviceName);
|
||||
void AqHomeDataServer_SendResponseResultToEndpoint(AQH_OBJECT *ep, uint32_t refMsgId, int result);
|
||||
|
||||
AQH_MSG_REQUEST *AqHomeDataServer_GetRequestTree(const AQH_OBJECT *o);
|
||||
void AqHomeDataServer_AddRequestToTree(AQH_OBJECT *o, AQH_MSG_REQUEST *rq);
|
||||
void AqHomeDataServer_CleanupRequests(AQH_OBJECT *o);
|
||||
|
||||
int AqHomeDataServer_LockStorage(AQH_OBJECT *o);
|
||||
int AqHomeDataServer_UnlockStorage(AQH_OBJECT *o);
|
||||
int AqHomeDataServer_WriteStorageIfChanged(AQH_OBJECT *o);
|
||||
AQH_VALUE *AqHomeDataServer_GetOrCreateValueForDriverWithTemplate(AQH_OBJECT *o, AQH_OBJECT *epDriver, const AQH_VALUE *valueTemplate);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_DATA_P_H
|
||||
#define AQHOME_DATA_P_H
|
||||
#ifndef AQHOME_DATA_SERVER_P_H
|
||||
#define AQHOME_DATA_SERVER_P_H
|
||||
|
||||
|
||||
#include "./aqhome_data.h"
|
||||
#include "./server.h"
|
||||
|
||||
#include <aqhome/events2/object.h>
|
||||
|
||||
#include <gwenhywfar/mutex.h>
|
||||
|
||||
@@ -23,22 +25,25 @@
|
||||
|
||||
|
||||
|
||||
struct AQHOME_DATA {
|
||||
GWEN_MSG_ENDPOINT *ipcdEndpoint;
|
||||
typedef struct AQHOME_SERVER AQHOME_SERVER;
|
||||
struct AQHOME_SERVER {
|
||||
AQH_OBJECT *ipcServer;
|
||||
AQH_OBJECT_LIST *tcpClientList;
|
||||
|
||||
AQH_MSG_REQUEST *requestTree;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
AQH_STORAGE *storage;
|
||||
|
||||
char *pidFile;
|
||||
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
|
||||
GWEN_MUTEX *storageMutex;
|
||||
|
||||
GWEN_MSG_REQUEST *requestTree;
|
||||
};
|
||||
|
||||
|
||||
AQHOME_SERVER *AqHomeDataServer_GetServerData(const AQH_OBJECT *o);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -37,30 +37,22 @@
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
init.h
|
||||
fini.h
|
||||
loop.h
|
||||
loop_ipc.h
|
||||
loop_mqtt.h
|
||||
aqhome_mqtt.h
|
||||
aqhome_mqtt_p.h
|
||||
xmlread.h
|
||||
xmlwrite.h
|
||||
c_setdata.h
|
||||
server.h
|
||||
server_p.h
|
||||
s_publish.h
|
||||
s_setdata.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
aqhome_mqtt.c
|
||||
init.c
|
||||
fini.c
|
||||
loop.c
|
||||
loop_ipc.c
|
||||
loop_mqtt.c
|
||||
main.c
|
||||
xmlread.c
|
||||
xmlwrite.c
|
||||
c_setdata.c
|
||||
server.c
|
||||
s_publish.c
|
||||
s_setdata.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/endpoint_ipcclient.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
|
||||
#include <gwenhywfar/misc.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AQHOME_MQTT *AqHomeMqtt_new(void)
|
||||
{
|
||||
AQHOME_MQTT *aqh;
|
||||
|
||||
GWEN_NEW_OBJECT(AQHOME_MQTT, aqh);
|
||||
|
||||
return aqh;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_free(AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->availableDeviceList);
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
GWEN_DB_Group_free(aqh->dbArgs);
|
||||
free(aqh->pidFile);
|
||||
|
||||
GWEN_FREE_OBJECT(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetBrokerEndpoint(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?(aqh->brokerEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetMqttEndpoint(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?(aqh->mqttEndpoint):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_DB_NODE *AqHomeMqtt_GetDbArgs(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?(aqh->dbArgs):NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeMqtt_GetPidFile(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->pidFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->pidFile);
|
||||
aqh->pidFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->timeout:0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->deviceFile:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s)
|
||||
{
|
||||
if (aqh) {
|
||||
free(aqh->deviceFile);
|
||||
aqh->deviceFile=s?strdup(s):NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
return aqh?aqh->availableDeviceList:NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->availableDeviceList);
|
||||
aqh->availableDeviceList=dl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl)
|
||||
{
|
||||
if (aqh) {
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
aqh->registeredDeviceList=dl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId)
|
||||
{
|
||||
if (aqh && aqh->registeredDeviceList) {
|
||||
return AQHMQTT_Device_List_GetById(aqh->registeredDeviceList, wantedDeviceId);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No registered devices");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh && aqh->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
|
||||
if (device) {
|
||||
fprintf(stderr, "Registered Devices:\n");
|
||||
while(device) {
|
||||
const char *sDeviceName;
|
||||
const char *sDeviceId;
|
||||
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
fprintf(stderr, " %s (%s)\n", sDeviceId?sDeviceId:"<no id>", sDeviceName?sDeviceName:"<no name>");
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "No registered devices\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "No registered devices\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTT_H
|
||||
#define AQHOME_MQTT_H
|
||||
|
||||
|
||||
//#include "./mqttvalue.h"
|
||||
//#include "./mqtttopic.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQHOME_MQTT AQHOME_MQTT;
|
||||
|
||||
|
||||
AQHOME_MQTT *AqHomeMqtt_new(void);
|
||||
void AqHomeMqtt_free(AQHOME_MQTT *aqh);
|
||||
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetBrokerEndpoint(const AQHOME_MQTT *aqh);
|
||||
GWEN_MSG_ENDPOINT *AqHomeMqtt_GetMqttEndpoint(const AQHOME_MQTT *aqh);
|
||||
|
||||
GWEN_DB_NODE *AqHomeMqtt_GetDbArgs(const AQHOME_MQTT *aqh);
|
||||
|
||||
const char *AqHomeMqtt_GetPidFile(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetPidFile(AQHOME_MQTT *aqh, const char *s);
|
||||
|
||||
int AqHomeMqtt_GetTimeout(const AQHOME_MQTT *aqh);
|
||||
|
||||
const char *AqHomeMqtt_GetDeviceFile(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetDeviceFile(AQHOME_MQTT *aqh, const char *s);
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AqHomeMqtt_GetAvailableDeviceList(const AQHOME_MQTT *aqh);
|
||||
void AqHomeMqtt_SetAvailableDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
||||
|
||||
void AqHomeMqtt_SetRegisteredDeviceList(AQHOME_MQTT *aqh, AQHMQTT_DEVICE_LIST *dl);
|
||||
AQHMQTT_DEVICE *AqHomeMqtt_FindRegisteredDevice(AQHOME_MQTT *aqh, const char *wantedDeviceId);
|
||||
|
||||
void AqHomeMqtt_DumpRegisteredDevices(const AQHOME_MQTT *aqh);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2024 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./c_setdata.h"
|
||||
#include "aqhome/data/value.h"
|
||||
#include "aqhome/ipc/data/msg_data_set.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const char *valueName, const char *valueData);
|
||||
static void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData);
|
||||
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg)
|
||||
{
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
DBG_ERROR(NULL, "Received SETDATA request");
|
||||
AQH_SetDataIpcMsg_Parse(recvdMsg, 0);
|
||||
recvdValue=AQH_SetDataIpcMsg_ReadValue(recvdMsg);
|
||||
if (recvdValue) {
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
|
||||
if (valueName && deviceName) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AqHomeMqtt_FindRegisteredDevice(aqh, deviceName);
|
||||
if (device) {
|
||||
char *valueDataFreeable;
|
||||
|
||||
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
|
||||
valueDataFreeable=AQH_SetDataIpcMsg_ReadData(recvdMsg);
|
||||
_sendDataForDevice(aqh, device, valueName, valueDataFreeable);
|
||||
free(valueDataFreeable);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
|
||||
AqHomeMqtt_DumpRegisteredDevices(aqh);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either value name or device name missing in request");
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Request does not contain a value object");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataForDevice(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const char *valueName, const char *valueData)
|
||||
{
|
||||
const char *deviceId;
|
||||
|
||||
deviceId=AQHMQTT_Device_GetId(device);
|
||||
if (deviceId && *deviceId) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
AQHMQTT_VALUE *value;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
|
||||
if (value) {
|
||||
/* found value, create publish msg, send */
|
||||
DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
|
||||
_sendValueToMqtt(aqh, deviceId, topic, valueData);
|
||||
}
|
||||
} /* if out */
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
} /* while topic */
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device has no id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueToMqtt(AQHOME_MQTT *aqh, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
GWEN_BUFFER *buf;
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
ep=AqHomeMqtt_GetMqttEndpoint(aqh);
|
||||
buf=_createBufferForTopic(deviceId, topic);
|
||||
DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
|
||||
msgOut=AQH_PublishMqttMsg_new(0, 0, GWEN_Buffer_GetStart(buf),
|
||||
(const uint8_t*) (valueData?valueData:NULL),
|
||||
valueData?strlen(valueData):0);
|
||||
if (msgOut) {
|
||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgOut);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Error creating message");
|
||||
}
|
||||
GWEN_Buffer_free(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
const char *s;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
s=AQHMQTT_Topic_GetBeforeId(topic);
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
GWEN_Buffer_AppendString(buf, deviceId);
|
||||
s=AQHMQTT_Topic_GetAfterId(topic);
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_MQTTLOG_C_SETDATA_H
|
||||
#define AQHOME_MQTTLOG_C_SETDATA_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
|
||||
void AqHomeMqttLog_HandleSetData(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *recvdMsg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./fini.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqtt_Fini(AQHOME_MQTT *aqh)
|
||||
{
|
||||
if (aqh) {
|
||||
if (aqh->rootEndpoint)
|
||||
_disconnectTree(aqh->rootEndpoint);
|
||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
||||
aqh->rootEndpoint=NULL;
|
||||
aqh->brokerEndpoint=NULL;
|
||||
aqh->mqttEndpoint=NULL;
|
||||
|
||||
AQHMQTT_Device_List_free(aqh->availableDeviceList);
|
||||
aqh->availableDeviceList=NULL;
|
||||
AQHMQTT_Device_List_free(aqh->registeredDeviceList);
|
||||
aqh->registeredDeviceList=NULL;
|
||||
|
||||
if (aqh->pidFile)
|
||||
remove(aqh->pidFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epChild;
|
||||
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
||||
while(epChild) {
|
||||
_disconnectTree(epChild);
|
||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
||||
} /* while */
|
||||
|
||||
GWEN_MsgEndpoint_Disconnect(ep);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_FINI_H
|
||||
#define AQHOMEMQTT_FINI_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_Fini(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,489 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "./init.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "./xmlread.h"
|
||||
#include "./xmlwrite.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/ipc/endpoint_ipc.h"
|
||||
#include "aqhome/ipc/endpoint_ipcclient.h"
|
||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _createPidFile(const char *pidFilename);
|
||||
static int _setupBroker(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static int _setupMqtt(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs);
|
||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
const char *s;
|
||||
|
||||
dbArgs=GWEN_DB_Group_new("args");
|
||||
rv=_readArgs(argc, argv, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
AQH_MergeConfigFileIntoConfig(dbArgs, "ConfigFile");
|
||||
aqh->dbArgs=dbArgs;
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "loglevel", 0, NULL);
|
||||
if (s && *s) {
|
||||
GWEN_LOGGER_LEVEL ll;
|
||||
|
||||
ll=GWEN_Logger_Name2Level(s);
|
||||
GWEN_Logger_SetLevel(NULL, ll);
|
||||
}
|
||||
|
||||
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_MQTT_DEFAULT_PIDFILE);
|
||||
if (s && *s) {
|
||||
AqHomeMqtt_SetPidFile(aqh, s);
|
||||
rv=_createPidFile(s);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "devicefile", 0, NULL);
|
||||
if (s && *s) {
|
||||
AqHomeMqtt_SetDeviceFile(aqh, s);
|
||||
}
|
||||
else {
|
||||
GWEN_BUFFER *bufFilename;
|
||||
|
||||
bufFilename=AQH_GetRuntimeFilePath(AQHOME_MQTT_DEFAULT_DEVICEFILE);
|
||||
if (bufFilename) {
|
||||
AqHomeMqtt_SetDeviceFile(aqh, GWEN_Buffer_GetStart(bufFilename));
|
||||
GWEN_Buffer_free(bufFilename);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Could not setup filename for devices, please specify via command line argument");
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
}
|
||||
|
||||
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
|
||||
|
||||
rv=_setupMqtt(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=_setupBroker(aqh, dbArgs);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting up connection to broker (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
AqHomeMqtt_LoadRuntimeDeviceFiles(aqh);
|
||||
|
||||
AqHomeMqtt_ReloadDeviceFiles(aqh);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
DBG_ERROR(NULL, "Loading devices description files");
|
||||
deviceList=AqHomeMqttLog_ReadDataDeviceFiles(aqh);
|
||||
if (deviceList)
|
||||
AqHomeMqtt_SetAvailableDeviceList(aqh, deviceList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
DBG_ERROR(NULL, "Loading registered devices from file \"%s\"", aqh->deviceFile);
|
||||
deviceList=AqHomeMqttLog_ReadDeviceFile(aqh, aqh->deviceFile);
|
||||
if (deviceList)
|
||||
AqHomeMqtt_SetRegisteredDeviceList(aqh, deviceList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=AqHomeMqttLog_WriteDevicesFile(aqh, aqh->registeredDeviceList, aqh->deviceFile);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing devices to \"%s\" (%d)", aqh->deviceFile, rv);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _createPidFile(const char *pidFilename)
|
||||
{
|
||||
FILE *f;
|
||||
int pidfd;
|
||||
|
||||
if (remove(pidFilename)==0) {
|
||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (pidfd < 0) {
|
||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
f = fdopen(pidfd, "w");
|
||||
#else /* HAVE_STAT_H */
|
||||
f=fopen(pidFilename,"w+");
|
||||
#endif /* HAVE_STAT_H */
|
||||
|
||||
/* write pid */
|
||||
#ifdef HAVE_GETPID
|
||||
fprintf(f,"%d\n",getpid());
|
||||
#else
|
||||
fprintf(f,"-1\n");
|
||||
#endif
|
||||
if (fclose(f)) {
|
||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupBroker(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *brokerAddress;
|
||||
int brokerPort;
|
||||
const char *brokerClientId;
|
||||
|
||||
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "brokerAddress", 0, NULL);
|
||||
if (!(brokerAddress && *brokerAddress))
|
||||
brokerAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/brokerAddress", 0, "127.0.0.1");
|
||||
|
||||
brokerPort=GWEN_DB_GetIntValue(dbArgs, "brokerPort", 0, -1);
|
||||
if (brokerPort<0)
|
||||
brokerPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/brokerPort", 0, AQHOME_MQTT_DEFAULT_BROKER_PORT);
|
||||
|
||||
brokerClientId=GWEN_DB_GetCharValue(dbArgs, "brokerClientId", 0, AQHOME_MQTT_DEFAULT_BROKER_CLIENTID);
|
||||
|
||||
if (brokerAddress && *brokerAddress && brokerPort) {
|
||||
GWEN_MSG_ENDPOINT *ep;
|
||||
GWEN_MSG_ENDPOINT *ipcBaseEndpoint;
|
||||
int rv;
|
||||
|
||||
ep=AQH_ClientIpcEndpoint_new("brokerIpcClient", 0);
|
||||
ipcBaseEndpoint=AQH_IpcEndpoint_CreateIpcTcpClient(brokerAddress, brokerPort, "brokerPhysEndpoint", 0);
|
||||
AQH_IpcEndpoint_SetServiceName(ipcBaseEndpoint, brokerClientId);
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(ep, ipcBaseEndpoint);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
||||
aqh->brokerEndpoint=ep;
|
||||
|
||||
rv=GWEN_MultilayerEndpoint_StartConnect(ep);
|
||||
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
|
||||
DBG_ERROR(NULL, "Error connecting to broker server %s:%d (%d), will retry later", brokerAddress, brokerPort, rv);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupMqtt(AQHOME_MQTT *aqh, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
const char *mqttAddress;
|
||||
int mqttPort;
|
||||
const char *mqttClientId;
|
||||
int mqttKeepAlive;
|
||||
|
||||
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL);
|
||||
if (!(mqttAddress && *mqttAddress))
|
||||
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/mqttAddr", 0, "127.0.0.1");
|
||||
|
||||
mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, 1883);
|
||||
if (mqttPort<0)
|
||||
mqttPort=GWEN_DB_GetIntValue(dbArgs, "ConfigFile/mqttPort", 0, 1883);
|
||||
|
||||
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, "aqhome-mqttlog");
|
||||
if (!(mqttClientId && *mqttClientId))
|
||||
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "ConfigFile/mqttClientId", 0, "aqhome-mqttlog");
|
||||
|
||||
mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, 600);
|
||||
|
||||
if (mqttAddress && *mqttAddress && mqttPort) {
|
||||
GWEN_MSG_ENDPOINT *epMqtt;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Connecting to %s (port %d)", mqttAddress, mqttPort);
|
||||
epMqtt=AQH_MqttClientEndpoint_new(mqttClientId, mqttAddress, mqttPort, NULL, 0);
|
||||
if (epMqtt==NULL) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error creating endpoint TCP");
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
AQH_MqttClientEndpoint_SetKeepAliveTime(epMqtt, mqttKeepAlive);
|
||||
GWEN_MsgEndpoint_AddFlags(epMqtt, AQH_ENDPOINT2_MQTTCLIENT_FLAGS_SUBSCRIBEALL);
|
||||
|
||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, epMqtt);
|
||||
aqh->mqttEndpoint=epMqtt;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
||||
{
|
||||
int rv;
|
||||
const GWEN_ARGS args[]= {
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"loglevel", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"L", /* short option */
|
||||
"loglevel", /* long option */
|
||||
I18S("Specify loglevel"), /* short description */
|
||||
I18S("Specify loglevel") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"cfgdir", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"D", /* short option */
|
||||
"cfgdir", /* long option */
|
||||
I18S("Specify the configuration folder"),
|
||||
I18S("Specify the configuration folder")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"charset", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
0, /* short option */
|
||||
"charset", /* long option */
|
||||
I18S("Specify the output character set"), /* short description */
|
||||
I18S("Specify the output character set") /* long description */
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"brokerAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"ba", /* short option */
|
||||
"brokeraddress", /* long option */
|
||||
I18S("Specify the address of the broker server to connect to (disabled if missing)"),
|
||||
I18S("Specify the address of the broker server to connect to (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"brokerPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"bp", /* short option */
|
||||
"brokerport", /* long option */
|
||||
I18S("Specify the port of the broker server (default: 1899)"),
|
||||
I18S("Specify the port of the broker server (default: 1899)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"brokerClientId", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"brokerclientid", /* long option */
|
||||
I18S("Specify client id for the broker server (default: \"nodes\")"),
|
||||
I18S("Specify client id for the broker server (default: \"nodes\")")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"mqttAddress", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"ma", /* short option */
|
||||
"mqttaddress", /* long option */
|
||||
I18S("Specify the address of the MQTT server to connect to (disabled if missing)"),
|
||||
I18S("Specify the address of the MQTT server to connect to (disabled if missing)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"mqttPort", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"mp", /* short option */
|
||||
"mqttport", /* long option */
|
||||
I18S("Specify the port of the MQTT server (default: 1883)"),
|
||||
I18S("Specify the port of the MQTT server (default: 1883)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"mqttClientId", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
NULL, /* short option */
|
||||
"mqttclientid", /* long option */
|
||||
I18S("Specify client id for the MQTT server (default: \"aqhomed\")"),
|
||||
I18S("Specify client id for the MQTT server (default: \"aqhomed\")")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"mqttKeepAlive", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"mk", /* short option */
|
||||
"mqttkeepalive", /* long option */
|
||||
I18S("Specify keepalive time in seconds (defaults: 600)"),
|
||||
I18S("Specify keepalive time in seconds (defaults: 600)")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"pidfile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"p", /* short option */
|
||||
"pidfile", /* long option */
|
||||
I18S("Specify the PID file"),
|
||||
I18S("Specify the PID file")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"timeout", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"T", /* short option */
|
||||
"timeout", /* long option */
|
||||
I18S("Specify timeout in second (default: no timeout)"),
|
||||
I18S("Specify timeout in second (default: no timeout)")
|
||||
},
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
||||
GWEN_ArgsType_Char, /* type */
|
||||
"devicefile", /* name */
|
||||
0, /* minnum */
|
||||
1, /* maxnum */
|
||||
"d", /* short option */
|
||||
"devicefile", /* long option */
|
||||
I18S("Specify the device file"),
|
||||
I18S("Specify the device file")
|
||||
},
|
||||
|
||||
{
|
||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
||||
GWEN_ArgsType_Int, /* type */
|
||||
"help", /* name */
|
||||
0, /* minnum */
|
||||
0, /* maxnum */
|
||||
"h", /* short option */
|
||||
"help",
|
||||
I18S("Show this help screen."),
|
||||
I18S("Show this help screen.")
|
||||
}
|
||||
};
|
||||
|
||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
||||
return GWEN_ERROR_INVALID;
|
||||
}
|
||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
||||
GWEN_BUFFER *ubuf;
|
||||
|
||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(ubuf,
|
||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
||||
AQHOME_VERSION_STRING,
|
||||
argv[0]);
|
||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
||||
return 1;
|
||||
}
|
||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
||||
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
||||
GWEN_Buffer_free(ubuf);
|
||||
return GWEN_ERROR_CLOSE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_INIT_H
|
||||
#define AQHOMEMQTT_INIT_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
|
||||
|
||||
int AqHomeMqtt_Init(AQHOME_MQTT *aqh, int argc, char **argv);
|
||||
void AqHomeMqtt_ReloadDeviceFiles(AQHOME_MQTT *aqh);
|
||||
|
||||
void AqHomeMqtt_LoadRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||
int AqHomeMqtt_SaveRuntimeDeviceFiles(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./loop.h"
|
||||
#include "./loop_ipc.h"
|
||||
#include "./loop_mqtt.h"
|
||||
#include "./c_setdata.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/json_read.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
|
||||
|
||||
//#define FULL_DEBUG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqttLog_Loop(AQHOME_MQTT *aqh, int timeoutInMsecs)
|
||||
{
|
||||
if (aqh) {
|
||||
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
|
||||
AqHomeMqttLog_ReadAndHandleMqttMessages(aqh);
|
||||
AqHomeMqttLog_ReadAndHandleIpcMessages(aqh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_LOOP_H
|
||||
#define AQHOMEMQTT_LOOP_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
void AqHomeMqttLog_Loop(AQHOME_MQTT *aqh, int timeoutInMsecs);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./loop_ipc.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "./c_setdata.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/json_read.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
|
||||
|
||||
#define FULL_DEBUG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleIpcMessages(AQHOME_MQTT *aqh)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msg;
|
||||
|
||||
epTcp=aqh->brokerEndpoint;
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
|
||||
_handleIpcMsg(aqh, epTcp, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleIpcMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, GWEN_MSG *msg)
|
||||
{
|
||||
uint16_t code;
|
||||
uint8_t protoId;
|
||||
|
||||
/* exec IPC message */
|
||||
code=GWEN_IpcMsg_GetCode(msg);
|
||||
protoId=GWEN_IpcMsg_GetProtoId(msg);
|
||||
if (protoId==AQH_IPC_PROTOCOL_DATA_ID) {
|
||||
DBG_DEBUG(AQH_LOGDOMAIN, "Received IPC packet %d (%x)", (int) code, code);
|
||||
switch(code) {
|
||||
case AQH_MSGTYPE_IPC_DATA_SETDATA: AqHomeMqttLog_HandleSetData(aqh, ep, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if (protoId==0 && code==AQH_MSGTYPE_IPC_DATA_RESULT) {
|
||||
/* result received */
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid IPC protocol %d (%02x)", protoId, protoId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_LOOP_IPC_H
|
||||
#define AQHOMEMQTT_LOOP_IPC_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleIpcMessages(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_LOOP_MQTT_H
|
||||
#define AQHOMEMQTT_LOOP_MQTT_H
|
||||
|
||||
|
||||
#include "./aqhome_mqtt.h"
|
||||
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/msg.h>
|
||||
|
||||
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleMqttMessages(AQHOME_MQTT *aqh);
|
||||
int AqHomeMqttLog_SendPing(AQHOME_MQTT *aqh);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10,10 +10,7 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./init.h"
|
||||
#include "./fini.h"
|
||||
#include "./loop.h"
|
||||
#include "./loop_mqtt.h"
|
||||
#include "./server.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
@@ -46,8 +43,9 @@
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
#define AQHOME_MQTTLOG_PING_INTERVAL 120
|
||||
#define AQHOME_MQTTLOG_SAVE_INTERVAL 60
|
||||
#define CONNCHECK_INTERVAL_IN_SECS 10
|
||||
#define PING_INTERVAL_IN_SECS 120
|
||||
#define SAVE_INTERVAL_IN_SECS 60
|
||||
|
||||
#define FULL_DEBUG
|
||||
|
||||
@@ -58,13 +56,14 @@
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _serve(AQHOME_MQTT *aqh);
|
||||
static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop);
|
||||
static int _diffInSeconds(time_t t1, time_t t0);
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -85,11 +84,10 @@ static int stopService=0;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
AQHOME_MQTT *aqh;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
AQH_EVENT_LOOP *eventLoop;
|
||||
AQH_OBJECT *aqh;
|
||||
int rv;
|
||||
GWEN_GUI *gui;
|
||||
const char *s;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
@@ -98,7 +96,14 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhome-mqttlog", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
//GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Notice);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
@@ -106,8 +111,13 @@ int main(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
|
||||
aqh=AqHomeMqtt_new();
|
||||
rv=AqHomeMqtt_Init(aqh, argc, argv);
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
eventLoop=AQH_EventLoop_new();
|
||||
|
||||
aqh=AQH_MqttLogServer_new(eventLoop);
|
||||
rv=AQH_MqttLogServer_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
if (rv==GWEN_ERROR_CLOSE)
|
||||
return 1;
|
||||
@@ -115,18 +125,12 @@ int main(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
|
||||
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
||||
_runService(aqh, eventLoop);
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
s=GWEN_DB_GetCharValue(dbArgs, "charset", 0, NULL);
|
||||
if (s && *s)
|
||||
GWEN_Gui_SetCharSet(gui, s);
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
_serve(aqh);
|
||||
|
||||
AqHomeMqtt_Fini(aqh);
|
||||
AqHomeMqtt_free(aqh);
|
||||
AQH_MqttLogServer_Fini(aqh);
|
||||
AQH_Object_free(aqh);
|
||||
AQH_EventLoop_free(eventLoop);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
@@ -136,77 +140,65 @@ int main(int argc, char **argv)
|
||||
|
||||
|
||||
|
||||
void _serve(AQHOME_MQTT *aqh)
|
||||
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
{
|
||||
int rv;
|
||||
time_t timeStart;
|
||||
int timeout;
|
||||
time_t startTime;
|
||||
time_t lastPingSendTime;
|
||||
time_t lastSaveTime;
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
time_t timeLastConnCheck;
|
||||
time_t timeLastSave;
|
||||
time_t timeLastPingSend;
|
||||
int rv;
|
||||
|
||||
startTime=time(NULL);
|
||||
lastSaveTime=time(NULL);
|
||||
|
||||
dbArgs=AqHomeMqtt_GetDbArgs(aqh);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error setting signal handlers (%d)", rv);
|
||||
return;
|
||||
}
|
||||
|
||||
timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
||||
|
||||
lastPingSendTime=time(NULL);
|
||||
timeout=AQH_MqttLogServer_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastConnCheck=time(NULL);
|
||||
timeLastSave=time(NULL);
|
||||
timeLastPingSend=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
DBG_DEBUG(NULL, "Next loop");
|
||||
AqHomeMqttLog_Loop(aqh, 2000);
|
||||
time_t now;
|
||||
|
||||
if (timeout) {
|
||||
time_t now;
|
||||
AQH_EventLoop_Run(eventLoop, 2000);
|
||||
AQH_MqttLogServer_HandleMqttMsgs(aqh);
|
||||
AQH_MqttLogServer_HandleBrokerMsgs(aqh);
|
||||
|
||||
now=time(NULL);
|
||||
if ((now-startTime)>timeout) {
|
||||
DBG_ERROR(NULL, "Timeout, stopping service");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (1){
|
||||
time_t now;
|
||||
now=time(NULL);
|
||||
|
||||
now=time(NULL);
|
||||
if (now-lastPingSendTime>AQHOME_MQTTLOG_PING_INTERVAL) {
|
||||
rv=AqHomeMqttLog_SendPing(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error sending PING");
|
||||
}
|
||||
lastPingSendTime=time(NULL);
|
||||
}
|
||||
if (_diffInSeconds(now, timeLastConnCheck)>CONNCHECK_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Check connections");
|
||||
AQH_MqttLogServer_CheckBrokerConnection(aqh);
|
||||
AQH_MqttLogServer_CheckMqttConnection(aqh);
|
||||
timeLastConnCheck=now;
|
||||
}
|
||||
|
||||
if (1){
|
||||
time_t now;
|
||||
|
||||
now=time(NULL);
|
||||
if (now-lastSaveTime>AQHOME_MQTTLOG_SAVE_INTERVAL) {
|
||||
DBG_ERROR(NULL, "Writing device files");
|
||||
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
lastSaveTime=time(NULL);
|
||||
if (_diffInSeconds(now, timeLastPingSend)>PING_INTERVAL_IN_SECS) {
|
||||
rv=AQH_MqttLogServer_SendPing(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error sending PING");
|
||||
}
|
||||
timeLastPingSend=time(NULL);
|
||||
}
|
||||
|
||||
if (_diffInSeconds(now, timeLastSave)>SAVE_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Writing device files");
|
||||
rv=AQH_MqttLogServer_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing device file");
|
||||
}
|
||||
timeLastSave=time(NULL);
|
||||
}
|
||||
|
||||
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
|
||||
DBG_INFO(NULL, "Timeout");
|
||||
break;
|
||||
}
|
||||
} /* while */
|
||||
DBG_ERROR(NULL, "Leaving server");
|
||||
|
||||
rv=AqHomeMqtt_SaveRuntimeDeviceFiles(aqh);
|
||||
rv=AQH_MqttLogServer_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -228,6 +220,10 @@ int _setSignalHandlers(void)
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saPIPE, SIGPIPE);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
@@ -269,6 +265,9 @@ void _signalHandler(int s)
|
||||
DBG_WARN(0, "Received signal %d, stopping service in next loop.",s);
|
||||
stopService=1;
|
||||
break;
|
||||
case SIGPIPE:
|
||||
DBG_WARN(0, "Received PIPE signal");
|
||||
break;
|
||||
default:
|
||||
DBG_WARN(0, "Unknown signal %d",s);
|
||||
break;
|
||||
@@ -277,3 +276,8 @@ void _signalHandler(int s)
|
||||
|
||||
|
||||
|
||||
int _diffInSeconds(time_t t1, time_t t0)
|
||||
{
|
||||
return t1-t0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
@@ -10,41 +10,38 @@
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./loop_mqtt.h"
|
||||
#include "./aqhome_mqtt_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
||||
#include "aqhome/ipc/data/msg_data_multidata.h"
|
||||
#include "aqhome/ipc/data/msg_data_values.h"
|
||||
#include "aqhome/ipc/data/ipc_data.h"
|
||||
#include "./s_publish.h"
|
||||
#include "./server_p.h"
|
||||
|
||||
#include <aqhome/aqhome.h>
|
||||
#include <aqhome/msg/ipc/data/m_ipcd.h>
|
||||
#include <aqhome/msg/ipc/data/m_ipcd_multidata.h>
|
||||
#include <aqhome/msg/ipc/data/m_ipcd_values.h>
|
||||
#include <aqhome/ipc2/endpoint.h>
|
||||
#include <aqhome/msg/mqtt/m_mqtt_publish.h>
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/endpoint.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/json_read.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
//#define FULL_DEBUG
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleMqttMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
static void _handlePublishMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg);
|
||||
static int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *topic, const char *value);
|
||||
static void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *dev, AQHMQTT_TOPIC *t, const char *rcvdValue);
|
||||
static void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *dev, AQHMQTT_TOPIC *t, const char *rcvdValue);
|
||||
static void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue);
|
||||
static void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device);
|
||||
static void _sendAnnounceValueMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
|
||||
static int _handlePublish(AQH_OBJECT *o, AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic, const char *rcvdValue);
|
||||
static void _handleNumTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
|
||||
AQHMQTT_TOPIC *topic, const char *rcvdValue);
|
||||
static void _handleJsonTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
|
||||
AQHMQTT_TOPIC *topic, const char *rcvdValue);
|
||||
static void _sendMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue);
|
||||
static void _announceDeviceToBroker(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device);
|
||||
static void _sendAnnounceValueMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
|
||||
static AQH_VALUE *_mkMessageValue(const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value);
|
||||
static int _mqttValueTypeMessageValueType(int t);
|
||||
static int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue);
|
||||
static int _registerNewDeviceForTopic(AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic);
|
||||
static AQHMQTT_TOPIC *_findMaskMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir);
|
||||
static AQHMQTT_TOPIC *_findTopicMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir);
|
||||
static GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic);
|
||||
@@ -52,148 +49,89 @@ static GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcv
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomeMqttLog_ReadAndHandleMqttMessages(AQHOME_MQTT *aqh)
|
||||
void AQH_MqttLogServer_HandlePublishMsg(AQH_OBJECT *o, GWEN_UNUSED AQH_OBJECT *ep, const AQH_MESSAGE *msg)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msg;
|
||||
if (o && msg) {
|
||||
AQH_MQTTLOG_SERVER *xo;
|
||||
|
||||
epTcp=aqh->mqttEndpoint;
|
||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp)) ) {
|
||||
#ifdef FULL_DEBUG
|
||||
DBG_ERROR(NULL, "Received this message:");
|
||||
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
|
||||
#endif
|
||||
_handleMqttMsg(aqh, epTcp, msg);
|
||||
GWEN_Msg_free(msg);
|
||||
}
|
||||
}
|
||||
xo=AQH_MqttLogServer_GetServerData(o);
|
||||
if (xo && xo->registeredDeviceList) {
|
||||
char *topic;
|
||||
char *value;
|
||||
|
||||
|
||||
|
||||
int AqHomeMqttLog_SendPing(AQHOME_MQTT *aqh)
|
||||
{
|
||||
GWEN_MSG_ENDPOINT *epTcp;
|
||||
GWEN_MSG *msgOut;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Sending PING");
|
||||
epTcp=aqh->mqttEndpoint;
|
||||
msgOut=GWEN_MqttMsg_new(AQH_MQTTMSG_MSGTYPE_PINGREQ, 0, NULL);
|
||||
if (msgOut==NULL) {
|
||||
DBG_ERROR(NULL, "Error creating message");
|
||||
return GWEN_ERROR_INTERNAL;
|
||||
}
|
||||
GWEN_MsgEndpoint_AddSendMessage(epTcp, msgOut);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMqttMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PUBLISH & 0xf0)) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "PUBLISH message received");
|
||||
#ifdef FULL_DEBUG
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
AQH_PublishMqttMsg_DumpToBuffer(msg, buf, "received");
|
||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
#endif
|
||||
_handlePublishMsg(aqh, ep, msg);
|
||||
}
|
||||
else if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PINGRESP & 0xf0)) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "PING response received");
|
||||
}
|
||||
else {
|
||||
#ifdef FULL_DEBUG
|
||||
DBG_ERROR(NULL, "Received this message:");
|
||||
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handlePublishMsg(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msg)
|
||||
{
|
||||
char *topic;
|
||||
char *value;
|
||||
topic=AQH_MqttMessagePublish_ExtractTopic(msg);
|
||||
value=AQH_MqttMessagePublish_ExtractValue(msg);
|
||||
|
||||
topic=AQH_PublishMqttMsg_ExtractTopic(msg);
|
||||
value=AQH_PublishMqttMsg_ExtractValue(msg);
|
||||
|
||||
if (topic && value) {
|
||||
int rv;
|
||||
if (topic && value) {
|
||||
int rv;
|
||||
|
||||
rv=_handlePublish(aqh, ep, topic, value);
|
||||
if (rv!=1) {
|
||||
DBG_INFO(NULL, "New topic \"%s\", trying to register", topic);
|
||||
rv=_registerNewDeviceForTopic(aqh, ep, topic, value);
|
||||
if (rv==1) {
|
||||
rv=_handlePublish(aqh, ep, topic, value);
|
||||
rv=_handlePublish(o, xo, topic, value);
|
||||
if (rv!=1) {
|
||||
DBG_ERROR(NULL, "Topic \"%s\" still not handled, SNH!", topic);
|
||||
DBG_INFO(NULL, "New topic \"%s\", trying to register", topic);
|
||||
rv=_registerNewDeviceForTopic(xo, topic);
|
||||
if (rv==1) {
|
||||
rv=_handlePublish(o, xo, topic, value);
|
||||
if (rv!=1) {
|
||||
DBG_ERROR(NULL, "Topic \"%s\" still not handled, SNH!", topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
|
||||
}
|
||||
free(value);
|
||||
free(topic);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
|
||||
}
|
||||
free(value);
|
||||
free(topic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue)
|
||||
int _handlePublish(AQH_OBJECT *o, AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic, const char *rcvdValue)
|
||||
{
|
||||
if (rcvdTopic && *rcvdTopic) {
|
||||
if (aqh->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
if (o && rcvdTopic && *rcvdTopic && xo && xo->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->registeredDeviceList);
|
||||
while(device) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
const char *sDeviceName;
|
||||
const char *sDeviceId;
|
||||
device=AQHMQTT_Device_List_First(xo->registeredDeviceList);
|
||||
while(device) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
const char *sDeviceName;
|
||||
const char *sDeviceId;
|
||||
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=_findTopicMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
topic=_findTopicMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
#if 0
|
||||
if (topic==NULL) {
|
||||
topic=_findMaskMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
if (topic)
|
||||
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
|
||||
}
|
||||
#endif
|
||||
if (topic) {
|
||||
DBG_INFO(AQH_LOGDOMAIN,
|
||||
"Handling topic \"%s\" for device type %s (id: %s)",
|
||||
rcvdTopic,
|
||||
sDeviceName, sDeviceId?sDeviceId:"<no id>");
|
||||
if (AQHMQTT_Topic_GetTopicType(topic)==AQHMQTT_TopicType_Json)
|
||||
_handleJsonTopic(aqh, ep, device, topic, rcvdValue);
|
||||
else
|
||||
_handleNumTopic(aqh, ep, device, topic, rcvdValue);
|
||||
return 1;
|
||||
}
|
||||
if (topic==NULL) {
|
||||
topic=_findMaskMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
if (topic)
|
||||
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
|
||||
}
|
||||
#endif
|
||||
if (topic) {
|
||||
DBG_INFO(AQH_LOGDOMAIN,
|
||||
"Handling topic \"%s\" for device type %s (id: %s)",
|
||||
rcvdTopic,
|
||||
sDeviceName, sDeviceId?sDeviceId:"<no id>");
|
||||
if (AQHMQTT_Topic_GetTopicType(topic)==AQHMQTT_TopicType_Json)
|
||||
_handleJsonTopic(xo, device, topic, rcvdValue);
|
||||
else
|
||||
_handleNumTopic(xo, device, topic, rcvdValue);
|
||||
return 1;
|
||||
}
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
|
||||
}
|
||||
@@ -202,13 +140,14 @@ int _handlePublish(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopi
|
||||
|
||||
|
||||
|
||||
void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *device, AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
void _handleNumTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
|
||||
AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
{
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList)
|
||||
_sendMessage(aqh, device, AQHMQTT_Value_List_First(valueList), rcvdValue);
|
||||
_sendMessage(xo, device, AQHMQTT_Value_List_First(valueList), rcvdValue);
|
||||
else {
|
||||
DBG_INFO(NULL, "No value list in device \"%s\"", AQHMQTT_Device_GetId(device));
|
||||
}
|
||||
@@ -216,7 +155,8 @@ void _handleNumTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *de
|
||||
|
||||
|
||||
|
||||
void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *device, AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
void _handleJsonTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
|
||||
AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
{
|
||||
GWEN_JSON_ELEM *jeRoot;
|
||||
|
||||
@@ -245,7 +185,7 @@ void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *d
|
||||
|
||||
s=GWEN_JsonElement_GetData(je);
|
||||
if (s && *s)
|
||||
_sendMessage(aqh, device, value, s);
|
||||
_sendMessage(xo, device, value, s);
|
||||
}
|
||||
}
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
@@ -257,35 +197,38 @@ void _handleJsonTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, AQHMQTT_DEVICE *d
|
||||
|
||||
|
||||
|
||||
void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue)
|
||||
void _sendMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue)
|
||||
{
|
||||
int rv;
|
||||
union {double f; uint64_t i;} u;
|
||||
double f;
|
||||
const char *deviceName;
|
||||
|
||||
deviceName=AQHMQTT_Device_GetId(device);
|
||||
rv=GWEN_Text_StringToDouble(rcvdValue, &(u.f));
|
||||
rv=GWEN_Text_StringToDouble(rcvdValue, &f);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Invalid value received from MQTT server (%s)", rcvdValue?rcvdValue:"<empty>");
|
||||
}
|
||||
else {
|
||||
GWEN_MSG *pubMsg;
|
||||
uint64_t arrayToSend[2];
|
||||
uint64_t now;
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
arrayToSend[0]=(uint64_t) time(NULL);
|
||||
arrayToSend[1]=u.i;
|
||||
|
||||
now=(uint64_t) time(NULL);
|
||||
msgValue=_mkMessageValue(device, value);
|
||||
if (xo->brokerEndpoint) {
|
||||
AQH_MESSAGE *pubMsg;
|
||||
|
||||
pubMsg=AQH_MultiDataDataIpcMsg_new(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
|
||||
msgValue, arrayToSend, 1);
|
||||
if (pubMsg) {
|
||||
pubMsg=AQH_IpcdMessageMultiData_newForOne(AQH_MSGTYPE_IPC_DATA_UPDATEDATA,
|
||||
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
|
||||
msgValue, now, f);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "BROKER UPDATE_DATA %s/%s: %f",
|
||||
deviceName?deviceName:"<no device name>",
|
||||
AQH_Value_GetName(msgValue), u.f);
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
|
||||
AQH_Value_GetName(msgValue), f);
|
||||
AQH_Endpoint_AddMsgOut(xo->brokerEndpoint, pubMsg);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Skipping BROKER UPDATE_DATA %s/%s: %f",
|
||||
deviceName?deviceName:"<no device name>",
|
||||
AQH_Value_GetName(msgValue), f);
|
||||
}
|
||||
AQH_Value_free(msgValue);
|
||||
}
|
||||
@@ -293,7 +236,7 @@ void _sendMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_
|
||||
|
||||
|
||||
|
||||
void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
|
||||
void _announceDeviceToBroker(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device)
|
||||
{
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
@@ -311,7 +254,7 @@ void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
|
||||
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
_sendAnnounceValueMessage(aqh, device, value);
|
||||
_sendAnnounceValueMessage(xo, device, value);
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
}
|
||||
}
|
||||
@@ -323,20 +266,25 @@ void _announceDeviceToBroker(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device)
|
||||
|
||||
|
||||
|
||||
void _sendAnnounceValueMessage(AQHOME_MQTT *aqh, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
|
||||
void _sendAnnounceValueMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
|
||||
{
|
||||
GWEN_MSG *pubMsg;
|
||||
AQH_MESSAGE *pubMsg;
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
msgValue=_mkMessageValue(device, value);
|
||||
pubMsg=AQH_ValuesDataIpcMsg_newForOneValue(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
|
||||
GWEN_MsgEndpoint_GetNextMessageId(aqh->brokerEndpoint), 0,
|
||||
0, msgValue);
|
||||
if (pubMsg) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "BROKER ANNOUNCE_VALUE %s", AQH_Value_GetName(msgValue));
|
||||
GWEN_MsgEndpoint_AddSendMessage(aqh->brokerEndpoint, pubMsg);
|
||||
if (xo->brokerEndpoint) {
|
||||
pubMsg=AQH_IpcdMessageValues_newForOne(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
|
||||
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
|
||||
0, msgValue);
|
||||
if (pubMsg) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "BROKER ANNOUNCE_VALUE %s/%s", AQH_Value_GetDeviceName(msgValue), AQH_Value_GetName(msgValue));
|
||||
AQH_Endpoint_AddMsgOut(xo->brokerEndpoint, pubMsg);
|
||||
}
|
||||
AQH_Value_free(msgValue);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Ignoring BROKER ANNOUNCE_VALUE %s", AQH_Value_GetName(msgValue));
|
||||
}
|
||||
AQH_Value_free(msgValue);
|
||||
}
|
||||
|
||||
|
||||
@@ -368,13 +316,13 @@ int _mqttValueTypeMessageValueType(int t)
|
||||
|
||||
|
||||
|
||||
int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const char *rcvdTopic, const char *rcvdValue)
|
||||
int _registerNewDeviceForTopic(AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic)
|
||||
{
|
||||
if (rcvdTopic && *rcvdTopic) {
|
||||
if (aqh->availableDeviceList) {
|
||||
if (xo->availableDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(aqh->availableDeviceList);
|
||||
device=AQHMQTT_Device_List_First(xo->availableDeviceList);
|
||||
while(device) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
@@ -394,11 +342,11 @@ int _registerNewDeviceForTopic(AQHOME_MQTT *aqh, GWEN_MSG_ENDPOINT *ep, const ch
|
||||
AQHMQTT_Device_SetId(newDevice, GWEN_Buffer_GetStart(buf));
|
||||
topic=_findMaskMatchingTopic(AQHMQTT_Device_GetTopicList(newDevice), rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
|
||||
if (aqh->registeredDeviceList==NULL)
|
||||
aqh->registeredDeviceList=AQHMQTT_Device_List_new();
|
||||
if (xo->registeredDeviceList==NULL)
|
||||
xo->registeredDeviceList=AQHMQTT_Device_List_new();
|
||||
DBG_ERROR(NULL, "Registered device \"%s\" (%s)", AQHMQTT_Device_GetId(newDevice), AQHMQTT_Device_GetName(newDevice));
|
||||
AQHMQTT_Device_List_Add(newDevice, aqh->registeredDeviceList);
|
||||
_announceDeviceToBroker(aqh, newDevice);
|
||||
AQHMQTT_Device_List_Add(newDevice, xo->registeredDeviceList);
|
||||
_announceDeviceToBroker(xo, newDevice);
|
||||
GWEN_Buffer_free(buf);
|
||||
return 1;
|
||||
}
|
||||
@@ -494,8 +442,3 @@ GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-mqttlog/s_publish.h
Normal file
25
apps/aqhome-mqttlog/s_publish.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_S_PUBLISH_H
|
||||
#define AQHOMEMQTT_S_PUBLISH_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <aqhome/events2/object.h>
|
||||
#include <aqhome/ipc2/message.h>
|
||||
|
||||
|
||||
|
||||
void AQH_MqttLogServer_HandlePublishMsg(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
179
apps/aqhome-mqttlog/s_setdata.c
Normal file
179
apps/aqhome-mqttlog/s_setdata.c
Normal file
@@ -0,0 +1,179 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "./s_setdata.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/data/value.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_setdata.h"
|
||||
#include "aqhome/msg/mqtt/m_mqtt_publish.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
#define DEBUG_DRY_RUN 0 /* don't actually set value if "1" */
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device,
|
||||
const char *valueName, const char *valueData);
|
||||
static void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData);
|
||||
static GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o,
|
||||
const AQH_MESSAGE *msg,
|
||||
const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
if (o && msg) {
|
||||
AQH_MQTTLOG_SERVER *xo;
|
||||
|
||||
xo=AQH_MqttLogServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_VALUE *recvdValue;
|
||||
|
||||
DBG_ERROR(NULL, "Received SETDATA request");
|
||||
recvdValue=AQH_IpcdMessageSetData_ReadValue(tagList);
|
||||
if (recvdValue) {
|
||||
const char *valueName;
|
||||
const char *deviceName;
|
||||
|
||||
valueName=recvdValue?AQH_Value_GetName(recvdValue):NULL;
|
||||
deviceName=recvdValue?AQH_Value_GetDeviceName(recvdValue):NULL;
|
||||
if (valueName && deviceName) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQH_MqttLogServer_FindRegisteredDevice(o, deviceName);
|
||||
if (device) {
|
||||
char *valueDataFreeable;
|
||||
|
||||
DBG_ERROR(NULL, "Sending data to value \"%s\" of device \"%s\"", valueName, deviceName);
|
||||
valueDataFreeable=AQH_IpcdMessageSetData_ReadData(tagList);
|
||||
_sendDataForDevice(xo, device, valueName, valueDataFreeable);
|
||||
free(valueDataFreeable);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device \"%s\" not found", deviceName);
|
||||
AQH_MqttLogServer_DumpRegisteredDevices(o);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Either value name or device name missing in request");
|
||||
}
|
||||
AQH_Value_free(recvdValue);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Request does not contain a value object");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendDataForDevice(AQH_MQTTLOG_SERVER *xo,
|
||||
const AQHMQTT_DEVICE *device,
|
||||
const char *valueName, const char *valueData)
|
||||
{
|
||||
const char *deviceId;
|
||||
|
||||
deviceId=AQHMQTT_Device_GetId(device);
|
||||
if (deviceId && *deviceId) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==AQHMQTT_TopicDir_Out) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
AQHMQTT_VALUE *value;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
value=valueList?AQHMQTT_Value_List_GetByName(valueList, valueName):NULL;
|
||||
if (value) {
|
||||
/* found value, create publish msg, send */
|
||||
DBG_ERROR(NULL, "Topic \"%s\" contains value \"%s\"", AQHMQTT_Topic_GetName(topic), valueName);
|
||||
_sendValueToMqtt(xo, deviceId, topic, valueData);
|
||||
}
|
||||
} /* if out */
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
} /* while topic */
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device has no id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendValueToMqtt(AQH_MQTTLOG_SERVER *xo, const char *deviceId, const AQHMQTT_TOPIC *topic, const char *valueData)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
#if !DEBUG_DRY_RUN
|
||||
AQH_MESSAGE *msgOut;
|
||||
#endif
|
||||
|
||||
buf=_createBufferForTopic(deviceId, topic);
|
||||
#if !DEBUG_DRY_RUN
|
||||
DBG_ERROR(NULL, "MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
|
||||
msgOut=AQH_MqttMessagePublish_new(0, 0, GWEN_Buffer_GetStart(buf),
|
||||
(const uint8_t*) (valueData?valueData:NULL),
|
||||
valueData?strlen(valueData):0);
|
||||
if (msgOut)
|
||||
AQH_Endpoint_AddMsgOut(xo->mqttEndpoint, msgOut);
|
||||
else {
|
||||
DBG_ERROR(NULL, "Error creating message");
|
||||
}
|
||||
#else
|
||||
DBG_ERROR(NULL, "Would MQTT PUBLISH: %s = %s", GWEN_Buffer_GetStart(buf), valueData?valueData:"<empty>");
|
||||
#endif
|
||||
GWEN_Buffer_free(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_createBufferForTopic(const char *deviceId, const AQHMQTT_TOPIC *topic)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
const char *s;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
s=AQHMQTT_Topic_GetBeforeId(topic);
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
GWEN_Buffer_AppendString(buf, deviceId);
|
||||
s=AQHMQTT_Topic_GetAfterId(topic);
|
||||
if (s && *s)
|
||||
GWEN_Buffer_AppendString(buf, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-mqttlog/s_setdata.h
Normal file
27
apps/aqhome-mqttlog/s_setdata.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* This file is part of the project AqHome.
|
||||
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
|
||||
*
|
||||
* The license for this file can be found in the file COPYING which you
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMEMQTT_S_SETDATA_H
|
||||
#define AQHOMEMQTT_S_SETDATA_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <aqhome/events2/object.h>
|
||||
#include <aqhome/ipc2/message.h>
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AQH_MqttLogServer_HandleSetData(AQH_OBJECT *o, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1151
apps/aqhome-mqttlog/server.c
Normal file
1151
apps/aqhome-mqttlog/server.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user