Compare commits
1022 Commits
20230510-f
...
mp-2025_07
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9685e45861 | ||
|
|
fbda9cf228 | ||
|
|
552cd5b2ae | ||
|
|
3926b01b13 | ||
|
|
ffaa27ca24 | ||
|
|
9a1c5799aa | ||
|
|
85e66c352d | ||
|
|
d1b67a4819 | ||
|
|
51d55128a9 | ||
|
|
52a5078706 | ||
|
|
2d15091b0c | ||
|
|
81598881d1 | ||
|
|
4a74a9990f | ||
|
|
6c1e8a45ff | ||
|
|
808a7c4258 | ||
|
|
80ca6e0ac5 | ||
|
|
0989543b1b | ||
|
|
36195f88e0 | ||
|
|
3b916facf4 | ||
|
|
9d59bf31e6 | ||
|
|
a256c6261c | ||
|
|
21830321f7 | ||
|
|
eb27d223fb | ||
|
|
33cae3ab26 | ||
|
|
1612065d8a | ||
|
|
eac37b9927 | ||
|
|
b95a4fa872 | ||
|
|
81669a5442 | ||
|
|
3270a71cb0 | ||
|
|
5ae7f821e4 | ||
|
|
224aca5c41 | ||
|
|
9600be78a5 | ||
|
|
246d00a220 | ||
|
|
809439fd26 | ||
|
|
86741a0e50 | ||
|
|
41843cbab9 | ||
|
|
64854506e5 | ||
|
|
463385a296 | ||
|
|
b97fc98bc1 | ||
|
|
9b86aea7ed | ||
|
|
5bfb49d9e1 | ||
|
|
32a0ad5eae | ||
|
|
65593f95ad | ||
|
|
ec3774c7a5 | ||
|
|
4bd462ea59 | ||
|
|
77d3a201f5 | ||
|
|
127525e3ec | ||
|
|
465e750e3c | ||
|
|
6e062d3f60 | ||
|
|
7efaf720cc | ||
|
|
66ac029a69 | ||
|
|
bae188ddee | ||
|
|
87788fa93c | ||
|
|
5013bb8e29 | ||
|
|
08d420a871 | ||
|
|
3a7951be16 | ||
|
|
6a3f6be8a9 | ||
|
|
6c3926c1e4 | ||
|
|
8467408fd8 | ||
|
|
6bb499740d | ||
|
|
fc073696f8 | ||
|
|
102996f69f | ||
|
|
f9d721ac02 | ||
|
|
6bf8f03fbb | ||
|
|
fa404a5fcf | ||
|
|
3592a745d3 | ||
|
|
7c01aa255f | ||
|
|
d9e7d4df81 | ||
|
|
9b1badb310 | ||
|
|
0dc4a3a952 | ||
|
|
32bd3bc2f9 | ||
|
|
3f2ae9dd03 | ||
|
|
7fbc616ce4 | ||
|
|
8c13f9fdf7 | ||
|
|
6c5dc21f6a | ||
|
|
eb1392f3fd | ||
|
|
2b25fed2cd | ||
|
|
66b298d977 | ||
|
|
1091ec1dee | ||
|
|
d0b5f84316 | ||
|
|
ae1e4c3e37 | ||
|
|
78cbbf334e | ||
|
|
c8c12bb892 | ||
|
|
ae1853ba62 | ||
|
|
e8423ae97f | ||
|
|
597504fb08 | ||
|
|
59a0962420 | ||
|
|
323a5b76be | ||
|
|
b7234a6da2 | ||
|
|
4a5ba97b85 | ||
|
|
bdd710fc5c | ||
|
|
535a695c50 | ||
|
|
357ffe4e17 | ||
|
|
349b4a929a | ||
|
|
a06d245345 | ||
|
|
83225c453d | ||
|
|
fa94190345 | ||
|
|
68aa3beab8 | ||
|
|
3cd23d5f60 | ||
|
|
003f53b0b7 | ||
|
|
c1ea4212f2 | ||
|
|
3283a38981 | ||
|
|
3054274da5 | ||
|
|
2d84198e54 | ||
|
|
f3544f5e93 | ||
|
|
04c02b5e33 | ||
|
|
b709b7e624 | ||
|
|
8c397dd6b2 | ||
|
|
6e923ce075 | ||
|
|
245d44c05d | ||
|
|
4f497fc41a | ||
|
|
e32e8e7c13 | ||
|
|
f3020562bf | ||
|
|
fbb710a4e3 | ||
|
|
cbd498150f | ||
|
|
691ee3c71b | ||
|
|
280d5828bf | ||
|
|
6ecc1721b0 | ||
|
|
1824e8ccdf | ||
|
|
0a45e38939 | ||
|
|
81b008af0c | ||
|
|
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 | ||
|
|
bebc4c1b0d | ||
|
|
8968f14122 | ||
|
|
f63079af11 | ||
|
|
cf8edbbd5f | ||
|
|
f1f24168e5 | ||
|
|
d5d6217c5e | ||
|
|
b60de3994c | ||
|
|
6e25647c0a | ||
|
|
a7990db831 | ||
|
|
bf61be029e | ||
|
|
c5ab06b6d0 | ||
|
|
bcc7194254 | ||
|
|
2a776ca895 | ||
|
|
35f2c2bd7e | ||
|
|
393d4b4f56 | ||
|
|
4339a8e80b | ||
|
|
351ab57d62 | ||
|
|
0790ac0dea | ||
|
|
358ceaaa7d | ||
|
|
50ba9ee3a1 | ||
|
|
703f8042f9 | ||
|
|
601559ca6e | ||
|
|
a36639ed8c | ||
|
|
224a5f336a | ||
|
|
9719063a21 | ||
|
|
dbe23f7e73 | ||
|
|
702acb3304 | ||
|
|
cc8dd6e22f | ||
|
|
bb73225b86 | ||
|
|
31ca7ae529 | ||
|
|
64e781f82f | ||
|
|
2d259ae9be | ||
|
|
b38d864612 | ||
|
|
52bbfcfb15 | ||
|
|
a96bd7fc07 | ||
|
|
7962ff6213 | ||
|
|
e840bfd9e6 | ||
|
|
779b37f195 | ||
|
|
dfbc10149c | ||
|
|
22a5402141 | ||
|
|
19af9daea7 | ||
|
|
0a10d136d5 | ||
|
|
0d7aca0060 | ||
|
|
7d33e451cd | ||
|
|
d631c5465f | ||
|
|
ecb2d85ea2 | ||
|
|
c390b1059c | ||
|
|
ba279ae2bb | ||
|
|
30a2743f19 | ||
|
|
46d939fa31 | ||
|
|
f2aff6c235 | ||
|
|
e97a5c0720 | ||
|
|
6dd9a3ba8f | ||
|
|
1775fb7785 | ||
|
|
a639316cdf | ||
|
|
87706e1265 | ||
|
|
fff64ae41e | ||
|
|
3633bb03fc | ||
|
|
172998a5c4 | ||
|
|
acbe4505b9 | ||
|
|
b2193afa46 | ||
|
|
28b130ecd4 | ||
|
|
2ac1182879 | ||
|
|
f2d18fceee | ||
|
|
43c23d754c | ||
|
|
8eee81c682 | ||
|
|
34d395bb0b | ||
|
|
277af02f68 | ||
|
|
68ef24ea9b | ||
|
|
a3d5b33105 | ||
|
|
a7adf15bf6 | ||
|
|
a435b995a8 | ||
|
|
9d71ff27a7 | ||
|
|
090e178ed1 | ||
|
|
a78e354c28 | ||
|
|
9c87c3e5f3 | ||
|
|
01133cc35b | ||
|
|
4dc6031d03 | ||
|
|
c3fd458769 | ||
|
|
433720525d | ||
|
|
375ab592ff | ||
|
|
d2694df67c | ||
|
|
2270163837 | ||
|
|
9282ac3bb2 | ||
|
|
6f858e3909 | ||
|
|
cf26a01bb8 | ||
|
|
2e3705946e | ||
|
|
42f76f9d09 | ||
|
|
bc7a549513 | ||
|
|
f002587aee | ||
|
|
a520b37089 | ||
|
|
4f628a16c6 | ||
|
|
630dc2cecb | ||
|
|
51a585740d | ||
|
|
dab4980a7a | ||
|
|
e847130f0c | ||
|
|
4c88c15874 | ||
|
|
132ec3ce95 | ||
|
|
9178a6fca5 | ||
|
|
eb68e66746 | ||
|
|
b72d474a7f | ||
|
|
2b68bfd3af | ||
|
|
e4a0e8557a | ||
|
|
57bbefdf38 | ||
|
|
7707cb0a82 | ||
|
|
dfad168875 | ||
|
|
7fde61f849 | ||
|
|
8904d33789 | ||
|
|
d28e20b179 | ||
|
|
c5915b5583 | ||
|
|
2626c4365c | ||
|
|
9c35e7a006 | ||
|
|
061438b7c8 | ||
|
|
88035efdf9 | ||
|
|
3546c93d23 | ||
|
|
e232b4adbf | ||
|
|
89019f1e60 | ||
|
|
efc91241d9 | ||
|
|
c90c33ec11 | ||
|
|
aca24183e4 | ||
|
|
1626526714 | ||
|
|
7ad64cd654 | ||
|
|
cc6ed1198b | ||
|
|
fae5b55e82 | ||
|
|
a6af10a32d | ||
|
|
97138bcbe0 | ||
|
|
2b8cabd391 | ||
|
|
85d0992ce9 | ||
|
|
b3199681de | ||
|
|
b78fc0999b | ||
|
|
3cba4a1f7c | ||
|
|
d7705590fe | ||
|
|
adcb037976 | ||
|
|
072ed88102 | ||
|
|
cc1dcc4d7f | ||
|
|
25efeeb244 | ||
|
|
0926ba2381 | ||
|
|
1d08945ae5 | ||
|
|
d2ac801223 | ||
|
|
8f6291ef02 | ||
|
|
21d47b8b7f | ||
|
|
6f5da8ee6c | ||
|
|
9c2001285b | ||
|
|
8199f7c3b0 | ||
|
|
03f9178dd2 | ||
|
|
0566483575 | ||
|
|
3a9bb3d5ec | ||
|
|
2d7459394e | ||
|
|
bb77c6acd1 | ||
|
|
10564ec78f | ||
|
|
ee73bb0f69 | ||
|
|
8aa4143d8a | ||
|
|
c22edcbbec | ||
|
|
8dd9e69bdf | ||
|
|
2014304c73 | ||
|
|
c2d7564e0c | ||
|
|
d70c673b8a | ||
|
|
23489dd5bf | ||
|
|
5767c1307d | ||
|
|
b93ead5e5f | ||
|
|
6fc7f5fc7a | ||
|
|
60c86c7598 | ||
|
|
07f99b7050 | ||
|
|
6676024cb0 | ||
|
|
cf9118e41d | ||
|
|
49d037c040 | ||
|
|
b0b6efb1c3 | ||
|
|
be053b035f | ||
|
|
a839d97140 | ||
|
|
bdcbaa2b46 | ||
|
|
a624331166 | ||
|
|
7e4977f472 | ||
|
|
9adb95d532 | ||
|
|
f729766e6b | ||
|
|
4548b3c225 | ||
|
|
caa7138738 | ||
|
|
91752156f2 | ||
|
|
a1a64fec42 | ||
|
|
9e80636acb | ||
|
|
741dd4fe12 | ||
|
|
5ca1fd4275 | ||
|
|
7590aa3717 | ||
|
|
08399ecf87 | ||
|
|
0e83988904 | ||
|
|
3bec999ae0 | ||
|
|
5b3c813981 | ||
|
|
b490646799 | ||
|
|
f912c537d4 | ||
|
|
3af514d946 | ||
|
|
9a2a1764d9 | ||
|
|
4687a8726b | ||
|
|
7a5900be25 | ||
|
|
2d09e22ec6 | ||
|
|
cdcb4e2b3e | ||
|
|
6ff68b848c | ||
|
|
0f98ed87a4 | ||
|
|
ee94d8a583 | ||
|
|
4ba0e01c9f | ||
|
|
c908eb4840 | ||
|
|
892dc65898 | ||
|
|
0c819bcd19 | ||
|
|
caf04e88f3 | ||
|
|
79f4018341 | ||
|
|
f1fe99673b | ||
|
|
79afc70b92 | ||
|
|
ec033cfd10 | ||
|
|
0107330c32 | ||
|
|
cb43378a2f | ||
|
|
0fafb36100 | ||
|
|
88aea30da1 | ||
|
|
4a20933397 | ||
|
|
a10cd8293b | ||
|
|
c055ee6cc2 | ||
|
|
7fbe9744ea | ||
|
|
0fabc6d613 | ||
|
|
39933a957b | ||
|
|
6308207548 | ||
|
|
2de89ecc96 | ||
|
|
85d7ccf0f2 | ||
|
|
d14363b8f0 | ||
|
|
a298e6845a | ||
|
|
d8985183f7 | ||
|
|
ad34bc8ec3 | ||
|
|
0bc37343a5 | ||
|
|
73f749b5bb | ||
|
|
28882010a9 | ||
|
|
b0afa98387 | ||
|
|
6ba1a18de1 | ||
|
|
c79037a1e1 | ||
|
|
743b33664f | ||
|
|
fd43a89bcd | ||
|
|
9bd376464a | ||
|
|
e70c294d9b | ||
|
|
a456211438 | ||
|
|
1c4d94c5ce | ||
|
|
50546799dc | ||
|
|
9bc837249e | ||
|
|
2215d68544 | ||
|
|
fc6130f4cc | ||
|
|
cf1983d264 | ||
|
|
ed21f4bbfc | ||
|
|
d99787b787 | ||
|
|
5f2da242c5 | ||
|
|
9b724d5a5f | ||
|
|
2fa3e9d4ab | ||
|
|
5e4ca45443 | ||
|
|
090917ea09 | ||
|
|
7e3523ec42 | ||
|
|
12a2cc1b8e | ||
|
|
6b0972d76e | ||
|
|
984cccc25b | ||
|
|
dbad1ba8a1 | ||
|
|
b70e0e0bc2 | ||
|
|
595a140428 | ||
|
|
b94105bf78 | ||
|
|
eec544d1b8 | ||
|
|
cb6e21715a | ||
|
|
026d4a57fb | ||
|
|
7745accfae | ||
|
|
cea3137b5a | ||
|
|
c73fede935 | ||
|
|
b56947dcba | ||
|
|
a23997db39 | ||
|
|
51ba17d43f | ||
|
|
575b0285fe | ||
|
|
277a27516c | ||
|
|
817ff958b9 | ||
|
|
ea2cd6e58e | ||
|
|
1f2f8b574e | ||
|
|
cd6413e7a6 | ||
|
|
425c26cfbb | ||
|
|
f2ab0d8b9f | ||
|
|
e0a6ddd89f | ||
|
|
c02f371350 | ||
|
|
c2a6d33ff2 | ||
|
|
8aeb488e2e | ||
|
|
45cae14f6a | ||
|
|
892d9f5c5a | ||
|
|
65e60c2dec | ||
|
|
6aac577365 | ||
|
|
85a93065a4 | ||
|
|
319cdbce18 | ||
|
|
c800e99dc8 | ||
|
|
2da873bbb9 | ||
|
|
6abac9b5a1 | ||
|
|
ed1f96fdbc | ||
|
|
37a290ce1f | ||
|
|
a3bf403ac0 | ||
|
|
dde9106a5d | ||
|
|
334d0e8096 | ||
|
|
abada7b89b | ||
|
|
69893640a3 | ||
|
|
9f7f5ab0db | ||
|
|
6828438780 | ||
|
|
05fb3d3b0a | ||
|
|
66c583f866 | ||
|
|
2363535fe0 | ||
|
|
9d0037b83d | ||
|
|
f8f4380038 | ||
|
|
ead34f0309 | ||
|
|
1d51ef0259 | ||
|
|
b888524cc3 | ||
|
|
5ec9827f92 | ||
|
|
7ce34b0500 | ||
|
|
516ac4e34e | ||
|
|
36e9909060 | ||
|
|
403392a72e | ||
|
|
2c584bbff9 | ||
|
|
b6e4a5265a | ||
|
|
b473d62cdc | ||
|
|
3e5bff90d1 | ||
|
|
d5b1dbd5ee | ||
|
|
29eb910881 | ||
|
|
bcc7629b1e | ||
|
|
f400104bbc | ||
|
|
a3d0fad984 | ||
|
|
075fbc1cb5 | ||
|
|
c9d82cc88e | ||
|
|
2342dfbe4a | ||
|
|
dbc8fdf35d | ||
|
|
89dd230b8f | ||
|
|
243754c15d | ||
|
|
d17274c6d6 | ||
|
|
9b2b9dccea | ||
|
|
83106327fa | ||
|
|
87114cecea | ||
|
|
f3c68a8bba | ||
|
|
f083fb1c00 | ||
|
|
88d049d68a | ||
|
|
7ee7edffec | ||
|
|
e486a7e69d | ||
|
|
2443fbca9f | ||
|
|
716c1c58df | ||
|
|
7ea260031e | ||
|
|
02c256ffa2 | ||
|
|
02f02b1ad1 | ||
|
|
f4902d5717 | ||
|
|
8bb60fdba7 | ||
|
|
1050ee1c75 | ||
|
|
ec816bddcf | ||
|
|
9468911451 | ||
|
|
61ce363a8a | ||
|
|
563e5f0eff | ||
|
|
ec5aeb9a05 | ||
|
|
9a4eb3c608 | ||
|
|
dd133c7368 | ||
|
|
a7267c061a | ||
|
|
a94ebeca29 | ||
|
|
1b1d2f6c9e | ||
|
|
83cdc8abe3 | ||
|
|
2653b16939 | ||
|
|
ee19014644 | ||
|
|
a479538743 | ||
|
|
2ac4887f01 | ||
|
|
8a7a4c7a64 | ||
|
|
c62165cd92 | ||
|
|
5305aa7fe3 | ||
|
|
e29a32f24b | ||
|
|
50bdefcb4a | ||
|
|
02d12b4209 | ||
|
|
6f9e20095a | ||
|
|
e0476924c1 | ||
|
|
2787bb9b79 | ||
|
|
d92ae455db | ||
|
|
f9a5119d1f | ||
|
|
e162d9564b | ||
|
|
6889d5d851 | ||
|
|
87d22b1e16 | ||
|
|
30522df662 | ||
|
|
ed4fc1852a | ||
|
|
d6494d07d5 | ||
|
|
2c8e57ecff | ||
|
|
d3a6256c8c | ||
|
|
656c9cf66f | ||
|
|
db19019202 | ||
|
|
5712b041fe | ||
|
|
5925bc58b1 | ||
|
|
2e29790be7 | ||
|
|
0545a802de | ||
|
|
a3efa18a61 | ||
|
|
605d78a2b7 | ||
|
|
e7bfa36cab | ||
|
|
dce1b8698a | ||
|
|
e4c753cefd | ||
|
|
9e49e60aa8 | ||
|
|
4c44890d3c | ||
|
|
ef22bd65ea | ||
|
|
1ba263fb13 | ||
|
|
0cf3976fc7 | ||
|
|
eeffe225ec | ||
|
|
de1a975586 | ||
|
|
13d161d119 | ||
|
|
793d12693b | ||
|
|
5888bc9068 | ||
|
|
b6fe1775bd | ||
|
|
90d2467fde | ||
|
|
3c91a83177 | ||
|
|
c7ee9dc18c | ||
|
|
62abfd56e9 | ||
|
|
b818065b9b | ||
|
|
c9b88f2cea | ||
|
|
f0cfbfccc4 | ||
|
|
a3f866f69c | ||
|
|
16e08d623d | ||
|
|
077b367299 | ||
|
|
d1f7a6b730 | ||
|
|
f26c78a5e9 | ||
|
|
0fc18c1da1 | ||
|
|
ddded51f9e | ||
|
|
7b89df6153 | ||
|
|
161dee1667 | ||
|
|
e98afa80d9 | ||
|
|
38ae2d3d1d | ||
|
|
79c71563d5 | ||
|
|
fa12be880a | ||
|
|
dcdb512995 | ||
|
|
7fb4e8b577 | ||
|
|
7f1c66cbe6 | ||
|
|
c90e8c899a | ||
|
|
ab6480ebca | ||
|
|
8613fbdad7 | ||
|
|
b66f3d2ef4 | ||
|
|
f1753eeea7 | ||
|
|
bfed937950 | ||
|
|
4730943931 | ||
|
|
afc0994c38 | ||
|
|
831c94f898 | ||
|
|
0740378ad8 | ||
|
|
f56b25d06f | ||
|
|
eadfead77c | ||
|
|
17d4ce5125 | ||
|
|
253b3862da | ||
|
|
043541f936 | ||
|
|
45da38b64a | ||
|
|
c57472d86e | ||
|
|
1e27223dfa | ||
|
|
0f896c1729 | ||
|
|
66073737a4 | ||
|
|
bf89562d51 | ||
|
|
2adefc4b79 | ||
|
|
f03c078606 | ||
|
|
d6ae79cf81 | ||
|
|
0814cf4af1 | ||
|
|
74789b802f | ||
|
|
5f6581d126 | ||
|
|
8c60c3c8e4 | ||
|
|
cf005fa60c | ||
|
|
9b7d043682 | ||
|
|
161b979e84 | ||
|
|
11798a39d6 | ||
|
|
07abc76a7a | ||
|
|
e1639a9d13 | ||
|
|
71f5ce8c7e | ||
|
|
518a3a53f9 | ||
|
|
2b733a52ca | ||
|
|
3bfb39966f | ||
|
|
f9ae85b9ad | ||
|
|
5fdb33c192 | ||
|
|
51a13f286f | ||
|
|
290967a7c5 | ||
|
|
64938b9cb0 | ||
|
|
590eccf8d9 | ||
|
|
a4c0f2e6fd | ||
|
|
bcd3e3325c | ||
|
|
c1353c056a | ||
|
|
9602471a9b | ||
|
|
f5878f43ff | ||
|
|
edcac1f2b9 | ||
|
|
e25a391fde | ||
|
|
978d3f6f7a | ||
|
|
c5171714b2 | ||
|
|
96c2b9a649 | ||
|
|
487e506a01 | ||
|
|
ec745f5cc9 | ||
|
|
17889fd30b | ||
|
|
23c9e286b1 | ||
|
|
a2c79aa6db | ||
|
|
f716ebd338 | ||
|
|
9b0122e34c | ||
|
|
b9a54b8ffb | ||
|
|
b5916acf79 | ||
|
|
4701a71986 | ||
|
|
fc2c18b489 | ||
|
|
0cc498d830 | ||
|
|
28bc8efac8 | ||
|
|
aafecfa704 | ||
|
|
3378908c93 | ||
|
|
e4135a7bbd | ||
|
|
1efcd09f0c | ||
|
|
6269431467 | ||
|
|
792f167a71 | ||
|
|
897fdffcf9 | ||
|
|
53e1fbae56 | ||
|
|
16ce958964 | ||
|
|
db5d6cb980 | ||
|
|
06b5ab26c8 | ||
|
|
02797ff092 | ||
|
|
3eb0a9afa9 | ||
|
|
5852ad9a1e | ||
|
|
8ee0602f7a | ||
|
|
f8c325e747 | ||
|
|
893ae6867b | ||
|
|
3efb83ecfd | ||
|
|
f30c4895fa | ||
|
|
0fd58567fe | ||
|
|
7a4edb6854 | ||
|
|
c7f232dd98 | ||
|
|
4489314b47 | ||
|
|
08c3875a26 | ||
|
|
39987b31c7 | ||
|
|
43b23b2636 | ||
|
|
2d393630d8 | ||
|
|
5105c0c7f7 | ||
|
|
6f5a26b0cf | ||
|
|
d766a3635a | ||
|
|
b4175f4a89 | ||
|
|
f0917064af | ||
|
|
1751170940 | ||
|
|
3e85dc9bd5 | ||
|
|
54301fed44 | ||
|
|
efcab6f38d | ||
|
|
9f32f206b3 | ||
|
|
6a22fb9956 | ||
|
|
a29a314976 | ||
|
|
226922d3e4 | ||
|
|
84403d07f6 |
20
.gitignore
vendored
20
.gitignore
vendored
@@ -4,3 +4,23 @@ build/
|
||||
aqhome.db
|
||||
aqhome.log
|
||||
aqhomed.vg
|
||||
aqhome-mqttlog.vg
|
||||
aqhome-storage.vg
|
||||
aqhome-storage.pid
|
||||
aqhome-data.vg
|
||||
aqhome-data.pid
|
||||
aqhome-nodes.db
|
||||
aqhome-nodes.log
|
||||
aqhome-nodes.pid
|
||||
aqhome-nodes.vg
|
||||
aqhome-tool.vg
|
||||
aqhome-mqtt.pid
|
||||
aqhome-mqtt.devices
|
||||
aqhome-react.pid
|
||||
|
||||
core.*
|
||||
core
|
||||
aqhome.geany
|
||||
aqhome-nodes.db
|
||||
aqhome-nodes.db.*
|
||||
|
||||
|
||||
82
0BUILD
82
0BUILD
@@ -2,7 +2,7 @@
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<project name="aqhome" version="0.0.1" so_current="0" so_age="0" so_revision="0" write_config_h="TRUE">
|
||||
<project name="aqhome" version="0.0.14" so_current="0" so_age="0" so_revision="14" write_config_h="TRUE">
|
||||
<setVar name="package">$(project_name)</setVar>
|
||||
<setVar name="version">
|
||||
$(project_vmajor).$(project_vminor).$(project_vpatchlevel)
|
||||
@@ -44,23 +44,83 @@
|
||||
<setVar name="includedir">$(option_prefix)/include</setVar>
|
||||
<setVar name="datarootdir">$(option_prefix)/share</setVar>
|
||||
<setVar name="datadir">$(option_prefix)/share</setVar>
|
||||
<setVar name="rtdatadir">$(option_prefix)/var/lib</setVar>
|
||||
<setVar name="localedir">$(option_prefix)/share/locale</setVar>
|
||||
|
||||
<setVar name="pkglibdir">$(libdir)/$(package)</setVar>
|
||||
<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>
|
||||
</option>
|
||||
<ifVarMatches name="option_enable_testcode" value="TRUE" >
|
||||
<define name="AQHOME_ENABLE_TESTCODE" value="1" />
|
||||
</ifVarMatches>
|
||||
|
||||
|
||||
<option id="local_install" type="string">
|
||||
<default>FALSE</default>
|
||||
<choices>TRUE FALSE</choices>
|
||||
</option>
|
||||
<ifVarMatches name="option_local_install" value="TRUE" >
|
||||
<define name="ENABLE_LOCAL_INSTALL" value="1" />
|
||||
</ifVarMatches>
|
||||
|
||||
|
||||
<option id="debug" type="string">
|
||||
<default>TRUE</default>
|
||||
<choices>TRUE FALSE</choices>
|
||||
</option>
|
||||
<ifVarMatches name="option_debug" value="TRUE" >
|
||||
<setVar name="CFLAGS">-ggdb -Wall -O0</setVar>
|
||||
<setVar name="CXXFLAGS">-ggdb -Wall -O0</setVar>
|
||||
<setVar name="CFLAGS">
|
||||
-ggdb -Wall -Og -W
|
||||
-Wbad-function-cast -Wmissing-parameter-type
|
||||
-Wnested-externs -Wstringop-overflow=2
|
||||
-Wdeclaration-after-statement -Wpointer-sign
|
||||
-Wunused-parameter
|
||||
</setVar>
|
||||
<setVar name="CXXFLAGS">-ggdb -Wall -Og</setVar>
|
||||
</ifVarMatches>
|
||||
|
||||
|
||||
|
||||
<!-- paths -->
|
||||
<ifVarMatches name="GWBUILD_SYSTEM" value="windows" > <!-- long version of IF statement with THEN and ELSE -->
|
||||
<then>
|
||||
<define name="OS_WIN32" value="1" />
|
||||
<setVar name="aqhome_sys_is_windows">1</setVar>
|
||||
<setVar name="aqhome_cfg_searchdir">etc</setVar>
|
||||
<setVar name="aqhome_locale_searchdir">share/locale</setVar>
|
||||
<setVar name="aqhome_data_searchdir">share"</setVar>
|
||||
<setVar name="aqhome_rtdata_searchdir">var/lib</setVar>
|
||||
</then>
|
||||
<else>
|
||||
<define name="OS_POSIX" value="1" />
|
||||
<setVar name="aqhome_sys_is_windows">0</setVar>
|
||||
<ifVarMatches name="option_local_install" value="TRUE" >
|
||||
<then>
|
||||
<setVar name="aqhome_cfg_searchdir">etc</setVar>
|
||||
<setVar name="aqhome_locale_searchdir">share/locale</setVar>
|
||||
<setVar name="aqhome_data_searchdir">share</setVar>
|
||||
<setVar name="aqhome_rtdata_searchdir">var/lib</setVar>
|
||||
</then>
|
||||
<else>
|
||||
<setVar name="aqhome_cfg_searchdir">$(sysconfdir)</setVar>
|
||||
<setVar name="aqhome_locale_searchdir">$(datadir)/locale</setVar>
|
||||
<setVar name="aqhome_data_searchdir">$(datadir)</setVar>
|
||||
<setVar name="aqhome_rtdata_searchdir">$(rtdatadir)</setVar>
|
||||
</else>
|
||||
</ifVarMatches>
|
||||
</else>
|
||||
</ifVarMatches>
|
||||
<define name="AQHOME_SYS_IS_WINDOWS" value="$(aqhome_sys_is_windows)" />
|
||||
|
||||
|
||||
|
||||
<!-- use "-Owith_avr=TRUE" or "FALSE" to enable or disable assembling AVR code -->
|
||||
<option id="with_avr" type="string">
|
||||
<default>TRUE</default>
|
||||
@@ -68,6 +128,7 @@
|
||||
</option>
|
||||
|
||||
|
||||
|
||||
<checkheaders>
|
||||
signal.h
|
||||
sys/stat.h
|
||||
@@ -88,9 +149,14 @@
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dep id="gwenhywfar" name="gwenhywfar" minversion="5.8.2.1" required="TRUE" >
|
||||
<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>
|
||||
-->
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -110,6 +176,9 @@
|
||||
<subdirs>
|
||||
aqhome
|
||||
apps
|
||||
devices
|
||||
etc
|
||||
scripts
|
||||
</subdirs>
|
||||
|
||||
<ifVarMatches name="option_with_avr" value="TRUE" >
|
||||
@@ -131,7 +200,10 @@
|
||||
|
||||
<output>
|
||||
</output>
|
||||
|
||||
<!-- see http://eleccelerator.com/fusecalc/fusecalc.php?chip=attiny84 -->
|
||||
<!-- disable divide by 8: -U lfuse:w:0xEA:m default (divide by 8): -U lfuse:w:0x6A:m -->
|
||||
<!-- changes to hfuse: enable EESAVE -->
|
||||
<!-- changes to efuse: enable SELFPRGEN -->
|
||||
<cmd tool="$(avrdude)" checkDates="FALSE" >
|
||||
-p t84 -c stk500 -P /dev/ttyACM0 -B16 -U hfuse:w:0xD7:m -U efuse:w:0xFE:m -U flash:w:avr/att84_temp1.hex
|
||||
</cmd>
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
<gwbuild>
|
||||
|
||||
<subdirs>
|
||||
aqhomed
|
||||
aqhome-tool
|
||||
aqhome-mqttlog
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
84
apps/aqhome-cgi/modules/0BUILD
Normal file
84
apps/aqhome-cgi/modules/0BUILD
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<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" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
|
||||
<define name="BUILDING_AQHOME" />
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
|
||||
<setVar name="tm2flags-INACTIVE" >
|
||||
--api=AQHOME_API
|
||||
</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="false" install="$(pkgincludedir)/service" >
|
||||
$(local/built_headers_pub)
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" install="$(pkgincludedir)/service" >
|
||||
mservice.h
|
||||
mroot.h
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" >
|
||||
mservice_p.h
|
||||
mroot_p.h
|
||||
</headers>
|
||||
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
mservice.c
|
||||
mroot.c
|
||||
</sources>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
<useTargets>
|
||||
</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
|
||||
|
||||
18
apps/aqhome-cgi/modules/mroot_p.h
Normal file
18
apps/aqhome-cgi/modules/mroot_p.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/****************************************************************************
|
||||
* 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_P_H
|
||||
#define AQHOME_CGI_MROOT_P_H
|
||||
|
||||
#include "aqhome-cgi/modules/mroot.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
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>
|
||||
86
apps/aqhome-cgi/service/0BUILD
Normal file
86
apps/aqhome-cgi/service/0BUILD
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<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" >
|
||||
--include=$(builddir)
|
||||
--include=$(srcdir)
|
||||
</includes>
|
||||
|
||||
|
||||
<define name="BUILDING_AQHOME" />
|
||||
|
||||
<setVar name="local/cflags">$(visibility_cflags)</setVar>
|
||||
|
||||
|
||||
<setVar name="tm2flags-INACTIVE" >
|
||||
--api=AQHOME_API
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/typefiles" >
|
||||
module.t2d
|
||||
moduleperms.t2d
|
||||
role.t2d
|
||||
user.t2d
|
||||
session.t2d
|
||||
permdef.t2d
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
</setVar>
|
||||
|
||||
|
||||
<headers dist="false" install="$(pkgincludedir)/service" >
|
||||
$(local/built_headers_pub)
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" install="$(pkgincludedir)/service" >
|
||||
service.h
|
||||
</headers>
|
||||
|
||||
|
||||
<headers dist="true" >
|
||||
service_p.h
|
||||
</headers>
|
||||
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
|
||||
service.c
|
||||
</sources>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
<useTargets>
|
||||
</useTargets>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
</target>
|
||||
|
||||
</gwbuild>
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
103
apps/aqhome-cgi/service/module.t2d
Normal file
103
apps/aqhome-cgi/service/module.t2d
Normal file
@@ -0,0 +1,103 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQH_MODULE" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQH_MODULE</identifier>
|
||||
<prefix>AQH_Module</prefix>
|
||||
<baseFileName>module</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_inherit
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
with_tree2
|
||||
nodup
|
||||
nocopy
|
||||
</flags>
|
||||
|
||||
<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-cgi/service/role.h</header>
|
||||
<header type="sys" loc="post">aqhome-cgi/service/permdef.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
</lang>
|
||||
|
||||
<defines>
|
||||
<define id="AQH_MODULE_FLAGS" prefix="AQH_MODULE_FLAGS_">
|
||||
<item name="ACTIVE" value="0x00000001" />
|
||||
</define>
|
||||
|
||||
</defines>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<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>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="descr" type="char_ptr" maxlen="256">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="guestPerms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="roleList" type="AQH_ROLE_LIST" elementName="role" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
<member name="permDefList" type="AQH_PERMDEF_LIST" elementName="permdef" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
75
apps/aqhome-cgi/service/moduleperms.t2d
Normal file
75
apps/aqhome-cgi/service/moduleperms.t2d
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQH_MODULE_PERMS" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQH_MODULE_PERMS</identifier>
|
||||
<prefix>AQH_ModulePerms</prefix>
|
||||
<baseFileName>moduleperms</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_inherit
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<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-cgi/service/role.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="moduleId" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="exclAddPerms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="exclDelPerms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="roleArray" type="uint8_t_array" maxlen="16">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="perms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>volatile</flags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
65
apps/aqhome-cgi/service/permdef.t2d
Normal file
65
apps/aqhome-cgi/service/permdef.t2d
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQH_PERMDEF" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQH_PERMDEF</identifier>
|
||||
<prefix>AQH_PermDef</prefix>
|
||||
<baseFileName>permdef</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
nodup
|
||||
nocopy
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="char_ptr" maxlen="32">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="32">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="mask" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="descr" type="char_ptr" maxlen="256">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
72
apps/aqhome-cgi/service/role.t2d
Normal file
72
apps/aqhome-cgi/service/role.t2d
Normal file
@@ -0,0 +1,72 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQH_ROLE" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQH_ROLE</identifier>
|
||||
<prefix>AQH_Role</prefix>
|
||||
<baseFileName>role</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">gwenhywfar/error.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="uint8_t" maxlen="1">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="16">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="perms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="explAddPerms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="explDelPerms" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
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
|
||||
117
apps/aqhome-cgi/service/session.t2d
Normal file
117
apps/aqhome-cgi/service/session.t2d
Normal file
@@ -0,0 +1,117 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQH_SESSION" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQH_SESSION</identifier>
|
||||
<prefix>AQH_Session</prefix>
|
||||
<baseFileName>session</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
nodup
|
||||
nocopy
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<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-cgi/service/user.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
|
||||
<defines>
|
||||
<define id="AQH_SESSION_RTFLAGS" prefix="AQH_SESSION_RTFLAGS_">
|
||||
<item name="MODIFIED" value="0x00000001" />
|
||||
</define>
|
||||
</defines>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="uid" type="char_ptr" maxlen="64">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own 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="userAlias" type="char_ptr" maxlen="64">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="state" type="int" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="tempToken" type="char_ptr" maxlen="64">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="timestampCreation" type="gwen_timestamp" maxlen="8">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="timestampLastAccess" type="gwen_timestamp" maxlen="8">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="user" type="AQH_USER">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<setflags>assign</setflags>
|
||||
<getflags>none</getflags>
|
||||
<flags>volatile nodup nocopy</flags>
|
||||
</member>
|
||||
|
||||
|
||||
|
||||
<member name="runtimeFlags" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>with_flags volatile</flags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
160
apps/aqhome-cgi/service/user.t2d
Normal file
160
apps/aqhome-cgi/service/user.t2d
Normal file
@@ -0,0 +1,160 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQH_USER" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQH_USER</identifier>
|
||||
<prefix>AQH_User</prefix>
|
||||
<baseFileName>user</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_xml
|
||||
with_db
|
||||
with_list1
|
||||
with_list2
|
||||
with_refcount
|
||||
nodup
|
||||
nocopy
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<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-cgi/service/moduleperms.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
</lang>
|
||||
|
||||
<defines>
|
||||
<define id="AQH_USER_RTFLAGS" prefix="AQH_USER_RTFLAGS_">
|
||||
<item name="MODIFIED" value="0x00000001" />
|
||||
<item name="PERMSCALC" value="0x00000002" />
|
||||
</define>
|
||||
|
||||
</defines>
|
||||
|
||||
<enums>
|
||||
|
||||
<enum id="AQH_USER_STATE" prefix="AQH_UserState_">
|
||||
<item name="suspended">
|
||||
<descr>User suspended</descr>
|
||||
</item>
|
||||
|
||||
<item name="waitForConfirmation">
|
||||
<descr>Waiting for email confirmation</descr>
|
||||
</item>
|
||||
|
||||
<item name="waitForApproval">
|
||||
<descr>Waiting for approval by admin</descr>
|
||||
</item>
|
||||
|
||||
<item name="active">
|
||||
<descr>User active</descr>
|
||||
</item>
|
||||
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<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="state" type="int" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="16">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="alias" type="char_ptr" maxlen="16">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="hashedPassword" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="email" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="notes" type="char_ptr" maxlen="256">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="timestampCreation" type="gwen_timestamp" maxlen="8">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="timestampLastLogin" type="gwen_timestamp" maxlen="8">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="modulePermList" type="AQH_MODULE_PERMS_LIST">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="runtimeFlags" type="uint32_t" maxlen="4">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>volatile with_flags</flags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
21
apps/aqhome-cgi/service_file.h
Normal file
21
apps/aqhome-cgi/service_file.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/****************************************************************************
|
||||
* 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_FILE_H
|
||||
#define AQHOME_SERVICE_FILE_H
|
||||
|
||||
|
||||
#include "aqhome-cgi/service/service.h"
|
||||
|
||||
|
||||
AQH_SERVICE *AQH_ServiceFiles_new(const char *baseFolder);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -6,21 +6,20 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_MSG_MANAGER_P_H
|
||||
#define AQH_MSG_MANAGER_P_H
|
||||
#ifndef AQHOME_SERVICE_FILE_P_H
|
||||
#define AQHOME_SERVICE_FILE_P_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include "aqhome-cgi/service_file.h"
|
||||
|
||||
#include <aqhome/msgmanager.h>
|
||||
#include <aqhome/nodes/nodedb.h>
|
||||
#include <gwenhywfar/configmgr.h>
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_MSG_MANAGER AQH_MSG_MANAGER;
|
||||
struct AQH_MSG_MANAGER {
|
||||
AQH_NODE_DB *nodeDb;
|
||||
char *dbFilename;
|
||||
typedef struct AQH_SERVICE_FILE AQH_SERVICE_FILE;
|
||||
struct AQH_SERVICE_FILE {
|
||||
char *baseFolder;
|
||||
GWEN_CONFIGMGR *configMgr;
|
||||
};
|
||||
|
||||
|
||||
1
apps/aqhome-data/.gitignore
vendored
Normal file
1
apps/aqhome-data/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
test/
|
||||
88
apps/aqhome-data/0BUILD
Normal file
88
apps/aqhome-data/0BUILD
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-data" install="$(sbindir)" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-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" >
|
||||
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)
|
||||
|
||||
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>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
268
apps/aqhome-data/main.c
Normal file
268
apps/aqhome-data/main.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/****************************************************************************
|
||||
* 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/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define DISABLE_DEBUGLOG
|
||||
|
||||
|
||||
//#define WRITE_INTERVAL_IN_SECS (5*60)
|
||||
|
||||
#define WRITE_INTERVAL_IN_SECS 60
|
||||
#define PING_INTERVAL 120
|
||||
#define CONNCLEAN_INTERVAL_IN_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
|
||||
#endif
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
AQH_EVENT_LOOP *eventLoop;
|
||||
AQH_OBJECT *aqh;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhome-data", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
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, eventLoop);
|
||||
|
||||
AqHomeDataServer_Fini(aqh);
|
||||
AQH_Object_free(aqh);
|
||||
AQH_EventLoop_free(eventLoop);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
{
|
||||
time_t timeStart;
|
||||
time_t timeLastWrite;
|
||||
time_t timeLastConnectionCleanup;
|
||||
int timeout;
|
||||
|
||||
timeout=AqHomeDataServer_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastWrite=time(NULL);
|
||||
timeLastConnectionCleanup=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
time_t now;
|
||||
|
||||
DBG_INFO(NULL, "Next loop (%d clients)", AqHomeDataServer_GetClientNum(aqh));
|
||||
AQH_EventLoop_Run(eventLoop, 2000);
|
||||
AqHomeDataServer_HandleClientMsgs(aqh);
|
||||
|
||||
now=time(NULL);
|
||||
|
||||
if (_diffInSeconds(now, timeLastConnectionCleanup)>CONNCLEAN_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Cleanup connections");
|
||||
AqHomeDataServer_CleanupClients(aqh);
|
||||
timeLastConnectionCleanup=now;
|
||||
}
|
||||
|
||||
if (_diffInSeconds(now, timeLastWrite)>WRITE_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Write time");
|
||||
_writeCurrentState(aqh);
|
||||
timeLastWrite=now;
|
||||
}
|
||||
|
||||
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
|
||||
DBG_ERROR(NULL, "Timeout");
|
||||
_writeCurrentState(aqh);
|
||||
break;
|
||||
}
|
||||
} /* while */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _diffInSeconds(time_t t1, time_t t0)
|
||||
{
|
||||
return t1-t0;
|
||||
}
|
||||
|
||||
|
||||
void _writeCurrentState(AQH_OBJECT *aqh)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=AqHomeDataServer_WriteStorageIfChanged(aqh);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "ATTENTION: Could not write storage statefile (%d)", rv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saPIPE, SIGPIPE);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
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,24 +6,22 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQH_MSG_ENDPOINT_MGR_P_H
|
||||
#define AQH_MSG_ENDPOINT_MGR_P_H
|
||||
#ifndef AQHOME_DATA_S_GETDEVICES_H
|
||||
#define AQHOME_DATA_S_GETDEVICES_H
|
||||
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include "./server.h"
|
||||
|
||||
#include "aqhome/msg/endpointmgr.h"
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_MSG_ENDPOINT_MGR AQH_MSG_ENDPOINT_MGR;
|
||||
struct AQH_MSG_ENDPOINT_MGR {
|
||||
uint8_t busAddr;
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
|
||||
49
apps/aqhome-data/server_p.h
Normal file
49
apps/aqhome-data/server_p.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/****************************************************************************
|
||||
* 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_P_H
|
||||
#define AQHOME_DATA_SERVER_P_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <aqhome/events2/object.h>
|
||||
|
||||
#include <gwenhywfar/mutex.h>
|
||||
|
||||
|
||||
#define AQHOME_DATA_DEFAULT_PIDFILE "/var/run/aqhome-data.pid"
|
||||
#define AQHOME_DATA_DEFAULT_DATADIR "/var/lib/aqhome-data/data"
|
||||
#define AQHOME_DATA_DEFAULT_IPC_PORT 45456
|
||||
|
||||
#define AQHOME_DATA_STATEFILENAME "statefile"
|
||||
|
||||
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
AQHOME_SERVER *AqHomeDataServer_GetServerData(const AQH_OBJECT *o);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
81
apps/aqhome-mqttlog/0BUILD
Normal file
81
apps/aqhome-mqttlog/0BUILD
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-mqttlog" install="$(sbindir)" >
|
||||
|
||||
<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" >
|
||||
xmlread.h
|
||||
xmlwrite.h
|
||||
server.h
|
||||
server_p.h
|
||||
s_publish.h
|
||||
s_setdata.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
main.c
|
||||
xmlread.c
|
||||
xmlwrite.c
|
||||
server.c
|
||||
s_publish.c
|
||||
s_setdata.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhome
|
||||
aqhmqtt_types
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
types
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
283
apps/aqhome-mqttlog/main.c
Normal file
283
apps/aqhome-mqttlog/main.c
Normal file
@@ -0,0 +1,283 @@
|
||||
/****************************************************************************
|
||||
* 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 "./server.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/db.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.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
|
||||
|
||||
#define CONNCHECK_INTERVAL_IN_SECS 10
|
||||
#define PING_INTERVAL_IN_SECS 120
|
||||
#define SAVE_INTERVAL_IN_SECS 60
|
||||
|
||||
#define FULL_DEBUG
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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, saPIPE;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
AQH_EVENT_LOOP *eventLoop;
|
||||
AQH_OBJECT *aqh;
|
||||
int rv;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
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_Notice);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
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;
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
_runService(aqh, eventLoop);
|
||||
|
||||
|
||||
AQH_MqttLogServer_Fini(aqh);
|
||||
AQH_Object_free(aqh);
|
||||
AQH_EventLoop_free(eventLoop);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
{
|
||||
time_t timeStart;
|
||||
int timeout;
|
||||
time_t timeLastConnCheck;
|
||||
time_t timeLastSave;
|
||||
time_t timeLastPingSend;
|
||||
int rv;
|
||||
|
||||
timeout=AQH_MqttLogServer_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastConnCheck=time(NULL);
|
||||
timeLastSave=time(NULL);
|
||||
timeLastPingSend=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
time_t now;
|
||||
|
||||
AQH_EventLoop_Run(eventLoop, 2000);
|
||||
AQH_MqttLogServer_HandleMqttMsgs(aqh);
|
||||
AQH_MqttLogServer_HandleBrokerMsgs(aqh);
|
||||
|
||||
now=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 (_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=AQH_MqttLogServer_SaveRuntimeDeviceFiles(aqh);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Error writing runtime data");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saPIPE, SIGPIPE);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _diffInSeconds(time_t t1, time_t t0)
|
||||
{
|
||||
return t1-t0;
|
||||
}
|
||||
|
||||
444
apps/aqhome-mqttlog/s_publish.c
Normal file
444
apps/aqhome-mqttlog/s_publish.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/****************************************************************************
|
||||
* 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_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/json_read.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
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(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);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AQH_MqttLogServer_HandlePublishMsg(AQH_OBJECT *o, GWEN_UNUSED AQH_OBJECT *ep, const AQH_MESSAGE *msg)
|
||||
{
|
||||
if (o && msg) {
|
||||
AQH_MQTTLOG_SERVER *xo;
|
||||
|
||||
xo=AQH_MqttLogServer_GetServerData(o);
|
||||
if (xo && xo->registeredDeviceList) {
|
||||
char *topic;
|
||||
char *value;
|
||||
|
||||
topic=AQH_MqttMessagePublish_ExtractTopic(msg);
|
||||
value=AQH_MqttMessagePublish_ExtractValue(msg);
|
||||
|
||||
if (topic && value) {
|
||||
int rv;
|
||||
|
||||
rv=_handlePublish(o, xo, topic, value);
|
||||
if (rv!=1) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _handlePublish(AQH_OBJECT *o, AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic, const char *rcvdValue)
|
||||
{
|
||||
if (o && rcvdTopic && *rcvdTopic && xo && xo->registeredDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
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);
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
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(xo, device, topic, rcvdValue);
|
||||
else
|
||||
_handleNumTopic(xo, device, topic, rcvdValue);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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(xo, device, AQHMQTT_Value_List_First(valueList), rcvdValue);
|
||||
else {
|
||||
DBG_INFO(NULL, "No value list in device \"%s\"", AQHMQTT_Device_GetId(device));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleJsonTopic(AQH_MQTTLOG_SERVER *xo, AQHMQTT_DEVICE *device,
|
||||
AQHMQTT_TOPIC *topic, const char *rcvdValue)
|
||||
{
|
||||
GWEN_JSON_ELEM *jeRoot;
|
||||
|
||||
jeRoot=GWEN_JsonElement_fromString(rcvdValue);
|
||||
if (jeRoot==NULL) {
|
||||
DBG_INFO(NULL, "Could not parse JSON value: %s", rcvdValue);
|
||||
}
|
||||
else {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList) {
|
||||
AQHMQTT_VALUE *value;
|
||||
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
const char *path;
|
||||
|
||||
path=AQHMQTT_Value_GetPath(value);
|
||||
if (path && *path) {
|
||||
GWEN_JSON_ELEM *je;
|
||||
|
||||
je=GWEN_JsonElement_GetElementByPath(jeRoot, path, 0);
|
||||
if (je) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_JsonElement_GetData(je);
|
||||
if (s && *s)
|
||||
_sendMessage(xo, device, value, s);
|
||||
}
|
||||
}
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
} /* while */
|
||||
}
|
||||
GWEN_JsonElement_free(jeRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value, const char *rcvdValue)
|
||||
{
|
||||
int rv;
|
||||
double f;
|
||||
const char *deviceName;
|
||||
|
||||
deviceName=AQHMQTT_Device_GetId(device);
|
||||
rv=GWEN_Text_StringToDouble(rcvdValue, &f);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Invalid value received from MQTT server (%s)", rcvdValue?rcvdValue:"<empty>");
|
||||
}
|
||||
else {
|
||||
uint64_t now;
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
now=(uint64_t) time(NULL);
|
||||
msgValue=_mkMessageValue(device, value);
|
||||
if (xo->brokerEndpoint) {
|
||||
AQH_MESSAGE *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), 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _announceDeviceToBroker(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device)
|
||||
{
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList) {
|
||||
const AQHMQTT_VALUE *value;
|
||||
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
_sendAnnounceValueMessage(xo, device, value);
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
}
|
||||
}
|
||||
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendAnnounceValueMessage(AQH_MQTTLOG_SERVER *xo, const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
|
||||
{
|
||||
AQH_MESSAGE *pubMsg;
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
msgValue=_mkMessageValue(device, value);
|
||||
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 *_mkMessageValue(const AQHMQTT_DEVICE *device, const AQHMQTT_VALUE *value)
|
||||
{
|
||||
AQH_VALUE *msgValue;
|
||||
|
||||
msgValue=AQH_Value_new();
|
||||
AQH_Value_SetDeviceName(msgValue, AQHMQTT_Device_GetId(device));
|
||||
AQH_Value_SetName(msgValue, AQHMQTT_Value_GetName(value));
|
||||
AQH_Value_SetValueUnits(msgValue, AQHMQTT_Value_GetValueUnits(value));
|
||||
AQH_Value_SetValueType(msgValue, _mqttValueTypeMessageValueType(AQHMQTT_Value_GetValueType(value)));
|
||||
return msgValue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _mqttValueTypeMessageValueType(int t)
|
||||
{
|
||||
switch(t){
|
||||
case AQHMQTT_ValueType_Sensor: return AQH_ValueType_Sensor;
|
||||
case AQHMQTT_ValueType_Actor: return AQH_ValueType_Actor;
|
||||
default: break;
|
||||
}
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Invalid mqtt value type %d", t);
|
||||
return AQH_ValueType_Sensor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _registerNewDeviceForTopic(AQH_MQTTLOG_SERVER *xo, const char *rcvdTopic)
|
||||
{
|
||||
if (rcvdTopic && *rcvdTopic) {
|
||||
if (xo->availableDeviceList) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=AQHMQTT_Device_List_First(xo->availableDeviceList);
|
||||
while(device) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=_findMaskMatchingTopic(topicList, rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
if (topic) {
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=_extractDeviceId(topic, rcvdTopic);
|
||||
if (buf) {
|
||||
AQHMQTT_DEVICE *newDevice;
|
||||
|
||||
newDevice=AQHMQTT_Device_dup(device);
|
||||
AQHMQTT_Device_SetId(newDevice, GWEN_Buffer_GetStart(buf));
|
||||
topic=_findMaskMatchingTopic(AQHMQTT_Device_GetTopicList(newDevice), rcvdTopic, AQHMQTT_TopicDir_In);
|
||||
AQHMQTT_Topic_SetTopic(topic, rcvdTopic);
|
||||
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, xo->registeredDeviceList);
|
||||
_announceDeviceToBroker(xo, newDevice);
|
||||
GWEN_Buffer_free(buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
}
|
||||
DBG_INFO(AQH_LOGDOMAIN, "ignoring topic \"%s\"", rcvdTopic);
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC *_findMaskMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir)
|
||||
{
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==dir) {
|
||||
const char *sMask;
|
||||
|
||||
sMask=AQHMQTT_Topic_GetMask(topic);
|
||||
if (sMask && *sMask && GWEN_Text_ComparePattern(rcvdTopic, sMask, 0)!=-1) {
|
||||
/* found a matching topic */
|
||||
return topic;
|
||||
}
|
||||
}
|
||||
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC *_findTopicMatchingTopic(AQHMQTT_TOPIC_LIST *topicList, const char *rcvdTopic, int dir)
|
||||
{
|
||||
if (topicList) {
|
||||
AQHMQTT_TOPIC *topic;
|
||||
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
if (AQHMQTT_Topic_GetDirection(topic)==dir) {
|
||||
const char *sTopic;
|
||||
|
||||
sTopic=AQHMQTT_Topic_GetTopic(topic);
|
||||
if (sTopic && *sTopic && strcasecmp(rcvdTopic, sTopic)==0) {
|
||||
return topic;
|
||||
}
|
||||
}
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GWEN_BUFFER *_extractDeviceId(const AQHMQTT_TOPIC *topic, const char *rcvdTopic)
|
||||
{
|
||||
const char *sBefore;
|
||||
const char *sAfter;
|
||||
|
||||
sBefore=AQHMQTT_Topic_GetBeforeId(topic);
|
||||
sAfter=AQHMQTT_Topic_GetAfterId(topic);
|
||||
|
||||
if (sBefore && *sBefore && sAfter && *sAfter) {
|
||||
GWEN_BUFFER *buf;
|
||||
int rv;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(buf, rcvdTopic);
|
||||
rv=GWEN_Buffer_KeepTextBetweenStrings(buf, sBefore, sAfter, 1);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "Could not extract id from [%s] (beforeId=%s, afterId=%s)", rcvdTopic, sBefore, sAfter);
|
||||
GWEN_Buffer_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
75
apps/aqhome-mqttlog/server.h
Normal file
75
apps/aqhome-mqttlog/server.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
* 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 SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
|
||||
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
#include "aqhome/events2/object.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 *AQH_MqttLogServer_new(AQH_EVENT_LOOP *eventLoop);
|
||||
int AQH_MqttLogServer_Init(AQH_OBJECT *o, int argc, char **argv);
|
||||
void AQH_MqttLogServer_Fini(AQH_OBJECT *o);
|
||||
|
||||
void AQH_MqttLogServer_ReloadDeviceFiles(AQH_OBJECT *o);
|
||||
void AQH_MqttLogServer_LoadRuntimeDeviceFiles(AQH_OBJECT *o);
|
||||
int AQH_MqttLogServer_SaveRuntimeDeviceFiles(AQH_OBJECT *o);
|
||||
|
||||
|
||||
/* loop functions */
|
||||
void AQH_MqttLogServer_HandleBrokerMsgs(AQH_OBJECT *o);
|
||||
void AQH_MqttLogServer_HandleMqttMsgs(AQH_OBJECT *o);
|
||||
void AQH_MqttLogServer_CheckBrokerConnection(AQH_OBJECT *o);
|
||||
void AQH_MqttLogServer_CheckMqttConnection(AQH_OBJECT *o);
|
||||
int AQH_MqttLogServer_SendPing(AQH_OBJECT *o);
|
||||
|
||||
|
||||
/* getters and setters */
|
||||
int AQH_MqttLogServer_GetTimeout(const AQH_OBJECT *o);
|
||||
void AQH_MqttLogServer_SetPidFile(AQH_OBJECT *o, const char *s);
|
||||
void AQH_MqttLogServer_SetDeviceFile(AQH_OBJECT *o, const char *s);
|
||||
|
||||
|
||||
/* device management */
|
||||
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_GetAvailableDeviceList(const AQH_OBJECT *o);
|
||||
void AQH_MqttLogServer_SetAvailableDeviceList(AQH_OBJECT *o, AQHMQTT_DEVICE_LIST *dl);
|
||||
void AQH_MqttLogServer_SetRegisteredDeviceList(AQH_OBJECT *o, AQHMQTT_DEVICE_LIST *dl);
|
||||
AQHMQTT_DEVICE *AQH_MqttLogServer_FindRegisteredDevice(AQH_OBJECT *o, const char *wantedDeviceId);
|
||||
void AQH_MqttLogServer_DumpRegisteredDevices(const AQH_OBJECT *o);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
67
apps/aqhome-mqttlog/server_p.h
Normal file
67
apps/aqhome-mqttlog/server_p.h
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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef SERVER_P_H
|
||||
#define SERVER_P_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
#include "aqhome/ipc2/msgrequest.h"
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
|
||||
/* default values */
|
||||
#define AQHOME_MQTT_DEFAULT_PIDFILE "/var/run/aqhome-mqtt.pid"
|
||||
#define AQHOME_MQTT_DEFAULT_DATADIR "/var/lib/aqhome-mqtt"
|
||||
#define AQHOME_MQTT_DEFAULT_DEVICEFILE "mqttlog/registereddevices.xml"
|
||||
|
||||
#define AQHOME_MQTT_DEFAULT_BROKER_PORT 1899
|
||||
#define AQHOME_MQTT_DEFAULT_BROKER_CLIENTID "mqtt"
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_MQTTLOG_SERVER AQH_MQTTLOG_SERVER;
|
||||
struct AQH_MQTTLOG_SERVER {
|
||||
AQH_OBJECT *mqttEndpoint;
|
||||
AQH_OBJECT *brokerEndpoint;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
AQHMQTT_DEVICE_LIST *availableDeviceList;
|
||||
AQHMQTT_DEVICE_LIST *registeredDeviceList;
|
||||
|
||||
char *deviceFile;
|
||||
char *pidFile;
|
||||
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
|
||||
char *mqttAddress;
|
||||
int mqttPort;
|
||||
char *mqttClientId;
|
||||
int mqttKeepAlive;
|
||||
|
||||
char *brokerAddress;
|
||||
int brokerPort;
|
||||
char *brokerClientId;
|
||||
|
||||
time_t timestampMqttDown;
|
||||
time_t timestampBrokerDown;
|
||||
|
||||
int timeoutInSeconds;
|
||||
|
||||
};
|
||||
|
||||
|
||||
AQH_MQTTLOG_SERVER *AQH_MqttLogServer_GetServerData(const AQH_OBJECT *o);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
81
apps/aqhome-mqttlog/types/0BUILD
Normal file
81
apps/aqhome-mqttlog/types/0BUILD
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhmqtt_types" >
|
||||
|
||||
<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" >
|
||||
device.t2d
|
||||
value.t2d
|
||||
topic.t2d
|
||||
translation.t2d
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
device.c
|
||||
value.c
|
||||
topic.c
|
||||
translation.c
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
device.h
|
||||
device_p.h
|
||||
value.h
|
||||
value_p.h
|
||||
topic.h
|
||||
topic_p.h
|
||||
translation.h
|
||||
translation_p.h
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
75
apps/aqhome-mqttlog/types/device.t2d
Normal file
75
apps/aqhome-mqttlog/types/device.t2d
Normal file
@@ -0,0 +1,75 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_DEVICE" type="pointer">
|
||||
<descr>
|
||||
This object and its objects are used to store registered devices and definitions for possible new devices.
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_DEVICE</identifier>
|
||||
<prefix>AQHMQTT_Device</prefix>
|
||||
<baseFileName>device</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-mqttlog/types/topic.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="id" type="char_ptr" maxlen="128">
|
||||
<descr>Only set for registered devices</descr>
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="driver" type="char_ptr" maxlen="64">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="topicList" type="AQHMQTT_TOPIC_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own noconst</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
114
apps/aqhome-mqttlog/types/topic.t2d
Normal file
114
apps/aqhome-mqttlog/types/topic.t2d
Normal file
@@ -0,0 +1,114 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_TOPIC" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_TOPIC</identifier>
|
||||
<prefix>AQHMQTT_Topic</prefix>
|
||||
<baseFileName>topic</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-mqttlog/types/value.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
|
||||
<enum id="AQHMQTT_TOPIC_TYPE" prefix="AQHMQTT_TopicType_">
|
||||
<item name="num" value="0">
|
||||
<descr>numeric type</descr>
|
||||
</item>
|
||||
<item name="json" >
|
||||
<descr>JSON type</descr>
|
||||
</item>
|
||||
</enum>
|
||||
|
||||
<enum id="AQHMQTT_TOPIC_DIR" prefix="AQHMQTT_TopicDir_">
|
||||
<item name="in" value="0"/>
|
||||
<item name="out" />
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="topic" type="char_ptr" maxlen="128">
|
||||
<descr>Only set for registered devices</descr>
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="topicType" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="direction" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="mask" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="beforeId" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="afterId" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="valueList" type="AQHMQTT_VALUE_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
55
apps/aqhome-mqttlog/types/translation.t2d
Normal file
55
apps/aqhome-mqttlog/types/translation.t2d
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_TRANSLATION" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_TRANSLATION</identifier>
|
||||
<prefix>AQHMQTT_Translation</prefix>
|
||||
<baseFileName>translation</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_db
|
||||
with_list1
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="aqhValue" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="driverValue" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
92
apps/aqhome-mqttlog/types/value.t2d
Normal file
92
apps/aqhome-mqttlog/types/value.t2d
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHMQTT_VALUE" type="pointer">
|
||||
<descr>
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHMQTT_VALUE</identifier>
|
||||
<prefix>AQHMQTT_Value</prefix>
|
||||
<baseFileName>value</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-mqttlog/types/translation.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
|
||||
<enum id="AQHMQTT_VALUE_TYPE" prefix="AQHMQTT_ValueType_">
|
||||
<item name="sensor" value="0">
|
||||
<descr>sensor</descr>
|
||||
</item>
|
||||
<item name="actor" >
|
||||
<descr>actor</descr>
|
||||
</item>
|
||||
|
||||
</enum>
|
||||
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="valueType" type="int" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="valueUnits" type="char_ptr" maxlen="32">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="path" type="char_ptr" maxlen="256">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="translationList" type="AQHMQTT_TRANSLATION_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
482
apps/aqhome-mqttlog/xmlread.c
Normal file
482
apps/aqhome-mqttlog/xmlread.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/****************************************************************************
|
||||
* 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 "./xmlread.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome-mqttlog/types/topic.h"
|
||||
#include "aqhome-mqttlog/types/value.h"
|
||||
#include "aqhome-mqttlog/types/translation.h"
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/xml.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQHMQTT_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl);
|
||||
static int _readDeviceFileToList(const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList);
|
||||
static int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList);
|
||||
static AQHMQTT_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode);
|
||||
static AQHMQTT_TOPIC_LIST *_readXmlTopicList(GWEN_XMLNODE *parentNode);
|
||||
static AQHMQTT_TOPIC *_readXmlTopic(GWEN_XMLNODE *topicNode);
|
||||
static AQHMQTT_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *parentNode);
|
||||
static AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode);
|
||||
static AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode);
|
||||
static AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDeviceFile(AQH_OBJECT *o, const char *sFilename)
|
||||
{
|
||||
if (o) {
|
||||
AQH_MQTTLOG_SERVER *xo;
|
||||
|
||||
xo=AQH_MqttLogServer_GetServerData(o);
|
||||
if (xo) {
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHMQTT_Device_List_new();
|
||||
rv=_readDeviceFileToList(sFilename, deviceList);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Could not read file \"%s\" (empty?)", sFilename);
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDataDeviceFiles(AQH_OBJECT *o)
|
||||
{
|
||||
if (o) {
|
||||
AQH_MQTTLOG_SERVER *xo;
|
||||
|
||||
xo=AQH_MqttLogServer_GetServerData(o);
|
||||
if (xo) {
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/mqtt", "*.xml");
|
||||
if (sl) {
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=_readDeviceFiles(sl);
|
||||
GWEN_StringList_free(sl);
|
||||
if (deviceList==NULL) {
|
||||
DBG_INFO(NULL, "Error reading data device files");
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No data device files");
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl)
|
||||
{
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
AQHMQTT_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHMQTT_Device_List_new();
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
while(se) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Reading device file \"%s\"", s);
|
||||
rv=_readDeviceFileToList(s, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
|
||||
}
|
||||
}
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
}
|
||||
|
||||
if (AQHMQTT_Device_List_GetCount(deviceList)<1) {
|
||||
AQHMQTT_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceFileToList(const char *sFilename, AQHMQTT_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_XMLNODE *deviceListNode;
|
||||
int rv;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
||||
rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL);
|
||||
if (deviceListNode==NULL)
|
||||
deviceListNode=rootNode;
|
||||
|
||||
rv=_readXmlDevices(deviceListNode, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHMQTT_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *deviceNode;
|
||||
|
||||
deviceNode=GWEN_XMLNode_FindFirstTag(deviceListNode, "device", NULL, NULL);
|
||||
if (deviceNode) {
|
||||
while(deviceNode) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL);
|
||||
if (driverName && *driverName && strcasecmp(driverName, "mqtt")==0) {
|
||||
AQHMQTT_DEVICE *device;
|
||||
|
||||
device=_readXmlDevice(deviceNode);
|
||||
if (device==NULL) {
|
||||
DBG_INFO(NULL, "Error reading device from XML");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
else {
|
||||
const char *sDeviceId;
|
||||
const char *sDeviceName;
|
||||
|
||||
sDeviceId=AQHMQTT_Device_GetId(device);
|
||||
sDeviceName=AQHMQTT_Device_GetName(device);
|
||||
if (sDeviceId && *sDeviceId) {
|
||||
DBG_ERROR(NULL, "Adding device \"%s\" (%s) to list", sDeviceId, sDeviceName?sDeviceName:"<no type name>");
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Adding device type \"%s\" to list", sDeviceName?sDeviceName:"<no type name>");
|
||||
}
|
||||
AQHMQTT_Device_List_Add(device, deviceList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device is not an MQTT device, ignoring");
|
||||
}
|
||||
deviceNode=GWEN_XMLNode_FindNextTag(deviceNode, "device", NULL, NULL);
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <device> element found");
|
||||
return GWEN_ERROR_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
AQHMQTT_DEVICE *device;
|
||||
GWEN_XMLNODE *topicsNode;
|
||||
|
||||
device=AQHMQTT_Device_new();
|
||||
AQHMQTT_Device_SetId(device, GWEN_XMLNode_GetProperty(deviceNode, "id", NULL));
|
||||
AQHMQTT_Device_SetName(device, GWEN_XMLNode_GetProperty(deviceNode, "name", NULL));
|
||||
AQHMQTT_Device_SetDriver(device, GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL));
|
||||
|
||||
topicsNode=GWEN_XMLNode_FindFirstTag(deviceNode, "mqtttopics", NULL, NULL);
|
||||
if (topicsNode) {
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
topicList=_readXmlTopicList(topicsNode);
|
||||
if (topicList)
|
||||
AQHMQTT_Device_SetTopicList(device, topicList);
|
||||
else {
|
||||
DBG_INFO(NULL, "No mqtt topics read");
|
||||
AQHMQTT_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <mqtttopics> element");
|
||||
AQHMQTT_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC_LIST *_readXmlTopicList(GWEN_XMLNODE *parentNode)
|
||||
{
|
||||
AQHMQTT_TOPIC_LIST *topicList;
|
||||
GWEN_XMLNODE *topicNode;
|
||||
|
||||
topicList=AQHMQTT_Topic_List_new();
|
||||
topicNode=GWEN_XMLNode_FindFirstTag(parentNode, "mqtttopic", NULL, NULL);
|
||||
while(topicNode) {
|
||||
AQHMQTT_TOPIC *topic=_readXmlTopic(topicNode);
|
||||
if (topic)
|
||||
AQHMQTT_Topic_List_Add(topic, topicList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <mqtttopic> element");
|
||||
AQHMQTT_Topic_List_free(topicList);
|
||||
return NULL;
|
||||
}
|
||||
topicNode=GWEN_XMLNode_FindNextTag(topicNode, "mqtttopic", NULL, NULL);
|
||||
}
|
||||
if (AQHMQTT_Topic_List_GetCount(topicList)<1) {
|
||||
AQHMQTT_Topic_List_free(topicList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return topicList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TOPIC *_readXmlTopic(GWEN_XMLNODE *topicNode)
|
||||
{
|
||||
AQHMQTT_TOPIC *topic;
|
||||
GWEN_XMLNODE *valuesNode;
|
||||
int i;
|
||||
const char *s;
|
||||
|
||||
topic=AQHMQTT_Topic_new();
|
||||
s=GWEN_XMLNode_GetProperty(topicNode, "type", NULL);
|
||||
i=AQHMQTT_TopicType_fromString(s);
|
||||
if (i==AQHMQTT_TopicType_Unknown) {
|
||||
DBG_ERROR(NULL, "Invalid topic type \"%s\"", s?s:"<empty>");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
AQHMQTT_Topic_SetTopicType(topic, i);
|
||||
|
||||
s=GWEN_XMLNode_GetProperty(topicNode, "direction", NULL);
|
||||
i=AQHMQTT_TopicDir_fromString(s);
|
||||
if (i==AQHMQTT_TopicDir_Unknown) {
|
||||
DBG_ERROR(NULL, "Invalid topic direction \"%s\"", s?s:"<empty>");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
AQHMQTT_Topic_SetDirection(topic, i);
|
||||
|
||||
AQHMQTT_Topic_SetName(topic, GWEN_XMLNode_GetProperty(topicNode, "name", NULL));
|
||||
AQHMQTT_Topic_SetTopic(topic, GWEN_XMLNode_GetCharValue(topicNode, "topic", NULL));
|
||||
AQHMQTT_Topic_SetMask(topic, GWEN_XMLNode_GetCharValue(topicNode, "mask", NULL));
|
||||
AQHMQTT_Topic_SetBeforeId(topic, GWEN_XMLNode_GetCharValue(topicNode, "beforeId", NULL));
|
||||
AQHMQTT_Topic_SetAfterId(topic, GWEN_XMLNode_GetCharValue(topicNode, "afterId", NULL));
|
||||
|
||||
valuesNode=GWEN_XMLNode_FindFirstTag(topicNode, "values", NULL, NULL);
|
||||
if (valuesNode) {
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
valueList=_readXmlValueList(valuesNode);
|
||||
if (valueList)
|
||||
AQHMQTT_Topic_SetValueList(topic, valueList);
|
||||
else {
|
||||
DBG_INFO(NULL, "No values read");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <values> element");
|
||||
AQHMQTT_Topic_free(topic);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return topic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *parentNode)
|
||||
{
|
||||
AQHMQTT_VALUE_LIST *valueList;
|
||||
GWEN_XMLNODE *valueNode;
|
||||
|
||||
valueList=AQHMQTT_Value_List_new();
|
||||
valueNode=GWEN_XMLNode_FindFirstTag(parentNode, "value", NULL, NULL);
|
||||
while(valueNode) {
|
||||
AQHMQTT_VALUE *value=_readXmlValue(valueNode);
|
||||
if (value)
|
||||
AQHMQTT_Value_List_Add(value, valueList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <value> element");
|
||||
AQHMQTT_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
valueNode=GWEN_XMLNode_FindNextTag(valueNode, "value", NULL, NULL);
|
||||
}
|
||||
if (AQHMQTT_Value_List_GetCount(valueList)<1) {
|
||||
AQHMQTT_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return valueList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode)
|
||||
{
|
||||
AQHMQTT_VALUE *value;
|
||||
GWEN_XMLNODE *translationNode;
|
||||
const char *s;
|
||||
int i;
|
||||
|
||||
value=AQHMQTT_Value_new();
|
||||
AQHMQTT_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL));
|
||||
AQHMQTT_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL));
|
||||
AQHMQTT_Value_SetPath(value, GWEN_XMLNode_GetProperty(valueNode, "path", NULL));
|
||||
|
||||
s=GWEN_XMLNode_GetProperty(valueNode, "type", NULL);
|
||||
i=AQHMQTT_ValueType_fromString(s);
|
||||
if (i==AQHMQTT_ValueType_Unknown) {
|
||||
DBG_ERROR(NULL, "Invalid value type \"%s\"", s?s:"<empty>");
|
||||
AQHMQTT_Value_free(value);
|
||||
return NULL;
|
||||
}
|
||||
AQHMQTT_Value_SetValueType(value, i);
|
||||
|
||||
translationNode=GWEN_XMLNode_FindFirstTag(valueNode, "translations", NULL, NULL);
|
||||
if (translationNode) {
|
||||
AQHMQTT_TRANSLATION_LIST *translationList;
|
||||
|
||||
translationList=_readXmlTranslationList(translationNode);
|
||||
if (translationList) {
|
||||
DBG_INFO(NULL, "Translations read");
|
||||
AQHMQTT_Value_SetTranslationList(value, translationList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <translations> element");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TRANSLATION_LIST *_readXmlTranslationList(GWEN_XMLNODE *parentNode)
|
||||
{
|
||||
AQHMQTT_TRANSLATION_LIST *translationList;
|
||||
GWEN_XMLNODE *translationNode;
|
||||
|
||||
translationList=AQHMQTT_Translation_List_new();
|
||||
translationNode=GWEN_XMLNode_FindFirstTag(parentNode, "translation", NULL, NULL);
|
||||
while(translationNode) {
|
||||
AQHMQTT_TRANSLATION *translation=_readXmlTranslation(translationNode);
|
||||
if (translation)
|
||||
AQHMQTT_Translation_List_Add(translation, translationList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <translation> element");
|
||||
AQHMQTT_Translation_List_free(translationList);
|
||||
return NULL;
|
||||
}
|
||||
translationNode=GWEN_XMLNode_FindNextTag(translationNode, "translation", NULL, NULL);
|
||||
}
|
||||
if (AQHMQTT_Translation_List_GetCount(translationList)<1) {
|
||||
AQHMQTT_Translation_List_free(translationList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return translationList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHMQTT_TRANSLATION *_readXmlTranslation(GWEN_XMLNODE *translationNode)
|
||||
{
|
||||
const char *sAqhValue;
|
||||
const char *sDriverValue;
|
||||
|
||||
sAqhValue=GWEN_XMLNode_GetProperty(translationNode, "aqhValue", NULL);
|
||||
sDriverValue=GWEN_XMLNode_GetProperty(translationNode, "driverValue", NULL);
|
||||
if (sAqhValue && *sAqhValue && sDriverValue && *sDriverValue) {
|
||||
AQHMQTT_TRANSLATION *translation;
|
||||
|
||||
translation=AQHMQTT_Translation_new();
|
||||
AQHMQTT_Translation_SetAqhValue(translation, sAqhValue);
|
||||
AQHMQTT_Translation_SetDriverValue(translation, sDriverValue);
|
||||
return translation;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Either AqhValue or DriverValue missing in device description file");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-mqttlog/xmlread.h
Normal file
25
apps/aqhome-mqttlog/xmlread.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 AQHOME_MQTTLOG_XMLREAD_H
|
||||
#define AQHOME_MQTTLOG_XMLREAD_H
|
||||
|
||||
#include "aqhome-mqttlog/server.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
|
||||
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDataDeviceFiles(AQH_OBJECT *o);
|
||||
AQHMQTT_DEVICE_LIST *AQH_MqttLogServer_ReadDeviceFile(AQH_OBJECT *o, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
248
apps/aqhome-mqttlog/xmlwrite.c
Normal file
248
apps/aqhome-mqttlog/xmlwrite.c
Normal file
@@ -0,0 +1,248 @@
|
||||
/****************************************************************************
|
||||
* 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 "./xmlwrite.h"
|
||||
#include "aqhome-mqttlog/types/topic.h"
|
||||
#include "aqhome-mqttlog/types/value.h"
|
||||
#include "aqhome-mqttlog/types/translation.h"
|
||||
|
||||
#include <aqhome/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include <gwenhywfar/endpoint_multilayer.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
#include <gwenhywfar/xml.h>
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _writeDevicesToXml(const AQHMQTT_DEVICE_LIST *deviceList, GWEN_XMLNODE *node);
|
||||
static void _writeDeviceToXml(const AQHMQTT_DEVICE *device, GWEN_XMLNODE *node);
|
||||
static void _writeTopicToXml(const AQHMQTT_TOPIC *topic, GWEN_XMLNODE *node);
|
||||
static void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node);
|
||||
static void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation);
|
||||
static void _setXmlPropertyIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value);
|
||||
static void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
int AQH_MqttLogServer_WriteDevicesFile(const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Could not access file \"%s\"", sFilename);
|
||||
return GWEN_ERROR_GENERIC;
|
||||
}
|
||||
else {
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_BUFFER *nbuf;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "root");
|
||||
_writeDevicesToXml(deviceList, rootNode);
|
||||
|
||||
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
GWEN_Buffer_AppendString(nbuf, sFilename);
|
||||
GWEN_Buffer_AppendString(nbuf, ".tmp");
|
||||
unlink(GWEN_Buffer_GetStart(nbuf));
|
||||
rv=GWEN_XMLNode_WriteFile(rootNode,
|
||||
GWEN_Buffer_GetStart(nbuf),
|
||||
GWEN_XML_FLAGS_SIMPLE | GWEN_XML_FLAGS_HANDLE_HEADERS | GWEN_XML_FLAGS_INDENT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error writing XML file \"%s\": %d", GWEN_Buffer_GetStart(nbuf), rv);
|
||||
GWEN_Buffer_free(nbuf);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
if (rename(GWEN_Buffer_GetStart(nbuf), sFilename)<0) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error renaming \"%s\"->\"%s\": %d (%s)",
|
||||
GWEN_Buffer_GetStart(nbuf), sFilename, errno, strerror(errno));
|
||||
GWEN_Buffer_free(nbuf);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
GWEN_Buffer_free(nbuf);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeDevicesToXml(const AQHMQTT_DEVICE_LIST *deviceList, GWEN_XMLNODE *node)
|
||||
{
|
||||
if (deviceList && AQHMQTT_Device_List_GetCount(deviceList)) {
|
||||
GWEN_XMLNODE *nDevices;
|
||||
const AQHMQTT_DEVICE *device;
|
||||
|
||||
nDevices=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "devices");
|
||||
device=AQHMQTT_Device_List_First(deviceList);
|
||||
while(device) {
|
||||
GWEN_XMLNODE *nDevice;
|
||||
|
||||
nDevice=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "device");
|
||||
_writeDeviceToXml(device, nDevice);
|
||||
GWEN_XMLNode_AddChild(nDevices, nDevice);
|
||||
|
||||
device=AQHMQTT_Device_List_Next(device);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nDevices);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _writeDeviceToXml(const AQHMQTT_DEVICE *device, GWEN_XMLNODE *node)
|
||||
{
|
||||
const AQHMQTT_TOPIC_LIST *topicList;
|
||||
|
||||
_setXmlPropertyIfNotNull(node, "id", AQHMQTT_Device_GetId(device));
|
||||
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Device_GetName(device));
|
||||
_setXmlPropertyIfNotNull(node, "driver", AQHMQTT_Device_GetDriver(device));
|
||||
|
||||
topicList=AQHMQTT_Device_GetTopicList(device);
|
||||
if (topicList && AQHMQTT_Topic_List_GetCount(topicList)) {
|
||||
GWEN_XMLNODE *nTopics;
|
||||
const AQHMQTT_TOPIC *topic;
|
||||
|
||||
nTopics=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "mqtttopics");
|
||||
topic=AQHMQTT_Topic_List_First(topicList);
|
||||
while(topic) {
|
||||
GWEN_XMLNODE *nTopic;
|
||||
|
||||
nTopic=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "mqtttopic");
|
||||
_writeTopicToXml(topic, nTopic);
|
||||
GWEN_XMLNode_AddChild(nTopics, nTopic);
|
||||
|
||||
topic=AQHMQTT_Topic_List_Next(topic);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nTopics);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void _writeTopicToXml(const AQHMQTT_TOPIC *topic, GWEN_XMLNODE *node)
|
||||
{
|
||||
const AQHMQTT_VALUE_LIST *valueList;
|
||||
|
||||
GWEN_XMLNode_SetProperty(node, "type", AQHMQTT_TopicType_toString(AQHMQTT_Topic_GetTopicType(topic)));
|
||||
GWEN_XMLNode_SetProperty(node, "direction", AQHMQTT_TopicDir_toString(AQHMQTT_Topic_GetDirection(topic)));
|
||||
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Topic_GetName(topic));
|
||||
_setXmlCharValueIfNotNull(node, "topic", AQHMQTT_Topic_GetTopic(topic));
|
||||
_setXmlCharValueIfNotNull(node, "mask", AQHMQTT_Topic_GetMask(topic));
|
||||
_setXmlCharValueIfNotNull(node, "beforeId", AQHMQTT_Topic_GetBeforeId(topic));
|
||||
_setXmlCharValueIfNotNull(node, "afterId", AQHMQTT_Topic_GetAfterId(topic));
|
||||
|
||||
valueList=AQHMQTT_Topic_GetValueList(topic);
|
||||
if (valueList && AQHMQTT_Value_List_GetCount(valueList)) {
|
||||
GWEN_XMLNODE *nValues;
|
||||
const AQHMQTT_VALUE *value;
|
||||
|
||||
nValues=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "values");
|
||||
value=AQHMQTT_Value_List_First(valueList);
|
||||
while(value) {
|
||||
GWEN_XMLNODE *nValue;
|
||||
|
||||
nValue=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "value");
|
||||
_writeValueToXml(value, nValue);
|
||||
GWEN_XMLNode_AddChild(nValues, nValue);
|
||||
|
||||
value=AQHMQTT_Value_List_Next(value);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void _writeValueToXml(const AQHMQTT_VALUE *value, GWEN_XMLNODE *node)
|
||||
{
|
||||
const AQHMQTT_TRANSLATION_LIST *translationList;
|
||||
|
||||
_setXmlPropertyIfNotNull(node, "name", AQHMQTT_Value_GetName(value));
|
||||
_setXmlPropertyIfNotNull(node, "units", AQHMQTT_Value_GetValueUnits(value));
|
||||
_setXmlPropertyIfNotNull(node, "path", AQHMQTT_Value_GetPath(value));
|
||||
GWEN_XMLNode_SetProperty(node, "type", AQHMQTT_ValueType_toString(AQHMQTT_Value_GetValueType(value)));
|
||||
|
||||
translationList=AQHMQTT_Value_GetTranslationList(value);
|
||||
if (translationList && AQHMQTT_Translation_List_GetCount(translationList)) {
|
||||
GWEN_XMLNODE *nTranslations;
|
||||
const AQHMQTT_TRANSLATION *translation;
|
||||
|
||||
nTranslations=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "translations");
|
||||
translation=AQHMQTT_Translation_List_First(translationList);
|
||||
while(translation) {
|
||||
GWEN_XMLNODE *nTranslation;
|
||||
|
||||
nTranslation=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "transaction");
|
||||
_writeTranslationToXml(translation, nTranslation);
|
||||
GWEN_XMLNode_AddChild(nTranslations, nTranslation);
|
||||
|
||||
translation=AQHMQTT_Translation_List_Next(translation);
|
||||
}
|
||||
|
||||
GWEN_XMLNode_AddChild(node, nTranslations);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeTranslationToXml(const AQHMQTT_TRANSLATION *t, GWEN_XMLNODE *nTranslation)
|
||||
{
|
||||
_setXmlPropertyIfNotNull(nTranslation, "aqhValue", AQHMQTT_Translation_GetAqhValue(t));
|
||||
_setXmlPropertyIfNotNull(nTranslation, "driverValue", AQHMQTT_Translation_GetDriverValue(t));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setXmlPropertyIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value)
|
||||
{
|
||||
if (value && *value)
|
||||
GWEN_XMLNode_SetProperty(n, name, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setXmlCharValueIfNotNull(GWEN_XMLNODE *n, const char *name, const char *value)
|
||||
{
|
||||
if (value && *value)
|
||||
GWEN_XMLNode_SetCharValue(n, name, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
apps/aqhome-mqttlog/xmlwrite.h
Normal file
23
apps/aqhome-mqttlog/xmlwrite.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/****************************************************************************
|
||||
* 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_MQTTLOG_XMLWRITE_H
|
||||
#define AQHOME_MQTTLOG_XMLWRITE_H
|
||||
|
||||
#include "aqhome-mqttlog/server.h"
|
||||
#include "aqhome-mqttlog/types/device.h"
|
||||
|
||||
|
||||
|
||||
int AQH_MqttLogServer_WriteDevicesFile(const AQHMQTT_DEVICE_LIST *deviceList, const char *sFilename);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
86
apps/aqhome-nodes/0BUILD
Normal file
86
apps/aqhome-nodes/0BUILD
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="Program" name="aqhome-nodes" install="$(sbindir)" >
|
||||
|
||||
<includes type="c" >
|
||||
$(gwenhywfar_cflags)
|
||||
-I$(topsrcdir)
|
||||
-I$(topbuilddir)
|
||||
-I$(topsrcdir)/apps
|
||||
-I$(topbuilddir)/apps
|
||||
</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" >
|
||||
db.h
|
||||
tty_log.h
|
||||
devicesread.h
|
||||
devicesdump.h
|
||||
r_setdata.h
|
||||
r_connect.h
|
||||
r_forward.h
|
||||
r_setaccmsggrps.h
|
||||
r_getnodes.h
|
||||
server.h
|
||||
server_p.h
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
server.c
|
||||
db.c
|
||||
devicesread.c
|
||||
devicesdump.c
|
||||
r_setdata.c
|
||||
r_connect.c
|
||||
r_forward.c
|
||||
r_setaccmsggrps.c
|
||||
r_getnodes.c
|
||||
main.c
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
aqhnodes_types
|
||||
aqhome
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
$(gwenhywfar_libs)
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
types
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
414
apps/aqhome-nodes/db.c
Normal file
414
apps/aqhome-nodes/db.c
Normal file
@@ -0,0 +1,414 @@
|
||||
/****************************************************************************
|
||||
* 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 "./db.h"
|
||||
#include "./server_p.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/msg/node/m_node.h"
|
||||
#include "aqhome/msg/node/m_sendstats.h"
|
||||
#include "aqhome/msg/node/m_recvstats.h"
|
||||
#include "aqhome/msg/node/m_value.h"
|
||||
#include "aqhome/msg/node/m_addr.h"
|
||||
#include "aqhome/msg/node/m_device.h"
|
||||
#include "aqhome/msg/node/m_flashready.h"
|
||||
|
||||
#include "aqhome/data/value.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd.h"
|
||||
#include "aqhome/msg/ipc/data/m_ipcd_values.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/args.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/timestamp.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _handleMsgValue(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _handleAddressMsg(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _handleMsgComSendStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _handleMsgComRecvStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _handleMsgDevice(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
static void _handleMsgFlashReady(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg);
|
||||
|
||||
static AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg, uint32_t uid);
|
||||
static void _updateTimestampLastChange(AQH_NODE_INFO *ni);
|
||||
static void _assignDeviceId(AQH_OBJECT *o, AQH_NODE_INFO *ni, uint32_t uid);
|
||||
|
||||
static void _announceNodeValues(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_NODE_INFO *ni);
|
||||
static void _setDeviceName(AQH_VALUE *value, uint32_t uid);
|
||||
static void _announceValue(AQH_NODE_SERVER *xo, uint32_t uid, const AQHNODE_VALUE *v);
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AQH_NodeServer_NodeMsgToDb(AQH_OBJECT *o, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo) {
|
||||
uint8_t msgType;
|
||||
|
||||
msgType=AQH_NodeMessage_GetMsgType(msg);
|
||||
|
||||
switch(msgType) {
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: _handleMsgComSendStat(xo, msg); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: _handleMsgComRecvStat(xo, msg); break;
|
||||
case AQH_MSG_TYPE_VALUE_REPORT: _handleMsgValue(xo, msg); break;
|
||||
case AQH_MSG_TYPE_NEED_ADDRESS: _handleAddressMsg(xo, msg); break;
|
||||
case AQH_MSG_TYPE_CLAIM_ADDRESS: _handleAddressMsg(xo, msg); break;
|
||||
case AQH_MSG_TYPE_HAVE_ADDRESS: _handleAddressMsg(xo, msg); break;
|
||||
case AQH_MSG_TYPE_DEVICE: _handleMsgDevice(o, xo, msg); break;
|
||||
case AQH_MSG_TYPE_FLASH_READY: _handleMsgFlashReady(o, xo, msg); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AQH_NodeServer_WriteNodeDb(AQH_OBJECT *o)
|
||||
{
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo && xo->dbFile) {
|
||||
GWEN_DB_NODE *dbNodeDb;
|
||||
|
||||
AQH_NodeDb_ClearModified(xo->nodeDb);
|
||||
dbNodeDb=GWEN_DB_Group_new("nodeDb");
|
||||
AQH_NodeDb_toDb(xo->nodeDb, dbNodeDb);
|
||||
GWEN_DB_WriteFile(dbNodeDb, xo->dbFile, GWEN_DB_FLAGS_DEFAULT);
|
||||
GWEN_DB_Group_free(dbNodeDb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgValue(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_ValueMessage_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
else {
|
||||
uint8_t valueId;
|
||||
uint16_t val;
|
||||
|
||||
val=AQH_ValueMessage_GetValueNom(msg);
|
||||
valueId=AQH_ValueMessage_GetValueId(msg);
|
||||
|
||||
switch(valueId) {
|
||||
case AQH_ENDPOINT_VID_STATS_PACKETS_IN: AQH_NodeInfo_SetStatsPacketsIn(ni, val); AQH_NodeDb_SetModified(xo->nodeDb); break;
|
||||
case AQH_ENDPOINT_VID_STATS_PACKETS_OUT: AQH_NodeInfo_SetStatsPacketsOut(ni, val); AQH_NodeDb_SetModified(xo->nodeDb); break;
|
||||
case AQH_ENDPOINT_VID_STATS_ERRS_CONTENT: AQH_NodeInfo_SetStatsCrcErrors(ni, val); AQH_NodeDb_SetModified(xo->nodeDb); break;
|
||||
case AQH_ENDPOINT_VID_STATS_ERRS_IO: AQH_NodeInfo_SetStatsIoErrors(ni, val); AQH_NodeDb_SetModified(xo->nodeDb); break;
|
||||
case AQH_ENDPOINT_VID_STATS_ERRS_NOBUF: break;
|
||||
case AQH_ENDPOINT_VID_STATS_ERRS_COLLISIONS: AQH_NodeInfo_SetStatsCollisions(ni, val); AQH_NodeDb_SetModified(xo->nodeDb); break;
|
||||
case AQH_ENDPOINT_VID_STATS_ERRS_BUSY: AQH_NodeInfo_SetStatsBusy(ni, val); AQH_NodeDb_SetModified(xo->nodeDb); break;
|
||||
case AQH_ENDPOINT_VID_STATS_HEAP_USED: break;
|
||||
case AQH_ENDPOINT_VID_STATS_HEAP_FREE: break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleAddressMsg(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_AddrMessage_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgComSendStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_SendStatsMessage_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
else {
|
||||
AQH_NodeInfo_SetStatsPacketsOut(ni, AQH_SendStatsMessage_GetPacketsOut(msg));
|
||||
AQH_NodeInfo_SetStatsCollisions(ni, AQH_SendStatsMessage_GetCollisions(msg));
|
||||
AQH_NodeInfo_SetStatsBusy(ni, AQH_SendStatsMessage_GetBusyErrors(msg));
|
||||
AQH_NodeDb_SetModified(xo->nodeDb);
|
||||
_updateTimestampLastChange(ni);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgComRecvStat(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_RecvStatsMessage_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
AQH_NodeInfo_SetStatsPacketsIn(ni, AQH_RecvStatsMessage_GetPacketsIn(msg));
|
||||
AQH_NodeInfo_SetStatsCrcErrors(ni, AQH_RecvStatsMessage_GetCrcErrors(msg));
|
||||
AQH_NodeInfo_SetStatsIoErrors(ni, AQH_RecvStatsMessage_GetIoErrors(msg));
|
||||
AQH_NodeDb_SetModified(xo->nodeDb);
|
||||
_updateTimestampLastChange(ni);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgDevice(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_DeviceMessage_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
|
||||
if (ni) {
|
||||
const char *s;
|
||||
|
||||
AQH_NodeInfo_SetManufacturer(ni, AQH_DeviceMessage_GetManufacturer(msg));
|
||||
AQH_NodeInfo_SetDeviceType(ni, AQH_DeviceMessage_GetDeviceType(msg));
|
||||
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_DeviceMessage_GetDeviceVersion(msg)<<8)+AQH_DeviceMessage_GetDeviceRevision(msg));
|
||||
AQH_NodeInfo_SetFirmwareVersion(ni,
|
||||
(AQH_DeviceMessage_GetFirmwareVariant(msg)<<24) |
|
||||
(AQH_DeviceMessage_GetFirmwareVersionMajor(msg)<<16) |
|
||||
(AQH_DeviceMessage_GetFirmwareVersionMinor(msg)<<8) |
|
||||
AQH_DeviceMessage_GetFirmwareVersionPatchlevel(msg));
|
||||
s=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (!(s && *s))
|
||||
_assignDeviceId(o, ni, uid);
|
||||
_updateTimestampLastChange(ni);
|
||||
AQH_NodeDb_SetModified(xo->nodeDb);
|
||||
if (uid!=0x00000000L && uid!=0xffffffff)
|
||||
_announceNodeValues(o, xo, ni);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _announceNodeValues(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_NODE_INFO *ni)
|
||||
{
|
||||
const char *devName;
|
||||
|
||||
devName=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (devName) {
|
||||
const AQHNODE_DEVICE *devInfo;
|
||||
|
||||
devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName);
|
||||
if (devInfo) {
|
||||
const AQHNODE_VALUE_LIST *valueList;
|
||||
|
||||
valueList=AQHNODE_Device_GetValueList(devInfo);
|
||||
if (valueList) {
|
||||
const AQHNODE_VALUE *v;
|
||||
|
||||
v=AQHNODE_Value_List_First(valueList);
|
||||
while(v) {
|
||||
DBG_INFO(NULL, "Announcing value \"%08x/%s\" (%d=%s)",
|
||||
AQH_NodeInfo_GetUid(ni), AQHNODE_Value_GetName(v),
|
||||
AQHNODE_Value_GetModality(v),
|
||||
AQH_ValueModality_toString(AQHNODE_Value_GetModality(v)));
|
||||
_announceValue(xo, AQH_NodeInfo_GetUid(ni), v);
|
||||
v=AQHNODE_Value_List_Next(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Node type \"%s\" not in database", devName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Node type not in database");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _setDeviceName(AQH_VALUE *value, uint32_t uid)
|
||||
{
|
||||
GWEN_BUFFER *buf;
|
||||
|
||||
buf=GWEN_Buffer_new(0, 64, 0, 1);
|
||||
GWEN_Buffer_AppendArgs(buf, "%08x", uid);
|
||||
AQH_Value_SetDeviceName(value, GWEN_Buffer_GetStart(buf));
|
||||
GWEN_Buffer_free(buf);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _announceValue(AQH_NODE_SERVER *xo, uint32_t uid, const AQHNODE_VALUE *v)
|
||||
{
|
||||
if (xo && xo->brokerEndpoint) {
|
||||
AQH_VALUE *value;
|
||||
AQH_MESSAGE *msg;
|
||||
|
||||
value=AQH_Value_new();
|
||||
_setDeviceName(value, uid);
|
||||
AQH_Value_SetDriver(value, "nodes");
|
||||
AQH_Value_SetName(value, AQHNODE_Value_GetName(v));
|
||||
AQH_Value_SetValueUnits(value, AQHNODE_Value_GetValueUnits(v));
|
||||
AQH_Value_SetValueType(value, AQHNODE_Value_GetValueType(v));
|
||||
AQH_Value_SetModality(value, AQHNODE_Value_GetModality(v));
|
||||
|
||||
msg=AQH_IpcdMessageValues_newForOne(AQH_MSGTYPE_IPC_DATA_ANNOUNCEVALUE,
|
||||
AQH_Endpoint_GetNextMessageId(xo->brokerEndpoint), 0,
|
||||
0, value);
|
||||
AQH_Endpoint_AddMsgOut(xo->brokerEndpoint, msg);
|
||||
AQH_Value_free(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _handleMsgFlashReady(AQH_OBJECT *o, AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_INFO *ni;
|
||||
uint32_t uid;
|
||||
|
||||
uid=AQH_FlashReadyMessage_GetUid(msg);
|
||||
ni=_getOrCreateNodeAndUpdateUidAddr(xo, msg, uid);
|
||||
if (ni) {
|
||||
const char *s;
|
||||
|
||||
AQH_NodeInfo_SetManufacturer(ni, AQH_FlashReadyMessage_GetManufacturer(msg));
|
||||
AQH_NodeInfo_SetDeviceType(ni, AQH_FlashReadyMessage_GetDeviceType(msg));
|
||||
AQH_NodeInfo_SetDeviceVersion(ni, (AQH_FlashReadyMessage_GetDeviceVersion(msg)<<8)+AQH_FlashReadyMessage_GetDeviceRevision(msg));
|
||||
AQH_NodeInfo_SetFirmwareVersion(ni,
|
||||
(AQH_FlashReadyMessage_GetFirmwareVariant(msg)<<24) |
|
||||
(AQH_FlashReadyMessage_GetFirmwareVersionMajor(msg)<<16) |
|
||||
(AQH_FlashReadyMessage_GetFirmwareVersionMinor(msg)<<8) |
|
||||
AQH_FlashReadyMessage_GetFirmwareVersionPatchlevel(msg));
|
||||
s=AQH_NodeInfo_GetDeviceId(ni);
|
||||
if (!(s && *s))
|
||||
_assignDeviceId(o, ni, uid);
|
||||
_updateTimestampLastChange(ni);
|
||||
AQH_NodeDb_SetModified(xo->nodeDb);
|
||||
if (uid!=0x00000000L && uid!=0xffffffff)
|
||||
_announceNodeValues(o, xo, ni);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Error handling message");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_NODE_INFO *_getOrCreateNodeAndUpdateUidAddr(AQH_NODE_SERVER *xo, const AQH_MESSAGE *msg, uint32_t uid)
|
||||
{
|
||||
uint8_t busAddr;
|
||||
AQH_NODE_INFO *ni;
|
||||
|
||||
busAddr=AQH_NodeMessage_GetSourceAddress(msg);
|
||||
ni=AQH_NodeDb_GetNodeInfoByUid(xo->nodeDb, uid);
|
||||
if (ni) {
|
||||
uint8_t storedBusAddr;
|
||||
|
||||
storedBusAddr=AQH_NodeInfo_GetBusAddress(ni);
|
||||
if (busAddr!=0 && storedBusAddr!=busAddr) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Changed busaddr for %08x from %02x to %02x", uid, storedBusAddr, busAddr);
|
||||
AQH_NodeInfo_SetBusAddress(ni, busAddr);
|
||||
_updateTimestampLastChange(ni);
|
||||
AQH_NodeDb_SetModified(xo->nodeDb);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int rv;
|
||||
|
||||
ni=AQH_NodeInfo_new();
|
||||
AQH_NodeInfo_SetBusAddress(ni, busAddr);
|
||||
AQH_NodeInfo_SetUid(ni, uid);
|
||||
_updateTimestampLastChange(ni);
|
||||
rv=AQH_NodeDb_AddNodeInfo(xo->nodeDb, ni);
|
||||
if (rv<0) {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
||||
AQH_NodeInfo_free(ni);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Added node %08x (%02x)", uid, busAddr);
|
||||
}
|
||||
}
|
||||
return ni;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _assignDeviceId(AQH_OBJECT *o, AQH_NODE_INFO *ni, uint32_t uid)
|
||||
{
|
||||
const AQHNODE_DEVICE *dev;
|
||||
|
||||
dev=AQH_NodeServer_FindDeviceDef(o,
|
||||
AQH_NodeInfo_GetManufacturer(ni),
|
||||
AQH_NodeInfo_GetDeviceType(ni),
|
||||
AQH_NodeInfo_GetDeviceVersion(ni));
|
||||
if (dev==NULL) {
|
||||
DBG_ERROR(NULL,
|
||||
"Unknown NODE device encountered (%08x, %04x, %04x)",
|
||||
AQH_NodeInfo_GetManufacturer(ni),
|
||||
AQH_NodeInfo_GetDeviceType(ni),
|
||||
AQH_NodeInfo_GetDeviceVersion(ni));
|
||||
}
|
||||
else {
|
||||
const char *s;
|
||||
|
||||
s=AQHNODE_Device_GetName(dev);
|
||||
DBG_ERROR(NULL, "Found device \"%s\" (%08x)", s?s:"<no name>", uid);
|
||||
AQH_NodeInfo_SetDeviceId(ni, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _updateTimestampLastChange(AQH_NODE_INFO *ni)
|
||||
{
|
||||
GWEN_TIMESTAMP *t;
|
||||
|
||||
t=GWEN_Timestamp_NowInLocalTime();
|
||||
AQH_NodeInfo_SetTimestampLastChange(ni, t);
|
||||
GWEN_Timestamp_free(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/db.h
Normal file
27
apps/aqhome-nodes/db.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 AQHOMED_DB_H
|
||||
#define AQHOMED_DB_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include "aqhome/events2/object.h"
|
||||
#include "aqhome/ipc2/message.h"
|
||||
|
||||
|
||||
void AQH_NodeServer_NodeMsgToDb(AQH_OBJECT *o, const AQH_MESSAGE *msg);
|
||||
|
||||
void AQH_NodeServer_WriteNodeDb(AQH_OBJECT *o);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
128
apps/aqhome-nodes/devicesdump.c
Normal file
128
apps/aqhome-nodes/devicesdump.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/****************************************************************************
|
||||
* 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 "./devicesdump.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _dumpDevice(const AQHNODE_DEVICE *dev, GWEN_BUFFER *dbuf, int indent);
|
||||
static void _dumpValue(const AQHNODE_VALUE *value, GWEN_BUFFER *dbuf, int indent);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AQH_NodeServer_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf)
|
||||
{
|
||||
|
||||
if (devList && AQHNODE_Device_List_GetCount(devList)) {
|
||||
const AQHNODE_DEVICE *dev;
|
||||
|
||||
GWEN_Buffer_AppendString(dbuf, "Devices:\n");
|
||||
dev=AQHNODE_Device_List_First(devList);
|
||||
while(dev) {
|
||||
_dumpDevice(dev, dbuf, 2);
|
||||
dev=AQHNODE_Device_List_Next(dev);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _dumpDevice(const AQHNODE_DEVICE *dev, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
const char *name;
|
||||
const char *driver;
|
||||
uint32_t manufacturer;
|
||||
uint16_t deviceType;
|
||||
uint16_t deviceVersion;
|
||||
const AQHNODE_VALUE_LIST *valueList;
|
||||
|
||||
name=AQHNODE_Device_GetName(dev);
|
||||
driver=AQHNODE_Device_GetDriver(dev);
|
||||
manufacturer=AQHNODE_Device_GetManufacturer(dev);
|
||||
deviceType=AQHNODE_Device_GetDeviceType(dev);
|
||||
deviceVersion=AQHNODE_Device_GetDeviceVersion(dev);
|
||||
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "Device: %s (%s, %08x, %04x, %04x)\n",
|
||||
name?name:"<empty name>",
|
||||
driver?driver:"<empty driver>",
|
||||
manufacturer,
|
||||
deviceType,
|
||||
deviceVersion);
|
||||
valueList=AQHNODE_Device_GetValueList(dev);
|
||||
if (valueList && AQHNODE_Value_List_GetCount(valueList)) {
|
||||
const AQHNODE_VALUE *value;
|
||||
|
||||
value=AQHNODE_Value_List_First(valueList);
|
||||
while(value) {
|
||||
_dumpValue(value, dbuf, indent+2);
|
||||
value=AQHNODE_Value_List_Next(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _dumpValue(const AQHNODE_VALUE *value, GWEN_BUFFER *dbuf, int indent)
|
||||
{
|
||||
int id;
|
||||
const char *name;
|
||||
const char *descr;
|
||||
int valueType;
|
||||
int dataType;
|
||||
int modality;
|
||||
const char *units;
|
||||
int denom;
|
||||
|
||||
id=AQHNODE_Value_GetId(value);
|
||||
name=AQHNODE_Value_GetName(value);
|
||||
descr=AQHNODE_Value_GetDescription(value);
|
||||
valueType=AQHNODE_Value_GetValueType(value);
|
||||
dataType=AQHNODE_Value_GetDataType(value);
|
||||
modality=AQHNODE_Value_GetModality(value);
|
||||
units=AQHNODE_Value_GetValueUnits(value);
|
||||
denom=AQHNODE_Value_GetDenom(value);
|
||||
|
||||
GWEN_Buffer_FillWithBytes(dbuf, ' ', indent);
|
||||
GWEN_Buffer_AppendArgs(dbuf, "Value: %d[%02x] (%s, %s, %s, %s, %s, %s, %d)\n",
|
||||
id, id,
|
||||
name?name:"<empty name>",
|
||||
AQH_ValueType_toString(valueType),
|
||||
AQH_ValueDataType_toString(dataType),
|
||||
AQH_ValueModality_toString(modality),
|
||||
units?units:"<empty units>",
|
||||
descr?descr:"<empty descr>",
|
||||
denom);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
24
apps/aqhome-nodes/devicesdump.h
Normal file
24
apps/aqhome-nodes/devicesdump.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOME_NODES_DEVICESDUMP_H
|
||||
#define AQHOME_NODES_DEVICESDUMP_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
|
||||
|
||||
void AQH_NodeServer_DumpDevices(const AQHNODE_DEVICE_LIST *devList, GWEN_BUFFER *dbuf);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
397
apps/aqhome-nodes/devicesread.c
Normal file
397
apps/aqhome-nodes/devicesread.c
Normal file
@@ -0,0 +1,397 @@
|
||||
/****************************************************************************
|
||||
* 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 "./devicesread.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/aqhome.h"
|
||||
|
||||
#include <gwenhywfar/directory.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/stringlist.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static int _readDeviceFileToList(const char *sFilename, AQHNODE_DEVICE_LIST *deviceList);
|
||||
static AQHNODE_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl);
|
||||
static int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHNODE_DEVICE_LIST *deviceList);
|
||||
static AQHNODE_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode);
|
||||
static AQHNODE_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *valuesNode);
|
||||
static AQHNODE_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode);
|
||||
static int _readManufacturer(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
|
||||
static int _readDeviceType(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
|
||||
static int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDeviceFile(const char *sFilename)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv=GWEN_Directory_GetPath(sFilename, GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_VARIABLE);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" does not exists, writing later", sFilename);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHNODE_Device_List_new();
|
||||
rv=_readDeviceFileToList(sFilename, deviceList);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "File \"%s\" not found", sFilename);
|
||||
AQHNODE_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AQHNODE_Device_List_GetCount(deviceList)<1) {
|
||||
AQHNODE_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDataDeviceFiles()
|
||||
{
|
||||
GWEN_STRINGLIST *sl;
|
||||
|
||||
sl=AQH_GetListOfMatchingDataFiles("aqhome/devices/nodes", "*.xml");
|
||||
if (sl) {
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=_readDeviceFiles(sl);
|
||||
GWEN_StringList_free(sl);
|
||||
if (deviceList==NULL) {
|
||||
DBG_INFO(NULL, "Error reading data device files");
|
||||
return NULL;
|
||||
}
|
||||
return deviceList;
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No data device files");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE_LIST *_readDeviceFiles(const GWEN_STRINGLIST *sl)
|
||||
{
|
||||
GWEN_STRINGLISTENTRY *se;
|
||||
AQHNODE_DEVICE_LIST *deviceList;
|
||||
|
||||
deviceList=AQHNODE_Device_List_new();
|
||||
se=GWEN_StringList_FirstEntry(sl);
|
||||
while(se) {
|
||||
const char *s;
|
||||
|
||||
s=GWEN_StringListEntry_Data(se);
|
||||
if (s && *s) {
|
||||
int rv;
|
||||
|
||||
DBG_INFO(NULL, "Reading device file \"%s\"", s);
|
||||
rv=_readDeviceFileToList(s, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_WARN(NULL, "Error reading device file \"%s\" (%d), ignoring", s, rv);
|
||||
}
|
||||
}
|
||||
se=GWEN_StringListEntry_Next(se);
|
||||
}
|
||||
|
||||
if (AQHNODE_Device_List_GetCount(deviceList)<1) {
|
||||
AQHNODE_Device_List_free(deviceList);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceFileToList(const char *sFilename, AQHNODE_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *rootNode;
|
||||
GWEN_XMLNODE *deviceListNode;
|
||||
int rv;
|
||||
|
||||
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
|
||||
rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
|
||||
if (rv<0) {
|
||||
DBG_ERROR(NULL, "Error reading XML file \"%s\": %d", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
deviceListNode=GWEN_XMLNode_FindFirstTag(rootNode, "devices", NULL, NULL);
|
||||
if (deviceListNode==NULL)
|
||||
deviceListNode=rootNode;
|
||||
|
||||
rv=_readXmlDevices(deviceListNode, deviceList);
|
||||
if (rv<0 && rv!=GWEN_ERROR_NO_DATA) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading devices from file \"%s\" (%d)", sFilename, rv);
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return rv;
|
||||
}
|
||||
|
||||
GWEN_XMLNode_free(rootNode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readXmlDevices(GWEN_XMLNODE *deviceListNode, AQHNODE_DEVICE_LIST *deviceList)
|
||||
{
|
||||
GWEN_XMLNODE *deviceNode;
|
||||
|
||||
deviceNode=GWEN_XMLNode_FindFirstTag(deviceListNode, "device", NULL, NULL);
|
||||
if (deviceNode) {
|
||||
while(deviceNode) {
|
||||
const char *driverName;
|
||||
|
||||
driverName=GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL);
|
||||
if (driverName && *driverName && strcasecmp(driverName, "nodes")==0) {
|
||||
AQHNODE_DEVICE *device;
|
||||
|
||||
device=_readXmlDevice(deviceNode);
|
||||
if (device==NULL) {
|
||||
DBG_INFO(NULL, "Error reading device from XML");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
else {
|
||||
const char *sDeviceName;
|
||||
|
||||
sDeviceName=AQHNODE_Device_GetName(device);
|
||||
if (sDeviceName && *sDeviceName) {
|
||||
DBG_ERROR(NULL, "Adding device type \"%s\" to list", sDeviceName?sDeviceName:"<no type name>");
|
||||
AQHNODE_Device_List_Add(device, deviceList);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Device with no name, not adding");
|
||||
AQHNODE_Device_free(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "Device is not an NODES device, ignoring");
|
||||
}
|
||||
deviceNode=GWEN_XMLNode_FindNextTag(deviceNode, "device", NULL, NULL);
|
||||
} /* while */
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <device> element found");
|
||||
return GWEN_ERROR_NO_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE *_readXmlDevice(GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
AQHNODE_DEVICE *device;
|
||||
GWEN_XMLNODE *valuesNode;
|
||||
int rv;
|
||||
|
||||
device=AQHNODE_Device_new();
|
||||
AQHNODE_Device_SetName(device, GWEN_XMLNode_GetProperty(deviceNode, "name", NULL));
|
||||
AQHNODE_Device_SetDriver(device, GWEN_XMLNode_GetProperty(deviceNode, "driver", NULL));
|
||||
rv=_readManufacturer(device, deviceNode);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
rv=_readDeviceType(device, deviceNode);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
rv=_readDeviceVersion(device, deviceNode);
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* read values */
|
||||
valuesNode=GWEN_XMLNode_FindFirstTag(deviceNode, "values", NULL, NULL);
|
||||
if (valuesNode) {
|
||||
AQHNODE_VALUE_LIST *valueList;
|
||||
|
||||
valueList=_readXmlValueList(valuesNode);
|
||||
if (valueList==NULL) {
|
||||
DBG_INFO(NULL, "here");
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
AQHNODE_Device_SetValueList(device, valueList);
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, "No <values> element");
|
||||
AQHNODE_Device_free(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_VALUE_LIST *_readXmlValueList(GWEN_XMLNODE *valuesNode)
|
||||
{
|
||||
AQHNODE_VALUE_LIST *valueList;
|
||||
GWEN_XMLNODE *node;
|
||||
|
||||
valueList=AQHNODE_Value_List_new();
|
||||
node=GWEN_XMLNode_FindFirstTag(valuesNode, "value", NULL, NULL);
|
||||
while(node) {
|
||||
AQHNODE_VALUE *value;
|
||||
|
||||
value=_readXmlValue(node);
|
||||
if (value)
|
||||
AQHNODE_Value_List_Add(value, valueList);
|
||||
else {
|
||||
DBG_INFO(NULL, "Error reading <value> element");
|
||||
AQHNODE_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
node=GWEN_XMLNode_FindNextTag(node, "value", NULL, NULL);
|
||||
}
|
||||
if (AQHNODE_Value_List_GetCount(valueList)<1) {
|
||||
DBG_INFO(NULL, "No <value> element in <values> element");
|
||||
AQHNODE_Value_List_free(valueList);
|
||||
return NULL;
|
||||
}
|
||||
return valueList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQHNODE_VALUE *_readXmlValue(GWEN_XMLNODE *valueNode)
|
||||
{
|
||||
AQHNODE_VALUE *value;
|
||||
|
||||
value=AQHNODE_Value_new();
|
||||
AQHNODE_Value_SetName(value, GWEN_XMLNode_GetProperty(valueNode, "name", NULL));
|
||||
AQHNODE_Value_SetId(value, GWEN_XMLNode_GetIntProperty(valueNode, "id", 0));
|
||||
AQHNODE_Value_SetValueUnits(value, GWEN_XMLNode_GetProperty(valueNode, "units", NULL));
|
||||
AQHNODE_Value_SetValueType(value, AQH_ValueType_fromString(GWEN_XMLNode_GetProperty(valueNode, "type", NULL)));
|
||||
AQHNODE_Value_SetDataType(value, AQH_ValueDataType_fromString(GWEN_XMLNode_GetProperty(valueNode, "dataType", NULL)));
|
||||
AQHNODE_Value_SetModality(value, AQH_ValueModality_fromString(GWEN_XMLNode_GetProperty(valueNode, "modality", NULL)));
|
||||
AQHNODE_Value_SetDenom(value, GWEN_XMLNode_GetIntProperty(valueNode, "denom", 1));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readManufacturer(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
const char *s;
|
||||
uint32_t v;
|
||||
|
||||
s=GWEN_XMLNode_GetCharValue(deviceNode, "manufacturer", NULL);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(NULL, "Missing manufacturer");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
if (strlen(s)>4) {
|
||||
DBG_ERROR(NULL, "Bad manufacturer string (too long): \"%s\"", s);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
v=0;
|
||||
while(*s) {
|
||||
v<<=8;
|
||||
v|=*s & 0xff;
|
||||
s++;
|
||||
}
|
||||
v=((v>>24) & 0x000000ffL) |
|
||||
((v>>8) & 0x0000ff00L) |
|
||||
((v<<8) & 0x00ff0000L) |
|
||||
((v<<24) & 0xff000000L);
|
||||
|
||||
AQHNODE_Device_SetManufacturer(device, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceType(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
const char *s;
|
||||
uint16_t v;
|
||||
|
||||
s=GWEN_XMLNode_GetCharValue(deviceNode, "devicetype", NULL);
|
||||
if (!(s && *s)) {
|
||||
DBG_ERROR(NULL, "Missing device type");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
if (strlen(s)>2) {
|
||||
DBG_ERROR(NULL, "Bad devicetype string (too long): \"%s\"", s);
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
v=0;
|
||||
while(*s) {
|
||||
v<<=8;
|
||||
v|=*s & 0xff;
|
||||
s++;
|
||||
}
|
||||
|
||||
AQHNODE_Device_SetDeviceType(device, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _readDeviceVersion(AQHNODE_DEVICE *device, GWEN_XMLNODE *deviceNode)
|
||||
{
|
||||
int v;
|
||||
|
||||
v=GWEN_XMLNode_GetIntValue(deviceNode, "deviceversion", -1);
|
||||
if (v<0) {
|
||||
DBG_ERROR(NULL, "Missing device version");
|
||||
return GWEN_ERROR_BAD_DATA;
|
||||
}
|
||||
|
||||
AQHNODE_Device_SetDeviceVersion(device, v<<8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
25
apps/aqhome-nodes/devicesread.h
Normal file
25
apps/aqhome-nodes/devicesread.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 AQHOME_NODES_DEVICESREAD_H
|
||||
#define AQHOME_NODES_DEVICESREAD_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
|
||||
|
||||
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDeviceFile(const char *sFilename);
|
||||
AQHNODE_DEVICE_LIST *AQH_NodeServer_ReadDataDeviceFiles(void);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
252
apps/aqhome-nodes/main.c
Normal file
252
apps/aqhome-nodes/main.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/****************************************************************************
|
||||
* 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/api.h>
|
||||
#include <aqhome/aqhome.h>
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/gwenhywfar.h>
|
||||
#include <gwenhywfar/logger.h>
|
||||
#include <gwenhywfar/cgui.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* defines
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define I18N(msg) msg
|
||||
#define I18S(msg) msg
|
||||
|
||||
#define CONNCLEAN_INTERVAL_IN_SECS 2
|
||||
#define CONNCHECK_INTERVAL_IN_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop);
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static int _setSignalHandlers(void);
|
||||
static int _setupSigAction(struct sigaction *sa, int sig);
|
||||
static void _signalHandler(int s);
|
||||
#endif
|
||||
static int _diffInSeconds(time_t t1, time_t t0);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* static vars
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT, saPIPE;
|
||||
#endif
|
||||
|
||||
static int stopService=0;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rv;
|
||||
AQH_EVENT_LOOP *eventLoop;
|
||||
AQH_OBJECT *aqh;
|
||||
GWEN_GUI *gui;
|
||||
|
||||
rv=GWEN_Init();
|
||||
if (rv) {
|
||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
GWEN_Logger_Open(0, "aqhome-nodes", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
||||
|
||||
rv=_setSignalHandlers();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv=AQH_Init();
|
||||
if (rv<0) {
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
gui=GWEN_Gui_CGui_new();
|
||||
GWEN_Gui_SetGui(gui);
|
||||
|
||||
eventLoop=AQH_EventLoop_new();
|
||||
aqh=AQH_NodeServer_new(eventLoop);
|
||||
rv=AQH_NodeServer_Init(aqh, argc, argv);
|
||||
if (rv<0) {
|
||||
if (rv==GWEN_ERROR_CLOSE)
|
||||
return 1;
|
||||
DBG_INFO(NULL, "here (%d)", rv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
_runService(aqh, eventLoop);
|
||||
|
||||
AQH_NodeServer_Fini(aqh);
|
||||
AQH_Object_free(aqh);
|
||||
AQH_EventLoop_free(eventLoop);
|
||||
|
||||
GWEN_Gui_SetGui(NULL);
|
||||
GWEN_Gui_free(gui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _runService(AQH_OBJECT *aqh, AQH_EVENT_LOOP *eventLoop)
|
||||
{
|
||||
time_t timeStart;
|
||||
int timeout;
|
||||
time_t timeLastConnectionCleanup;
|
||||
time_t timeLastConnCheck;
|
||||
|
||||
timeout=AQH_NodeServer_GetTimeout(aqh);
|
||||
timeStart=time(NULL);
|
||||
timeLastConnectionCleanup=time(NULL);
|
||||
timeLastConnCheck=time(NULL);
|
||||
|
||||
while(!stopService) {
|
||||
time_t now;
|
||||
|
||||
AQH_EventLoop_Run(eventLoop, 2000);
|
||||
AQH_NodeServer_HandleTtyMsgs(aqh);
|
||||
AQH_NodeServer_HandleClientMsgs(aqh);
|
||||
AQH_NodeServer_HandleBrokerMsgs(aqh);
|
||||
|
||||
now=time(NULL);
|
||||
|
||||
if (_diffInSeconds(now, timeLastConnectionCleanup)>CONNCLEAN_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Cleanup connections");
|
||||
AQH_NodeServer_CleanupClients(aqh);
|
||||
timeLastConnectionCleanup=now;
|
||||
}
|
||||
|
||||
if (_diffInSeconds(now, timeLastConnCheck)>CONNCHECK_INTERVAL_IN_SECS) {
|
||||
DBG_INFO(NULL, "Check connections");
|
||||
AQH_NodeServer_CheckBrokerConnection(aqh);
|
||||
AQH_NodeServer_CheckTtyConnection(aqh);
|
||||
timeLastConnCheck=now;
|
||||
}
|
||||
|
||||
if (timeout && (_diffInSeconds(now, timeStart)>timeout)) {
|
||||
DBG_INFO(NULL, "Timeout");
|
||||
break;
|
||||
}
|
||||
} /* while */
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setSignalHandlers(void)
|
||||
{
|
||||
#ifdef HAVE_SIGNAL_H
|
||||
int rv;
|
||||
|
||||
rv=_setupSigAction(&saINT, SIGINT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saTERM, SIGTERM);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saHUP, SIGHUP);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv=_setupSigAction(&saPIPE, SIGPIPE);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
# ifdef SIGTSTP
|
||||
rv=_setupSigAction(&saTSTP, SIGTSTP);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
|
||||
# ifdef SIGCONT
|
||||
rv=_setupSigAction(&saCONT, SIGCONT);
|
||||
if (rv)
|
||||
return rv;
|
||||
# endif
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _setupSigAction(struct sigaction *sa, int sig)
|
||||
{
|
||||
sa->sa_handler=_signalHandler;
|
||||
sigemptyset(&sa->sa_mask);
|
||||
sa->sa_flags=0;
|
||||
if (sigaction(sig, sa, 0)) {
|
||||
DBG_ERROR(NULL, "Could not setup signal handler for signal %d", sig);
|
||||
return GWEN_ERROR_IO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _signalHandler(int s)
|
||||
{
|
||||
switch(s) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _diffInSeconds(time_t t1, time_t t0)
|
||||
{
|
||||
return t1-t0;
|
||||
}
|
||||
|
||||
|
||||
82
apps/aqhome-nodes/r_connect.c
Normal file
82
apps/aqhome-nodes/r_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 "./r_connect.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn.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 AQH_NodeServer_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_NODES_ID,
|
||||
AQH_IPC_PROTOCOL_NODES_VERSION,
|
||||
AQH_MSGTYPE_IPC_NODES_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
resultCode, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/r_connect.h
Normal file
27
apps/aqhome-nodes/r_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 AQHOMED_R_CONNECT_H
|
||||
#define AQHOMED_R_CONNECT_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
|
||||
void AQH_NodeServer_HandleConnect(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
81
apps/aqhome-nodes/r_forward.c
Normal file
81
apps/aqhome-nodes/r_forward.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/****************************************************************************
|
||||
* 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 "./r_forward.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn_forward.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 <aqhome/msg/node/m_node.h>
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* code
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AQH_NodeServer_HandleForward(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
const GWEN_TAG16 *tag;
|
||||
const uint8_t *ptr;
|
||||
uint32_t len;
|
||||
|
||||
tag=tagList?GWEN_Tag16_List_FindFirstByTagType(tagList, AQH_MSGNODE_FORWARD_TAGS_MSG):NULL;
|
||||
ptr=tag?GWEN_Tag16_GetTagData(tag):NULL;
|
||||
len=tag?GWEN_Tag16_GetTagLength(tag):0;
|
||||
|
||||
if (ptr && len) {
|
||||
if (xo->ttyEndpoint) {
|
||||
AQH_MESSAGE *nodeMsg;
|
||||
|
||||
nodeMsg=AQH_Message_new();
|
||||
AQH_Message_SetData(nodeMsg, ptr, len);
|
||||
AQH_Message_SetUsedSize(nodeMsg, len);
|
||||
AQH_Endpoint_AddMsgOut(xo->ttyEndpoint, nodeMsg);
|
||||
DBG_ERROR(NULL, "Forwarding node message %d to node", AQH_NodeMessage_GetMsgType(nodeMsg));
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "TTY endpoint currently not connected");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_TRYAGAIN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Empty message to forward");
|
||||
resultCode=AQH_MSGDATA_RESULT_ERROR_BADDATA;
|
||||
}
|
||||
|
||||
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_NODES_ID,
|
||||
AQH_IPC_PROTOCOL_NODES_VERSION,
|
||||
AQH_MSGTYPE_IPC_NODES_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
resultCode, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/r_forward.h
Normal file
27
apps/aqhome-nodes/r_forward.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_R_FORWARD_H
|
||||
#define AQHOMED_R_FORWARD_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AQH_NodeServer_HandleForward(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
77
apps/aqhome-nodes/r_getnodes.c
Normal file
77
apps/aqhome-nodes/r_getnodes.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
* 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 "./r_getnodes.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn_setaccmsggrps.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn_getdevices_rsp.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 AQH_NodeServer_HandleGetNodes(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_NODE_INFO_LIST *nodeInfoList;
|
||||
|
||||
nodeInfoList=AQH_NodeDb_GetAllNodeInfos(xo->nodeDb);
|
||||
if (nodeInfoList && AQH_NodeInfo_List_GetCount(nodeInfoList)) {
|
||||
const AQH_NODE_INFO *ni;
|
||||
|
||||
ni=AQH_NodeInfo_List_First(nodeInfoList);
|
||||
while(ni) {
|
||||
const AQH_NODE_INFO *niNext;
|
||||
AQH_MESSAGE *outMsg;
|
||||
|
||||
niNext=AQH_NodeInfo_List_Next(ni);
|
||||
DBG_INFO(AQH_LOGDOMAIN, "Sending response for node %02x (%08x)", AQH_NodeInfo_GetBusAddress(ni), AQH_NodeInfo_GetUid(ni));
|
||||
outMsg=AQH_IpcnMessageGetDevicesRsp_new(AQH_MSGTYPE_IPC_NODES_GETDEVICES_RSP,
|
||||
AQH_Endpoint_GetNextMessageId(ep), AQH_IpcMessage_GetMsgId(msg),
|
||||
niNext?0:AQH_MSGNODE_GETDEVICES_RSP_FLAGS_LASTMSG, ni);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
DBG_DEBUG(NULL, "Messages in clients out queue: %d", AQH_Message_List_GetCount(AQH_Endpoint_GetMsgOutList(ep)));
|
||||
ni=niNext;
|
||||
}
|
||||
}
|
||||
else {
|
||||
AQH_MESSAGE *outMsg;
|
||||
|
||||
DBG_INFO(AQH_LOGDOMAIN, "No nodes");
|
||||
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_NODES_ID,
|
||||
AQH_IPC_PROTOCOL_NODES_VERSION,
|
||||
AQH_MSGTYPE_IPC_NODES_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
AQH_MSGDATA_RESULT_ERROR_NODATA, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/r_getnodes.h
Normal file
27
apps/aqhome-nodes/r_getnodes.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 AQHOMED_R_GETNODES_H
|
||||
#define AQHOMED_R_GETNODES_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AQH_NodeServer_HandleGetNodes(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
56
apps/aqhome-nodes/r_setaccmsggrps.c
Normal file
56
apps/aqhome-nodes/r_setaccmsggrps.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/****************************************************************************
|
||||
* 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 "./r_setaccmsggrps.h"
|
||||
#include "./server_p.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
#include "aqhome/msg/ipc/m_ipc.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn.h"
|
||||
#include "aqhome/msg/ipc/nodes/m_ipcn_setaccmsggrps.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 AQH_NodeServer_HandleSetAccMsgGrps(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList)
|
||||
{
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo) {
|
||||
AQH_MESSAGE *outMsg;
|
||||
int resultCode=AQH_MSGDATA_RESULT_SUCCESS;
|
||||
uint32_t msgGrps=0;
|
||||
|
||||
msgGrps=AQH_IpcnMessageSetAcceptedMsgGroups_GetGroups(tagList);
|
||||
AQH_Endpoint_SetAcceptedMsgGroups(ep, msgGrps);
|
||||
outMsg=AQH_IpcMessageResult_new(AQH_IPC_PROTOCOL_NODES_ID,
|
||||
AQH_IPC_PROTOCOL_NODES_VERSION,
|
||||
AQH_MSGTYPE_IPC_NODES_RESULT,
|
||||
AQH_Endpoint_GetNextMessageId(ep),
|
||||
AQH_IpcMessage_GetMsgId(msg),
|
||||
resultCode, NULL);
|
||||
AQH_Endpoint_AddMsgOut(ep, outMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/r_setaccmsggrps.h
Normal file
27
apps/aqhome-nodes/r_setaccmsggrps.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_R_SETACCMSGGRPS_H
|
||||
#define AQHOMED_R_SETACCMSGGRPS_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/tag16.h>
|
||||
|
||||
|
||||
void AQH_NodeServer_HandleSetAccMsgGrps(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *msg, const GWEN_TAG16_LIST *tagList);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
382
apps/aqhome-nodes/r_setdata.c
Normal file
382
apps/aqhome-nodes/r_setdata.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/****************************************************************************
|
||||
* 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 "./r_setdata.h"
|
||||
#include "./server_p.h"
|
||||
|
||||
#include "aqhome/aqhome.h"
|
||||
#include "aqhome/data/value.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 "aqhome/msg/ipc/data/m_ipcd_setdata.h"
|
||||
#include "aqhome/msg/node/m_node.h"
|
||||
#include "aqhome/msg/node/m_value.h"
|
||||
#include "aqhome/ipc2/endpoint.h"
|
||||
|
||||
#include <gwenhywfar/debug.h>
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* definitions
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#define R_SETDATA_REQUEST_EXPIRE_SECS 20
|
||||
#define R_SETDATA_SUBREQUEST_EXPIRE_SECS 10
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static AQH_NODE_INFO *_getNodeInfoFromValue(AQH_NODE_SERVER *xo, const AQH_VALUE *value);
|
||||
|
||||
static AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o, AQH_NODE_SERVER *xo,
|
||||
AQH_OBJECT *ep, uint32_t requestMsgId,
|
||||
int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom);
|
||||
|
||||
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_NODE_SERVER *xo,
|
||||
int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom);
|
||||
static int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg);
|
||||
static void _subRqAbort(AQH_MSG_REQUEST *rq, int reason);
|
||||
static void _sendResponseResultToBroker(AQH_OBJECT *ep, uint32_t refMsgId, int result);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
void AQH_NodeServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg)
|
||||
{
|
||||
if (o) {
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo) {
|
||||
uint32_t msgId;
|
||||
|
||||
DBG_INFO(NULL, "Received IPC SetDataRequest message");
|
||||
msgId=AQH_IpcMessage_GetMsgId(recvdMsg);
|
||||
|
||||
if (xo->ttyEndpoint) {
|
||||
GWEN_TAG16_LIST *tagList;
|
||||
|
||||
tagList=AQH_IpcMessageTag16_ParsePayload(recvdMsg, 0);
|
||||
if (tagList) {
|
||||
AQH_VALUE *value;
|
||||
|
||||
value=AQH_IpcdMessageSetData_ReadValue(tagList);
|
||||
if (value) {
|
||||
const char *varName;
|
||||
|
||||
varName=AQH_Value_GetName(value);
|
||||
if (varName) {
|
||||
char *data;
|
||||
|
||||
data=AQH_IpcdMessageSetData_ReadData(tagList);
|
||||
if (data) {
|
||||
AQH_NODE_INFO *nodeInfo;
|
||||
|
||||
nodeInfo=_getNodeInfoFromValue(xo, value);
|
||||
if (nodeInfo) {
|
||||
const char *devName;
|
||||
|
||||
devName=AQH_NodeInfo_GetDeviceId(nodeInfo);
|
||||
if (devName) {
|
||||
const AQHNODE_DEVICE *devInfo;
|
||||
|
||||
devInfo=AQH_NodeServer_GetDeviceDefByName(o, devName);
|
||||
if (devInfo) {
|
||||
const AQHNODE_VALUE *devValue;
|
||||
|
||||
devValue=AQHNODE_Value_List_GetByName(AQHNODE_Device_GetValueList(devInfo), varName);
|
||||
if (devValue) {
|
||||
uint16_t dataVal=0;
|
||||
uint16_t dataDenom=0;
|
||||
|
||||
if (AQH_ReadDataFromString(AQHNODE_Value_GetDataType(devValue), data, &dataVal, &dataDenom)==0) {
|
||||
AQH_MSG_REQUEST *rq;
|
||||
int destAddr;
|
||||
|
||||
destAddr=AQH_NodeInfo_GetBusAddress(nodeInfo);
|
||||
DBG_DEBUG(NULL, "Creating SETDATA request");
|
||||
|
||||
rq=_mkRequest_SetData(o, xo, ep, msgId, destAddr, AQHNODE_Value_GetId(devValue), dataVal, dataDenom);
|
||||
AQH_NodeServer_AddRequestToTree(o, rq);
|
||||
/* done */
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Bad data \"%s\"", data);
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_BADDATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Invalid value name \"%s\"", varName);
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Unknown node \"%s\"", devName);
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Node not yet fully identified, come back later");
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_TRYAGAIN);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No matching nodeinfo");
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_INVALID);
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No data");
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_NODATA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "No var name");
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_NODATA);
|
||||
}
|
||||
AQH_Value_free(value);
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "Could not read value from message");
|
||||
}
|
||||
GWEN_Tag16_List_free(tagList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_ERROR(NULL, "TTY endpoint not connected");
|
||||
_sendResponseResultToBroker(ep, msgId, AQH_MSGDATA_RESULT_ERROR_IO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* IPC Request SETDATA
|
||||
*/
|
||||
|
||||
AQH_MSG_REQUEST *_mkRequest_SetData(AQH_OBJECT *o, AQH_NODE_SERVER *xo,
|
||||
AQH_OBJECT *ep, uint32_t requestMsgId,
|
||||
int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom)
|
||||
{
|
||||
AQH_MSG_REQUEST *rq;
|
||||
AQH_MSG_REQUEST *subRq;
|
||||
|
||||
rq=AQH_MsgRequest_new();
|
||||
AQH_MsgRequest_SetPrivateData(rq, o);
|
||||
AQH_MsgRequest_SetEndpoint(rq, ep);
|
||||
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, xo, destAddr, valueId, dataVal, dataDenom);
|
||||
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_INFO(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)
|
||||
_sendResponseResultToBroker(ep, refMsgId, AQH_MSGDATA_RESULT_ERROR_GENERIC);
|
||||
else
|
||||
_sendResponseResultToBroker(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);
|
||||
_sendResponseResultToBroker(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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* TTY Request SETDATA
|
||||
*/
|
||||
|
||||
|
||||
AQH_MSG_REQUEST *_mkSubRequest_SetData(AQH_OBJECT *o, AQH_NODE_SERVER *xo,
|
||||
int destAddr, int valueId, uint16_t dataVal, uint16_t dataDenom)
|
||||
{
|
||||
AQH_MSG_REQUEST *rq;
|
||||
uint16_t msgId;
|
||||
AQH_MESSAGE *msgOut;
|
||||
|
||||
rq=AQH_MsgRequest_new();
|
||||
AQH_MsgRequest_SetPrivateData(rq, o);
|
||||
AQH_MsgRequest_SetEndpoint(rq, xo->ttyEndpoint);
|
||||
|
||||
AQH_MsgRequest_SetHandleResponseFn(rq, _subRqHandleResponse);
|
||||
AQH_MsgRequest_SetAbortFn(rq, _subRqAbort);
|
||||
|
||||
msgId=AQH_Endpoint_GetNextMessageId(xo->ttyEndpoint) & 0xffff;
|
||||
AQH_MsgRequest_SetRequestMsgId(rq, msgId);
|
||||
AQH_MsgRequest_SetTimestamps(rq, R_SETDATA_SUBREQUEST_EXPIRE_SECS);
|
||||
|
||||
msgOut=AQH_ValueMessage_new(destAddr, xo->nodeAddress, AQH_MSG_TYPE_VALUE_SET, msgId, valueId, dataVal, dataDenom);
|
||||
AQH_Endpoint_AddMsgOut(xo->ttyEndpoint, msgOut);
|
||||
|
||||
return rq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int _subRqHandleResponse(AQH_MSG_REQUEST *rq, const AQH_MESSAGE *msg)
|
||||
{
|
||||
AQH_OBJECT *o;
|
||||
|
||||
DBG_DEBUG(NULL, "Checking message from %02x", AQH_NodeMessage_GetSourceAddress(msg));
|
||||
o=(AQH_OBJECT*)AQH_MsgRequest_GetPrivateData(rq);
|
||||
if (o) {
|
||||
AQH_NODE_SERVER *xo;
|
||||
|
||||
xo=AQH_NodeServer_GetServerData(o);
|
||||
if (xo) {
|
||||
uint8_t destAddr;
|
||||
|
||||
destAddr=AQH_NodeMessage_GetDestAddress(msg);
|
||||
if (destAddr==0xff || destAddr==xo->nodeAddress) {
|
||||
uint8_t msgCode;
|
||||
|
||||
msgCode=AQH_NodeMessage_GetMsgType(msg);
|
||||
if (msgCode==AQH_MSG_TYPE_VALUE_SET_ACK || msgCode==AQH_MSG_TYPE_VALUE_SET_NACK) {
|
||||
uint16_t msgId;
|
||||
|
||||
msgId=AQH_ValueMessage_GetMsgId(msg);
|
||||
if (msgId==AQH_MsgRequest_GetRequestMsgId(rq)) {
|
||||
AQH_MSG_REQUEST *rqParent;
|
||||
|
||||
DBG_INFO(NULL,
|
||||
"Received response (%02x) for msg id %04x from %02x",
|
||||
msgCode, msgId, AQH_NodeMessage_GetSourceAddress(msg));
|
||||
AQH_MsgRequest_SetResult(rq,
|
||||
(msgCode==AQH_MSG_TYPE_VALUE_SET_ACK)?AQH_MSGDATA_RESULT_SUCCESS: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, AQH_MSG_REQUEST_REASON_DONE);
|
||||
return AQH_MSG_REQUEST_RESULT_HANDLED;
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, " Non-matching message id");
|
||||
}
|
||||
}
|
||||
else {
|
||||
DBG_INFO(NULL, " Non-matching message code");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
AQH_NODE_INFO *_getNodeInfoFromValue(AQH_NODE_SERVER *xo, const AQH_VALUE *value)
|
||||
{
|
||||
const char *s;
|
||||
unsigned long int uid;
|
||||
|
||||
s=AQH_Value_GetDeviceName(value);
|
||||
if (s && *s && 1==sscanf(s, "%lx", &uid)) {
|
||||
AQH_NODE_INFO *ni;
|
||||
|
||||
ni=AQH_NodeDb_GetNodeInfoByUid(xo->nodeDb, uid);
|
||||
if (ni==NULL) {
|
||||
DBG_ERROR(NULL, "Node \"%08lx\" not found", uid);
|
||||
return NULL;
|
||||
}
|
||||
return ni;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _sendResponseResultToBroker(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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
27
apps/aqhome-nodes/r_setdata.h
Normal file
27
apps/aqhome-nodes/r_setdata.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef AQHOMED_R_SETDATA_H
|
||||
#define AQHOMED_R_SETDATA_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
|
||||
#include <gwenhywfar/request.h>
|
||||
|
||||
|
||||
|
||||
void AQH_NodeServer_HandleSetData(AQH_OBJECT *o, AQH_OBJECT *ep, const AQH_MESSAGE *recvdMsg);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1476
apps/aqhome-nodes/server.c
Normal file
1476
apps/aqhome-nodes/server.c
Normal file
File diff suppressed because it is too large
Load Diff
94
apps/aqhome-nodes/server.h
Normal file
94
apps/aqhome-nodes/server.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/****************************************************************************
|
||||
* 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 SERVER_H
|
||||
#define SERVER_H
|
||||
|
||||
|
||||
|
||||
#include "aqhome-nodes/types/device.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
|
||||
|
||||
|
||||
|
||||
#define AQH_ENDPOINT_VID_STATS_PACKETS_IN 0xe0
|
||||
#define AQH_ENDPOINT_VID_STATS_PACKETS_OUT 0xe1
|
||||
#define AQH_ENDPOINT_VID_STATS_ERRS_CONTENT 0xe2
|
||||
#define AQH_ENDPOINT_VID_STATS_ERRS_IO 0xe3
|
||||
#define AQH_ENDPOINT_VID_STATS_ERRS_NOBUF 0xe4
|
||||
#define AQH_ENDPOINT_VID_STATS_ERRS_COLLISIONS 0xe5
|
||||
#define AQH_ENDPOINT_VID_STATS_ERRS_BUSY 0xe6
|
||||
#define AQH_ENDPOINT_VID_STATS_HEAP_USED 0xe7
|
||||
#define AQH_ENDPOINT_VID_STATS_HEAP_FREE 0xe8
|
||||
|
||||
|
||||
|
||||
AQH_OBJECT *AQH_NodeServer_new(AQH_EVENT_LOOP *eventLoop);
|
||||
int AQH_NodeServer_Init(AQH_OBJECT *o, int argc, char **argv);
|
||||
void AQH_NodeServer_Fini(AQH_OBJECT *o);
|
||||
|
||||
/* loop functions */
|
||||
void AQH_NodeServer_CleanupClients(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_HandleTtyMsgs(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_HandleClientMsgs(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_HandleBrokerMsgs(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_CheckBrokerConnection(AQH_OBJECT *o);
|
||||
void AQH_NodeServer_CheckTtyConnection(AQH_OBJECT *o);
|
||||
|
||||
|
||||
/* getters and setters */
|
||||
int AQH_NodeServer_GetTimeout(const AQH_OBJECT *o);
|
||||
void AQH_NodeServer_SetLogFile(AQH_OBJECT *o, const char *s);
|
||||
void AQH_NodeServer_SetDbFile(AQH_OBJECT *o, const char *s);
|
||||
void AQH_NodeServer_SetPidFile(AQH_OBJECT *o, const char *s);
|
||||
|
||||
void AQH_NodeServer_SetDevicePath(AQH_OBJECT *o, const char *s);
|
||||
void AQH_NodeServer_SetTpcAddress(AQH_OBJECT *o, const char *s);
|
||||
void AQH_NodeServer_SetTcpPort(AQH_OBJECT *o, int i);
|
||||
void AQH_NodeServer_SetBrokerAddress(AQH_OBJECT *o, const char *s);
|
||||
void AQH_NodeServer_SetBrokerPort(AQH_OBJECT *o, int i);
|
||||
void AQH_NodeServer_SetBrokerClientId(AQH_OBJECT *o, const char *s);
|
||||
|
||||
|
||||
/* device management */
|
||||
const AQHNODE_DEVICE_LIST *AQH_NodeServer_GetDeviceDefList(const AQH_OBJECT *o);
|
||||
const AQHNODE_DEVICE *AQH_NodeServer_FindDeviceDef(const AQH_OBJECT *o,
|
||||
uint32_t manufacturer,
|
||||
uint16_t deviceType, uint16_t deviceVersion);
|
||||
const AQHNODE_DEVICE *AQH_NodeServer_GetDeviceDefByName(const AQH_OBJECT *o, const char *name);
|
||||
|
||||
|
||||
/* request management */
|
||||
AQH_MSG_REQUEST *AQH_NodeServer_GetRequestTree(const AQH_OBJECT *o);
|
||||
void AQH_NodeServer_AddRequestToTree(AQH_OBJECT *o, AQH_MSG_REQUEST *rq);
|
||||
void AQH_NodeServer_CleanupRequests(AQH_OBJECT *o);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
81
apps/aqhome-nodes/server_p.h
Normal file
81
apps/aqhome-nodes/server_p.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/****************************************************************************
|
||||
* 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 SERVER_P_H
|
||||
#define SERVER_P_H
|
||||
|
||||
|
||||
#include "./server.h"
|
||||
#include "aqhome-nodes/types/device.h"
|
||||
|
||||
#include "aqhome/nodes/nodedb.h"
|
||||
#include "aqhome/ipc2/msgrequest.h"
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
|
||||
/* default values */
|
||||
#define AQHOMED_DEFAULT_NODEADDR 240
|
||||
#define AQHOMED_DEFAULT_PIDFILE "/var/run/aqhomed-node.pid"
|
||||
#define AQHOMED_DEFAULT_DEVICE "/dev/ttyUSB0"
|
||||
#define AQHOMED_DEFAULT_IPC_PORT 45454
|
||||
#define AQHOMED_DEFAULT_BROKER_PORT 1899
|
||||
#define AQHOMED_DEFAULT_BROKER_CLIENTID "nodes"
|
||||
|
||||
|
||||
|
||||
typedef struct AQH_NODE_SERVER AQH_NODE_SERVER;
|
||||
struct AQH_NODE_SERVER {
|
||||
AQH_OBJECT *ttyEndpoint;
|
||||
AQH_OBJECT *brokerEndpoint;
|
||||
|
||||
AQH_OBJECT *ipcEndpoint;
|
||||
AQH_OBJECT_LIST *ipcClientList;
|
||||
|
||||
AQH_NODE_DB *nodeDb;
|
||||
AQHNODE_DEVICE_LIST *deviceDefList;
|
||||
|
||||
AQH_MSG_REQUEST *requestTree;
|
||||
|
||||
GWEN_DB_NODE *dbArgs;
|
||||
|
||||
char *dbFile;
|
||||
char *logFile;
|
||||
char *pidFile;
|
||||
|
||||
int timeout; /* timeout for run e.g. inside valgrind */
|
||||
char *devicePath;
|
||||
|
||||
char *tcpAddress;
|
||||
int tcpPort;
|
||||
|
||||
char *brokerAddress;
|
||||
int brokerPort;
|
||||
char *brokerClientId;
|
||||
|
||||
time_t timestampTtyDown;
|
||||
time_t timestampBrokerDown;
|
||||
|
||||
int nodeAddress;
|
||||
|
||||
struct termios initialTermiosState;
|
||||
|
||||
int timeoutInSeconds;
|
||||
|
||||
uint8_t protoId;
|
||||
uint8_t protoVer;
|
||||
|
||||
int noAttn;
|
||||
};
|
||||
|
||||
|
||||
AQH_NODE_SERVER *AQH_NodeServer_GetServerData(const AQH_OBJECT *o);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
136
apps/aqhome-nodes/tty_log.c
Normal file
136
apps/aqhome-nodes/tty_log.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/****************************************************************************
|
||||
* 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 "./tty_log.h"
|
||||
#include "./aqhomed_p.h"
|
||||
|
||||
#include "aqhome/msg/msg_value.h"
|
||||
#include "aqhome/msg/msg_value2.h"
|
||||
#include "aqhome/msg/msg_value3.h"
|
||||
#include "aqhome/msg/msg_sendstats.h"
|
||||
#include "aqhome/msg/msg_recvstats.h"
|
||||
#include "aqhome/msg/msg_memstats.h"
|
||||
#include "aqhome/msg/msg_sysstats.h"
|
||||
#include "aqhome/msg/msg_ping.h"
|
||||
#include "aqhome/msg/msg_pong.h"
|
||||
#include "aqhome/msg/msg_needaddr.h"
|
||||
#include "aqhome/msg/msg_claimaddr.h"
|
||||
#include "aqhome/msg/msg_haveaddr.h"
|
||||
#include "aqhome/msg/msg_denyaddr.h"
|
||||
#include "aqhome/msg/msg_device.h"
|
||||
#include "aqhome/msg/msg_flashready.h"
|
||||
#include "aqhome/msg/msg_flashstart.h"
|
||||
#include "aqhome/msg/msg_flashresponse.h"
|
||||
#include "aqhome/msg/msg_flashend.h"
|
||||
#include "aqhome/msg/msg_flashdata.h"
|
||||
#include "aqhome/msg/msg_reboot.h"
|
||||
|
||||
#include <gwenhywfar/list.h>
|
||||
#include <gwenhywfar/inherit.h>
|
||||
#include <gwenhywfar/debug.h>
|
||||
#include <gwenhywfar/gwentime.h>
|
||||
#include <gwenhywfar/text.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* forward declarations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void _writeToLogFile(const char *filename, const char *txt);
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* implementations
|
||||
* ------------------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg)
|
||||
{
|
||||
if (aqh && aqh->logFile) {
|
||||
uint8_t msgType;
|
||||
int msgIsValid;
|
||||
GWEN_BUFFER *dbuf;
|
||||
GWEN_TIME *ti;
|
||||
|
||||
dbuf=GWEN_Buffer_new(0, 256, 0, 1);
|
||||
ti=GWEN_CurrentTime();
|
||||
GWEN_Time_toString(ti, "YYYY-MM-DD hh:mm:ss ", dbuf);
|
||||
GWEN_Time_free(ti);
|
||||
ti=NULL;
|
||||
|
||||
msgIsValid=(AQH_NodeMsg_IsChecksumValid(msg) && AQH_NodeMsg_IsMsgComplete(msg));
|
||||
msgType=AQH_NodeMsg_GetMsgType(msg);
|
||||
|
||||
if (msgIsValid) {
|
||||
switch(msgType) {
|
||||
case AQH_MSG_TYPE_PING: AQH_PingMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_PONG: AQH_PongMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_COMSENDSTATS: AQH_SendStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_COMRECVSTATS: AQH_RecvStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_TWIBUSMEMBER: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_DEBUG: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_VALUE: AQH_ValueMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_VALUE2: AQH_Value2Msg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_NEED_ADDRESS: AQH_NeedAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_CLAIM_ADDRESS: AQH_ClaimAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_HAVE_ADDRESS: AQH_HaveAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_DENY_ADDRESS: AQH_DenyAddrMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_DEVICE: AQH_DeviceMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_MEMSTATS: AQH_MemStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_SYSSTATS: AQH_SysStatsMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_READY: AQH_FlashReadyMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_START: AQH_FlashStartMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_RSP: AQH_FlashResponseMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_END: AQH_FlashEndMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_FLASH_DATA: AQH_FlashDataMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_REBOOT_REQ: AQH_RebootRequestMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_REBOOT_RSP: AQH_RebootResponseMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
case AQH_MSG_TYPE_VALUE_REPORT:
|
||||
case AQH_MSG_TYPE_VALUE_SET:
|
||||
case AQH_MSG_TYPE_VALUE_SET_ACK:
|
||||
case AQH_MSG_TYPE_VALUE_SET_NACK: AQH_Value3Msg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
default: AQH_NodeMsg_DumpToBuffer(msg, dbuf, "received"); break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
AQH_NodeMsg_DumpToBuffer(msg, dbuf, "(invalid) received");
|
||||
}
|
||||
_writeToLogFile(aqh->logFile, GWEN_Buffer_GetStart(dbuf));
|
||||
GWEN_Buffer_free(dbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _writeToLogFile(const char *filename, const char *txt)
|
||||
{
|
||||
if (txt && *txt) {
|
||||
FILE *f;
|
||||
|
||||
f=fopen(filename, "a+");
|
||||
if (f) {
|
||||
if (1!=fwrite(txt, strlen(txt), 1, f)) {
|
||||
DBG_ERROR(AQH_LOGDOMAIN, "Error logging.");
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,11 +6,18 @@
|
||||
* should have received along with this file.
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#ifndef AQHOMED_TTY_LOG_H
|
||||
#define AQHOMED_TTY_LOG_H
|
||||
|
||||
|
||||
#include "./aqhomed.h"
|
||||
|
||||
|
||||
|
||||
void AqHomed_LogTtyMsg(AQHOMED *aqh, const GWEN_MSG *msg);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#include <aqhome/ipc/msg_ipc.h>
|
||||
|
||||
|
||||
73
apps/aqhome-nodes/types/0BUILD
Normal file
73
apps/aqhome-nodes/types/0BUILD
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml?>
|
||||
|
||||
<gwbuild>
|
||||
|
||||
<target type="ConvenienceLibrary" name="aqhnodes_types" >
|
||||
|
||||
<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" >
|
||||
device.t2d
|
||||
value.t2d
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_sources" >
|
||||
device.c
|
||||
value.c
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_pub">
|
||||
</setVar>
|
||||
|
||||
<setVar name="local/built_headers_priv" >
|
||||
device.h
|
||||
device_p.h
|
||||
value.h
|
||||
value_p.h
|
||||
</setVar>
|
||||
|
||||
<headers dist="true" >
|
||||
</headers>
|
||||
|
||||
<sources>
|
||||
$(local/typefiles)
|
||||
</sources>
|
||||
|
||||
<useTargets>
|
||||
</useTargets>
|
||||
|
||||
<libraries>
|
||||
</libraries>
|
||||
|
||||
<subdirs>
|
||||
</subdirs>
|
||||
|
||||
|
||||
<extradist>
|
||||
</extradist>
|
||||
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
</gwbuild>
|
||||
|
||||
|
||||
87
apps/aqhome-nodes/types/device.t2d
Normal file
87
apps/aqhome-nodes/types/device.t2d
Normal file
@@ -0,0 +1,87 @@
|
||||
<?xml?>
|
||||
|
||||
<tm2>
|
||||
<type id="AQHNODE_DEVICE" type="pointer">
|
||||
<descr>
|
||||
This object and its objects are used to store registered devices and definitions for possible new devices.
|
||||
</descr>
|
||||
<lang id="c">
|
||||
<identifier>AQHNODE_DEVICE</identifier>
|
||||
<prefix>AQHNODE_Device</prefix>
|
||||
<baseFileName>device</baseFileName>
|
||||
|
||||
<flags>
|
||||
with_list1
|
||||
with_list2
|
||||
</flags>
|
||||
|
||||
<headers>
|
||||
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||
<header type="sys" loc="pre">aqhome-nodes/types/value.h</header>
|
||||
</headers>
|
||||
|
||||
<inlines>
|
||||
</inlines>
|
||||
|
||||
|
||||
|
||||
</lang>
|
||||
|
||||
|
||||
<enums>
|
||||
</enums>
|
||||
|
||||
|
||||
<members>
|
||||
|
||||
<member name="name" type="char_ptr" maxlen="128">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own with_getbymember</flags>
|
||||
</member>
|
||||
|
||||
<member name="driver" type="char_ptr" maxlen="64">
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
</member>
|
||||
|
||||
<member name="manufacturer" type="uint32_t" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="deviceType" type="uint16_t" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
<member name="deviceVersion" type="uint16_t" maxlen="8">
|
||||
<default>0</default>
|
||||
<preset>0</preset>
|
||||
<access>public</access>
|
||||
<flags></flags>
|
||||
</member>
|
||||
|
||||
|
||||
<member name="valueList" type="AQHNODE_VALUE_LIST" >
|
||||
<default>NULL</default>
|
||||
<preset>NULL</preset>
|
||||
<access>public</access>
|
||||
<flags>own</flags>
|
||||
<getflags>none</getflags>
|
||||
<setflags>none</setflags>
|
||||
</member>
|
||||
|
||||
</members>
|
||||
|
||||
</type>
|
||||
|
||||
</tm2>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user