removed old code.
aqhome-storage has long been incorporated into aqhome-data.
This commit is contained in:
1
apps/aqhome-storage/.gitignore
vendored
1
apps/aqhome-storage/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
test/
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
<?xml?>
|
|
||||||
|
|
||||||
<gwbuild>
|
|
||||||
|
|
||||||
<target type="Program" name="aqhome-storage" install="$(bindir)" >
|
|
||||||
|
|
||||||
<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" >
|
|
||||||
aqhomestorage_p.h
|
|
||||||
aqhomestorage.h
|
|
||||||
init.h
|
|
||||||
init_http.h
|
|
||||||
init_mqtt.h
|
|
||||||
fini.h
|
|
||||||
loop.h
|
|
||||||
loop_http.h
|
|
||||||
loop_mqtt.h
|
|
||||||
cleanup.h
|
|
||||||
u_base.h
|
|
||||||
u_login.h
|
|
||||||
u_objects.h
|
|
||||||
u_objects_p.h
|
|
||||||
u_rooms.h
|
|
||||||
u_devices.h
|
|
||||||
u_mqtttopics.h
|
|
||||||
u_values.h
|
|
||||||
u_static.h
|
|
||||||
u_static_p.h
|
|
||||||
aqhomehttp.h
|
|
||||||
aqhomehttp_p.h
|
|
||||||
</headers>
|
|
||||||
|
|
||||||
<sources>
|
|
||||||
$(local/typefiles)
|
|
||||||
|
|
||||||
aqhomestorage.c
|
|
||||||
init.c
|
|
||||||
init_http.c
|
|
||||||
init_mqtt.c
|
|
||||||
fini.c
|
|
||||||
loop.c
|
|
||||||
loop_http.c
|
|
||||||
loop_mqtt.c
|
|
||||||
cleanup.c
|
|
||||||
u_base.c
|
|
||||||
u_login.c
|
|
||||||
u_objects.c
|
|
||||||
u_rooms.c
|
|
||||||
u_devices.c
|
|
||||||
u_mqtttopics.c
|
|
||||||
u_values.c
|
|
||||||
u_static.c
|
|
||||||
main.c
|
|
||||||
aqhomehttp.c
|
|
||||||
</sources>
|
|
||||||
|
|
||||||
<useTargets>
|
|
||||||
aqhome
|
|
||||||
</useTargets>
|
|
||||||
|
|
||||||
<libraries>
|
|
||||||
$(gwenhywfar_libs)
|
|
||||||
</libraries>
|
|
||||||
|
|
||||||
<subdirs>
|
|
||||||
</subdirs>
|
|
||||||
|
|
||||||
|
|
||||||
<extradist>
|
|
||||||
</extradist>
|
|
||||||
|
|
||||||
|
|
||||||
</target>
|
|
||||||
|
|
||||||
|
|
||||||
</gwbuild>
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
- isolate storage service:
|
|
||||||
- remove http service from here
|
|
||||||
- add ipc service
|
|
||||||
- admin:
|
|
||||||
- add room/device/MQTT topic/value
|
|
||||||
- edit room/device/MQTT topic/value
|
|
||||||
- del room/device/MQTT topic/value
|
|
||||||
- get received topics
|
|
||||||
- list rooms/devices/MQTT topics/values
|
|
||||||
- getValues(valueId, timeFrom, timeUntil)
|
|
||||||
- addValue(valueId/valueName, timeStamp, value)
|
|
||||||
- aqhome-tool
|
|
||||||
- add ipc admin code to connect to ipc service
|
|
||||||
- create http service as stand-alone app or create PHP code which uses aqhome-tool
|
|
||||||
- connect to storage service for information/admin
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- move http service into own folder
|
|
||||||
- isolate functions:
|
|
||||||
- getRoomList
|
|
||||||
- getDeviceList
|
|
||||||
- getTopicList
|
|
||||||
- addRoom/Device/Topic/Value
|
|
||||||
- delRoom/Device/Topic/Value
|
|
||||||
- editRoom/Device/Topic/Value
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- aqhome-storage->aqhome-data
|
|
||||||
|
|
||||||
- aqhome-data
|
|
||||||
- only list of values
|
|
||||||
- manages datafiles only
|
|
||||||
- IPC (later secure ipc):
|
|
||||||
- get value list
|
|
||||||
- add value
|
|
||||||
- del value
|
|
||||||
- edit value
|
|
||||||
|
|
||||||
- add datapoint(valueId, timestamp, data)
|
|
||||||
- add datapoint(valueName, timestamp, data)
|
|
||||||
|
|
||||||
- getData(valueId, timeFrom, timeUntil)
|
|
||||||
- getLastData(valueId)
|
|
||||||
|
|
||||||
- aqhome-tool:
|
|
||||||
- add ipc code
|
|
||||||
|
|
||||||
- aqhome-mqttdata:
|
|
||||||
- use devices, topics and values from aqhome-storage
|
|
||||||
- derive valueid and data from mqtt messages
|
|
||||||
- send data to aqhome-data via ipc (later secure ipc)
|
|
||||||
|
|
||||||
|
|
||||||
- mqtt values:
|
|
||||||
- aliases (e.g. for doors: open=1.0, closed=0.0, tilted=0.5)
|
|
||||||
|
|
||||||
|
|
||||||
- later services only:
|
|
||||||
- aqhomed (tty, ipcd)
|
|
||||||
- aqhome-data (ipcd)
|
|
||||||
- aqhome-mqtt (mqttc, ipcd)
|
|
||||||
- aqhome-httpd (maybe; httpd, ipcc)
|
|
||||||
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomehttp_p.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/db.h>
|
|
||||||
#include <gwenhywfar/buffer.h>
|
|
||||||
#include <gwenhywfar/text.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_INHERIT(AQH_SERVICE, AQHOME_HTTP)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
void AqHomeHttpService_Extend(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
GWEN_NEW_OBJECT(AQHOME_HTTP, xsv);
|
|
||||||
GWEN_INHERIT_SETDATA(AQH_SERVICE, AQHOME_HTTP, sv, xsv, _freeData);
|
|
||||||
|
|
||||||
xsv->contentTree=AQH_HttpContent_new("root");
|
|
||||||
xsv->storageMutex=GWEN_Mutex_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _freeData(void *bp, void *p)
|
|
||||||
{
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=(AQHOME_HTTP*) p;
|
|
||||||
|
|
||||||
xsv->storage=NULL;
|
|
||||||
AQH_HttpContent_free(xsv->contentTree);
|
|
||||||
xsv->contentTree=NULL;
|
|
||||||
GWEN_Mutex_free(xsv->storageMutex);
|
|
||||||
|
|
||||||
GWEN_FREE_OBJECT(xsv);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv)
|
|
||||||
return xsv->storage;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeHttpService_SetStorage(AQH_SERVICE *sv, AQH_STORAGE *sto)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv)
|
|
||||||
xsv->storage=sto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_CONTENT *AqHomeHttpService_GetContentTree(const AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv)
|
|
||||||
return xsv->contentTree;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeHttpService_SetContentTree(AQH_SERVICE *sv, AQH_HTTP_CONTENT *c)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv) {
|
|
||||||
AQH_HttpContent_free(xsv->contentTree);
|
|
||||||
xsv->contentTree=c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeHttpService_MarkStorageChanged(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv) {
|
|
||||||
AQH_Storage_AddRuntimeFlags(xsv->storage, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeHttpService_LockStorage(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=GWEN_Mutex_Lock(xsv->storageMutex);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error obtaining lock on storage mutex");
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeHttpService_UnlockStorage(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
if (sv) {
|
|
||||||
AQHOME_HTTP *xsv;
|
|
||||||
|
|
||||||
xsv=GWEN_INHERIT_GETDATA(AQH_SERVICE, AQHOME_HTTP, sv);
|
|
||||||
if (xsv) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=GWEN_Mutex_Unlock(xsv->storageMutex);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error releasing lock on storage mutex");
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_HTTP_H
|
|
||||||
#define AQHOME_HTTP_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/service/service.h"
|
|
||||||
#include "aqhome/data/storage.h"
|
|
||||||
#include "aqhome/http/content.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
#define AQHOME_HTTP_PERMS_LIST_ROOMS 0x00000001
|
|
||||||
#define AQHOME_HTTP_PERMS_LIST_DEVICES 0x00000002
|
|
||||||
#define AQHOME_HTTP_PERMS_LIST_VALUES 0x00000004
|
|
||||||
#define AQHOME_HTTP_PERMS_LIST_TOPICS 0x00000008
|
|
||||||
|
|
||||||
#define AQHOME_HTTP_PERMS_ADD_ROOM 0x00000100
|
|
||||||
#define AQHOME_HTTP_PERMS_ADD_DEVICE 0x00000200
|
|
||||||
#define AQHOME_HTTP_PERMS_ADD_VALUE 0x00000400
|
|
||||||
#define AQHOME_HTTP_PERMS_ADD_TOPIC 0x00000800
|
|
||||||
|
|
||||||
#define AQHOME_HTTP_PERMS_DEL_ROOM 0x00010000
|
|
||||||
#define AQHOME_HTTP_PERMS_DEL_DEVICE 0x00020000
|
|
||||||
#define AQHOME_HTTP_PERMS_DEL_VALUE 0x00040000
|
|
||||||
#define AQHOME_HTTP_PERMS_DEL_TOPIC 0x00080000
|
|
||||||
|
|
||||||
#define AQHOME_HTTP_PERMS_EDIT_ROOM 0x01000000
|
|
||||||
#define AQHOME_HTTP_PERMS_EDIT_DEVICE 0x02000000
|
|
||||||
#define AQHOME_HTTP_PERMS_EDIT_VALUE 0x04000000
|
|
||||||
#define AQHOME_HTTP_PERMS_EDIT_TOPIC 0x08000000
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeHttpService_Extend(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
AQH_STORAGE *AqHomeHttpService_GetStorage(const AQH_SERVICE *sv);
|
|
||||||
void AqHomeHttpService_SetStorage(AQH_SERVICE *sv, AQH_STORAGE *sto);
|
|
||||||
|
|
||||||
AQH_HTTP_CONTENT *AqHomeHttpService_GetContentTree(const AQH_SERVICE *sv);
|
|
||||||
void AqHomeHttpService_SetContentTree(AQH_SERVICE *sv, AQH_HTTP_CONTENT *c);
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeHttpService_LockStorage(AQH_SERVICE *sv);
|
|
||||||
int AqHomeHttpService_UnlockStorage(AQH_SERVICE *sv);
|
|
||||||
void AqHomeHttpService_MarkStorageChanged(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_HTTP_P_H
|
|
||||||
#define AQHOME_HTTP_P_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/mutex.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct AQHOME_HTTP AQHOME_HTTP;
|
|
||||||
struct AQHOME_HTTP {
|
|
||||||
AQH_STORAGE *storage; /* do not release */
|
|
||||||
GWEN_MUTEX *storageMutex;
|
|
||||||
|
|
||||||
AQH_HTTP_CONTENT *contentTree;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/misc.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQHOME_STORAGE *AqHomeStorage_new()
|
|
||||||
{
|
|
||||||
AQHOME_STORAGE *aqh;
|
|
||||||
|
|
||||||
GWEN_NEW_OBJECT(AQHOME_STORAGE, aqh);
|
|
||||||
aqh->rootEndpoint=GWEN_MsgEndpoint_new("root", 0);
|
|
||||||
|
|
||||||
return aqh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_free(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
if (aqh) {
|
|
||||||
AQH_Service_free(aqh->httpService);
|
|
||||||
aqh->httpService=NULL;
|
|
||||||
AQH_Storage_free(aqh->storage);
|
|
||||||
aqh->storage=NULL;
|
|
||||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
|
||||||
aqh->rootEndpoint=NULL;
|
|
||||||
aqh->ipcdEndpoint=NULL;
|
|
||||||
aqh->mqttEndpoint=NULL;
|
|
||||||
aqh->httpdEndpoint=NULL;
|
|
||||||
GWEN_DB_Group_free(aqh->dbArgs);
|
|
||||||
aqh->dbArgs=NULL;
|
|
||||||
free(aqh->pidFile);
|
|
||||||
|
|
||||||
GWEN_FREE_OBJECT(aqh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetRootEndpoint(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?(aqh->rootEndpoint):NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetIpcdEndpoint(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?(aqh->ipcdEndpoint):NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetMqttEndpoint(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?(aqh->mqttEndpoint):NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetHttpdEndpoint(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?(aqh->httpdEndpoint):NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_DB_NODE *AqHomeStorage_GetDbArgs(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?(aqh->dbArgs):NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_STORAGE *AqHomeStorage_GetStorage(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?(aqh->storage):NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *AqHomeStorage_GetPidFile(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?aqh->pidFile:NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_SetPidFile(AQHOME_STORAGE *aqh, const char *s)
|
|
||||||
{
|
|
||||||
if (aqh) {
|
|
||||||
free(aqh->pidFile);
|
|
||||||
aqh->pidFile=s?strdup(s):NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_GetTimeout(const AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
return aqh?aqh->timeout:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_H
|
|
||||||
#define AQHOME_STORAGE_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/data/storage.h"
|
|
||||||
#include "aqhome/service/session.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct AQHOME_STORAGE AQHOME_STORAGE;
|
|
||||||
|
|
||||||
|
|
||||||
AQHOME_STORAGE *AqHomeStorage_new();
|
|
||||||
void AqHomeStorage_free(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetRootEndpoint(const AQHOME_STORAGE *aqh);
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetIpcdEndpoint(const AQHOME_STORAGE *aqh);
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetMqttEndpoint(const AQHOME_STORAGE *aqh);
|
|
||||||
GWEN_MSG_ENDPOINT *AqHomeStorage_GetHttpdEndpoint(const AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
GWEN_DB_NODE *AqHomeStorage_GetDbArgs(const AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
AQH_STORAGE *AqHomeStorage_GetStorage(const AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
const char *AqHomeStorage_GetPidFile(const AQHOME_STORAGE *aqh);
|
|
||||||
void AqHomeStorage_SetPidFile(AQHOME_STORAGE *aqh, const char *s);
|
|
||||||
|
|
||||||
int AqHomeStorage_GetTimeout(const AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_P_H
|
|
||||||
#define AQHOME_STORAGE_P_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* default values */
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_PIDFILE "/var/run/aqhome-storage.pid"
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_IPC_PORT 45455
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_HTTP_PORT 45456
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_MQTT_CLIENTID "AQHOMESTORAGE"
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_MQTT_KEEPALIVE 600
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_MQTT_PORT 1883
|
|
||||||
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_CONFIGDIR "/var/lib/aqhomestorage/config"
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR "/var/lib/aqhomestorage/html"
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_DATADIR "/var/lib/aqhomestorage/data"
|
|
||||||
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_STATEFILE "/var/lib/aqhomestorage/config/statefile"
|
|
||||||
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_MAXSESSIONAGE (30*60)
|
|
||||||
|
|
||||||
#define AQHOME_STORAGE_SITEHEADER "site-header.html"
|
|
||||||
#define AQHOME_STORAGE_SITEFOOTER "site-footer.html"
|
|
||||||
|
|
||||||
#define AQHOME_STORAGE_STATIC_RELFOLDER "static"
|
|
||||||
|
|
||||||
|
|
||||||
struct AQHOME_STORAGE {
|
|
||||||
GWEN_MSG_ENDPOINT *rootEndpoint;
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *ipcdEndpoint; /* don't release, will be released by freeing rootEndpoint! */
|
|
||||||
GWEN_MSG_ENDPOINT *mqttEndpoint; /* don't release, will be released by freeing rootEndpoint! */
|
|
||||||
GWEN_MSG_ENDPOINT *httpdEndpoint; /* don't release, will be released by freeing rootEndpoint! */
|
|
||||||
|
|
||||||
GWEN_DB_NODE *dbArgs;
|
|
||||||
|
|
||||||
AQH_SERVICE *httpService;
|
|
||||||
AQH_STORAGE *storage;
|
|
||||||
|
|
||||||
char *pidFile;
|
|
||||||
|
|
||||||
int maxSessionAgeInSeconds;
|
|
||||||
|
|
||||||
int timeout; /* timeout for run e.g. inside valgrind */
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./cleanup.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_Cleanup(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=AQH_HttpService_CleanupSessions(aqh->httpService, aqh->maxSessionAgeInSeconds);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_CLEANUP_H
|
|
||||||
#define AQHOME_STORAGE_CLEANUP_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_Cleanup(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./fini.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint_tcpd.h>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void _disconnectTree(GWEN_MSG_ENDPOINT *ep);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
void AqHomeStorage_Fini(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
if (aqh) {
|
|
||||||
if (aqh->rootEndpoint) {
|
|
||||||
_disconnectTree(aqh->rootEndpoint);
|
|
||||||
GWEN_MsgEndpoint_Disconnect(aqh->rootEndpoint);
|
|
||||||
}
|
|
||||||
GWEN_MsgEndpoint_free(aqh->rootEndpoint);
|
|
||||||
aqh->rootEndpoint=NULL;
|
|
||||||
aqh->ipcdEndpoint=NULL;
|
|
||||||
aqh->httpdEndpoint=NULL;
|
|
||||||
aqh->mqttEndpoint=NULL;
|
|
||||||
|
|
||||||
if (aqh->pidFile)
|
|
||||||
remove(aqh->pidFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _disconnectTree(GWEN_MSG_ENDPOINT *ep)
|
|
||||||
{
|
|
||||||
GWEN_MSG_ENDPOINT *epChild;
|
|
||||||
|
|
||||||
epChild=GWEN_MsgEndpoint_Tree2_GetFirstChild(ep);
|
|
||||||
while(epChild) {
|
|
||||||
_disconnectTree(epChild);
|
|
||||||
epChild=GWEN_MsgEndpoint_Tree2_GetNext(epChild);
|
|
||||||
} /* while */
|
|
||||||
|
|
||||||
GWEN_MsgEndpoint_Disconnect(ep);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_FINI_H
|
|
||||||
#define AQHOME_STORAGE_FINI_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_Fini(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
|
|
||||||
<html>
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<!-- copyright (c) 2023 by martin -->
|
|
||||||
<meta name="generator" content="FTE 1.1" />
|
|
||||||
<meta name="revised" content="martin,2023-07-23" />
|
|
||||||
<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 Storage Service</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
@@ -1,506 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./init.h"
|
|
||||||
#include "./init_http.h"
|
|
||||||
#include "./init_mqtt.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
|
|
||||||
#include "aqhome/msg/endpoint_tty.h"
|
|
||||||
#include "aqhome/ipc/endpoint_ipc.h"
|
|
||||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
|
||||||
#include "aqhome/http/endpoint_http.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint_tcpd.h>
|
|
||||||
#include <gwenhywfar/endpoint_msgio.h>
|
|
||||||
#include <gwenhywfar/directory.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
|
||||||
# include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
|
||||||
# include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
//#define I18N(msg) msg
|
|
||||||
#define I18S(msg) msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _setupFolders(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
|
||||||
|
|
||||||
static int _setupStorage(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
|
||||||
|
|
||||||
static void _setupIpc(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
|
||||||
|
|
||||||
static GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
|
||||||
|
|
||||||
static int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs);
|
|
||||||
static int _createPidFile(const char *pidFilename);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
int AqHomeStorage_Init(AQHOME_STORAGE *aqh, int argc, char **argv)
|
|
||||||
{
|
|
||||||
GWEN_DB_NODE *dbArgs;
|
|
||||||
int rv;
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
dbArgs=GWEN_DB_Group_new("args");
|
|
||||||
rv=_readArgs(argc, argv, dbArgs);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error reading args (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
aqh->dbArgs=dbArgs;
|
|
||||||
|
|
||||||
aqh->maxSessionAgeInSeconds=GWEN_DB_GetIntValue(dbArgs, "maxSessionAge", 0, AQHOME_STORAGE_DEFAULT_MAXSESSIONAGE);
|
|
||||||
aqh->timeout=GWEN_DB_GetIntValue(dbArgs, "timeout", 0, 0);
|
|
||||||
|
|
||||||
s=GWEN_DB_GetCharValue(dbArgs, "pidfile", 0, AQHOME_STORAGE_DEFAULT_PIDFILE);
|
|
||||||
if (s && *s) {
|
|
||||||
AqHomeStorage_SetPidFile(aqh, s);
|
|
||||||
rv=_createPidFile(s);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error creating PID file (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_setupFolders(aqh, dbArgs);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_setupStorage(aqh, dbArgs);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
_setupIpc(aqh, dbArgs);
|
|
||||||
|
|
||||||
rv=AqHomeStorage_SetupMqtt(aqh, dbArgs);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeStorage_SetupHttp(aqh, dbArgs);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _setupFolders(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
const char *s;
|
|
||||||
GWEN_BUFFER *nameBuf;
|
|
||||||
int pos;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
s=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
|
|
||||||
if (!(s && *s)) {
|
|
||||||
DBG_ERROR(NULL, "Missing configuration folder");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, s);
|
|
||||||
pos=GWEN_Buffer_GetPos(nameBuf);
|
|
||||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error accessing configuration folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
GWEN_Buffer_Crop(nameBuf, 0, pos);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S "modules");
|
|
||||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error accessing modules folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
GWEN_Buffer_Crop(nameBuf, 0, pos);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S "users");
|
|
||||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf), GWEN_PATH_FLAGS_CHECKROOT);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error accessing configuration folder \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _setupStorage(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
const char *dataFolder;
|
|
||||||
const char *stateFile;
|
|
||||||
|
|
||||||
dataFolder=GWEN_DB_GetCharValue(dbArgs, "dataFolder", 0, AQHOME_STORAGE_DEFAULT_DATADIR);
|
|
||||||
stateFile=GWEN_DB_GetCharValue(dbArgs, "stateFile", 0, NULL);
|
|
||||||
if (stateFile && *stateFile) {
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sto=AQH_Storage_new();
|
|
||||||
AQH_Storage_SetStateFile(sto, stateFile);
|
|
||||||
|
|
||||||
AQH_Storage_SetDataFileFolder(sto, (dataFolder && *dataFolder)?dataFolder:NULL);
|
|
||||||
|
|
||||||
rv=AQH_Storage_Init(sto);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
AQH_Storage_free(sto);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
aqh->storage=sto;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "No state file given");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _setupIpc(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
const char *tcpAddress;
|
|
||||||
int tcpPort;
|
|
||||||
|
|
||||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "tcpAddress", 0, NULL);
|
|
||||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "tcpPort", 0, AQHOME_STORAGE_DEFAULT_IPC_PORT);
|
|
||||||
|
|
||||||
if (tcpAddress && *tcpAddress && tcpPort) {
|
|
||||||
GWEN_MSG_ENDPOINT *ep;
|
|
||||||
|
|
||||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
|
|
||||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptIpcFn, aqh);
|
|
||||||
|
|
||||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
|
||||||
aqh->ipcdEndpoint=ep;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *_acceptIpcFn(GWEN_MSG_ENDPOINT *ep,
|
|
||||||
GWEN_SOCKET *sk,
|
|
||||||
const GWEN_INETADDRESS *addr,
|
|
||||||
GWEN_UNUSED void *data)
|
|
||||||
{
|
|
||||||
/* AQHOME_STORAGE *aqh;
|
|
||||||
*
|
|
||||||
* aqh=(AQHOME_STORAGE*) data;
|
|
||||||
*/
|
|
||||||
DBG_INFO(NULL, "Incoming IPC connection");
|
|
||||||
return AQH_IpcEndpoint_CreateIpcTcpServiceForSocket(sk, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createPidFile(const char *pidFilename)
|
|
||||||
{
|
|
||||||
FILE *f;
|
|
||||||
int pidfd;
|
|
||||||
|
|
||||||
if (remove(pidFilename)==0) {
|
|
||||||
DBG_ERROR(0, "Old PID file existed, removed. (Unclean shutdown?)");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
|
||||||
pidfd = open(pidFilename, O_EXCL|O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
|
||||||
if (pidfd < 0) {
|
|
||||||
DBG_ERROR(NULL, "Could not create PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = fdopen(pidfd, "w");
|
|
||||||
#else /* HAVE_STAT_H */
|
|
||||||
f=fopen(pidFilename,"w+");
|
|
||||||
#endif /* HAVE_STAT_H */
|
|
||||||
|
|
||||||
/* write pid */
|
|
||||||
#ifdef HAVE_GETPID
|
|
||||||
fprintf(f,"%d\n",getpid());
|
|
||||||
#else
|
|
||||||
fprintf(f,"-1\n");
|
|
||||||
#endif
|
|
||||||
if (fclose(f)) {
|
|
||||||
DBG_ERROR(0, "Could not close PID file \"%s\" (%s), aborting.", pidFilename, strerror(errno));
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _readArgs(int argc, char **argv, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
const GWEN_ARGS args[]= {
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Char, /* type */
|
|
||||||
"cfgdir", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"D", /* short option */
|
|
||||||
"cfgdir", /* long option */
|
|
||||||
I18S("Specify the configuration folder"),
|
|
||||||
I18S("Specify the configuration folder")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Char, /* type */
|
|
||||||
"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 */
|
|
||||||
"mqttAddress", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"ma", /* short option */
|
|
||||||
"mqttaddress", /* long option */
|
|
||||||
I18S("Specify the address of the MQTT server to connect to (disabled if missing)"),
|
|
||||||
I18S("Specify the address of the MQTT server to connect to (disabled if missing)")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Int, /* type */
|
|
||||||
"mqttPort", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"mp", /* short option */
|
|
||||||
"mqttport", /* long option */
|
|
||||||
I18S("Specify the port of the MQTT server (default: 1883)"),
|
|
||||||
I18S("Specify the port of the MQTT server (default: 1883)")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Char, /* type */
|
|
||||||
"mqttClientId", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
NULL, /* short option */
|
|
||||||
"mqttclientid", /* long option */
|
|
||||||
I18S("Specify client id for the MQTT server (default: \"AQHOMESTORAGE\")"),
|
|
||||||
I18S("Specify client id for the MQTT server (default: \"AQHOMESTORAGE\")")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Int, /* type */
|
|
||||||
"mqttKeepAlive", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"mk", /* short option */
|
|
||||||
"mqttkeepalive", /* long option */
|
|
||||||
I18S("Specify keepalive time in seconds (defaults: 600)"),
|
|
||||||
I18S("Specify keepalive time in seconds (defaults: 600)")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Char, /* type */
|
|
||||||
"httpAddress", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"ha", /* short option */
|
|
||||||
"httpaddress", /* long option */
|
|
||||||
I18S("Specify the address to bind the http service to (disabled if missing)"),
|
|
||||||
I18S("Specify the address to bind the http service to (disabled if missing)")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Int, /* type */
|
|
||||||
"httpPort", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"hp", /* short option */
|
|
||||||
"httpport", /* long option */
|
|
||||||
I18S("Specify the port to listen on for HTTP connections"),
|
|
||||||
I18S("Specify the port to listen on for HTTP connections")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Int, /* type */
|
|
||||||
"maxSessionAge", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
NULL, /* short option */
|
|
||||||
"maxsessionage", /* long option */
|
|
||||||
I18S("Specify maximum session age in seconds (default: 30mins)"),
|
|
||||||
I18S("Specify maximum session age in seconds (default: 30mins)")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Char, /* type */
|
|
||||||
"sourcefolder", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
NULL, /* short option */
|
|
||||||
"sourcefolder", /* long option */
|
|
||||||
I18S("Folder where static HTML source files are stored"),
|
|
||||||
I18S("Folder where static HTML source files are stored")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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 */
|
|
||||||
"statefile", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"S", /* short option */
|
|
||||||
"statefile", /* long option */
|
|
||||||
I18S("File where rooms, devices and values etc. are stored"),
|
|
||||||
I18S("File where rooms, devices and values etc. are stored")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Char, /* type */
|
|
||||||
"pidfile", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"p", /* short option */
|
|
||||||
"pidfile", /* long option */
|
|
||||||
I18S("Specify the PID file"),
|
|
||||||
I18S("Specify the PID file")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
|
|
||||||
GWEN_ArgsType_Int, /* type */
|
|
||||||
"timeout", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
1, /* maxnum */
|
|
||||||
"T", /* short option */
|
|
||||||
"timeout", /* long option */
|
|
||||||
I18S("Specify timeout in second (default: no timeout)"),
|
|
||||||
I18S("Specify timeout in second (default: no timeout)")
|
|
||||||
},
|
|
||||||
{
|
|
||||||
GWEN_ARGS_FLAGS_HELP | GWEN_ARGS_FLAGS_LAST, /* flags */
|
|
||||||
GWEN_ArgsType_Int, /* type */
|
|
||||||
"help", /* name */
|
|
||||||
0, /* minnum */
|
|
||||||
0, /* maxnum */
|
|
||||||
"h", /* short option */
|
|
||||||
"help",
|
|
||||||
I18S("Show this help screen."),
|
|
||||||
I18S("Show this help screen.")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
rv=GWEN_Args_Check(argc, argv, 1, 0, args, dbArgs);
|
|
||||||
if (rv==GWEN_ARGS_RESULT_ERROR) {
|
|
||||||
fprintf(stderr, "ERROR: Could not parse arguments main\n");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
else if (rv==GWEN_ARGS_RESULT_HELP) {
|
|
||||||
GWEN_BUFFER *ubuf;
|
|
||||||
|
|
||||||
ubuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
|
||||||
GWEN_Buffer_AppendArgs(ubuf,
|
|
||||||
I18N("This is version %s.\nUsage: %s [OPTIONS]\n\nOptions:\n"),
|
|
||||||
AQHOME_VERSION_STRING,
|
|
||||||
argv[0]);
|
|
||||||
if (GWEN_Args_Usage(args, ubuf, GWEN_ArgsOutType_Txt)) {
|
|
||||||
fprintf(stderr, "ERROR: Could not create help string\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(ubuf, "\n");
|
|
||||||
|
|
||||||
fprintf(stdout, "%s\n", GWEN_Buffer_GetStart(ubuf));
|
|
||||||
GWEN_Buffer_free(ubuf);
|
|
||||||
return GWEN_ERROR_CLOSE;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_INIT_H
|
|
||||||
#define AQHOME_STORAGE_INIT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_Init(AQHOME_STORAGE *aqh, int argc, char **argv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,336 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./init_http.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "./u_login.h"
|
|
||||||
#include "./u_rooms.h"
|
|
||||||
#include "./u_devices.h"
|
|
||||||
#include "./u_mqtttopics.h"
|
|
||||||
#include "./u_values.h"
|
|
||||||
#include "./u_static.h"
|
|
||||||
|
|
||||||
#include "aqhome/msg/endpoint_tty.h"
|
|
||||||
#include "aqhome/ipc/endpoint_ipc.h"
|
|
||||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
|
||||||
#include "aqhome/http/endpoint_http.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
#include "aqhome/http/content_files.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint_tcpd.h>
|
|
||||||
#include <gwenhywfar/endpoint_msgio.h>
|
|
||||||
#include <gwenhywfar/directory.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
|
||||||
# include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
|
||||||
# include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
//#define I18N(msg) msg
|
|
||||||
#define I18S(msg) msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort);
|
|
||||||
static int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
|
||||||
static int _createContentRoot(AQHOME_STORAGE *aqh);
|
|
||||||
static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, const GWEN_INETADDRESS *addr, void *data);
|
|
||||||
|
|
||||||
static int _createUrlHandler_login(AQHOME_STORAGE *aqh);
|
|
||||||
static int _createUrlHandler_rooms(AQHOME_STORAGE *aqh);
|
|
||||||
static int _createUrlHandler_devices(AQHOME_STORAGE *aqh);
|
|
||||||
static int _createUrlHandler_topics(AQHOME_STORAGE *aqh);
|
|
||||||
static int _createUrlHandler_values(AQHOME_STORAGE *aqh);
|
|
||||||
static int _createUrlHandler_static(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
const char *tcpAddress;
|
|
||||||
int tcpPort;
|
|
||||||
|
|
||||||
tcpAddress=GWEN_DB_GetCharValue(dbArgs, "httpAddress", 0, NULL);
|
|
||||||
tcpPort=GWEN_DB_GetIntValue(dbArgs, "httpPort", 0, AQHOME_STORAGE_DEFAULT_HTTP_PORT);
|
|
||||||
|
|
||||||
if (tcpAddress && *tcpAddress && tcpPort) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
_setupEndpoint(aqh, tcpAddress, tcpPort);
|
|
||||||
rv=_setupHttpService(aqh, dbArgs);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_createContentRoot(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_createUrlHandler_login(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_createUrlHandler_rooms(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_createUrlHandler_devices(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
rv=_createUrlHandler_topics(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_createUrlHandler_values(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_createUrlHandler_static(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _setupEndpoint(AQHOME_STORAGE *aqh, const char *tcpAddress, int tcpPort)
|
|
||||||
{
|
|
||||||
GWEN_MSG_ENDPOINT *ep;
|
|
||||||
|
|
||||||
ep=GWEN_TcpdEndpoint_new(tcpAddress, tcpPort, NULL, 0);
|
|
||||||
GWEN_TcpdEndpoint_SetAcceptFn(ep, _acceptHttpFn, aqh);
|
|
||||||
|
|
||||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
|
||||||
aqh->httpdEndpoint=ep;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _setupHttpService(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
const char *configFolder;
|
|
||||||
const char *sourceFolder;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
configFolder=GWEN_DB_GetCharValue(dbArgs, "cfgdir", 0, AQHOME_STORAGE_DEFAULT_CONFIGDIR);
|
|
||||||
sourceFolder=GWEN_DB_GetCharValue(dbArgs, "sourceFolder", 0, AQHOME_STORAGE_DEFAULT_HTTP_SOURCEDIR);
|
|
||||||
aqh->httpService=AQH_HttpService_new(configFolder, sourceFolder);
|
|
||||||
AqHomeHttpService_Extend(aqh->httpService);
|
|
||||||
AqHomeHttpService_SetStorage(aqh->httpService, aqh->storage);
|
|
||||||
rv=AQH_HttpService_LoadConfig(aqh->httpService);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error loading config for HTTP service (%d)", rv);
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
AQH_HttpService_LoadAllSessions(aqh->httpService);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep,
|
|
||||||
GWEN_SOCKET *sk,
|
|
||||||
const GWEN_INETADDRESS *addr,
|
|
||||||
GWEN_UNUSED void *data)
|
|
||||||
{
|
|
||||||
GWEN_MSG_ENDPOINT *epIncoming;
|
|
||||||
|
|
||||||
/* AQHOME_STORAGE *aqh;
|
|
||||||
*
|
|
||||||
* aqh=(AQHOME_STORAGE*) data;
|
|
||||||
*/
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Incoming HTTP connection");
|
|
||||||
epIncoming=GWEN_MsgEndpoint_new("http", 0);
|
|
||||||
GWEN_MsgEndpoint_SetSocket(epIncoming, sk);
|
|
||||||
GWEN_MsgIoEndpoint_Extend(epIncoming);
|
|
||||||
AQH_HttpEndpoint_Extend(epIncoming, AQH_ENDPOINT_HTTP_FLAGS_PASSIVE);
|
|
||||||
return epIncoming;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createContentRoot(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
const char *sourceFolder;
|
|
||||||
GWEN_BUFFER *nbuf1;
|
|
||||||
GWEN_BUFFER *nbuf2;
|
|
||||||
AQH_HTTP_CONTENT *c;
|
|
||||||
|
|
||||||
sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);
|
|
||||||
|
|
||||||
nbuf1=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
nbuf2=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendString(nbuf1, sourceFolder);
|
|
||||||
GWEN_Buffer_AppendString(nbuf1, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEHEADER);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendString(nbuf2, sourceFolder);
|
|
||||||
GWEN_Buffer_AppendString(nbuf2, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_SITEFOOTER);
|
|
||||||
|
|
||||||
c=AQH_HttpContentFiles_new("root", GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
|
|
||||||
if (c==NULL) {
|
|
||||||
DBG_INFO(NULL,
|
|
||||||
"Unable to create content for root (header=[%s], footer=[%s])",
|
|
||||||
GWEN_Buffer_GetStart(nbuf1), GWEN_Buffer_GetStart(nbuf2));
|
|
||||||
GWEN_Buffer_free(nbuf2);
|
|
||||||
GWEN_Buffer_free(nbuf1);
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
AqHomeHttpService_SetContentTree(aqh->httpService, c);
|
|
||||||
|
|
||||||
GWEN_Buffer_free(nbuf2);
|
|
||||||
GWEN_Buffer_free(nbuf1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createUrlHandler_login(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_LoginHttpUrlHandler_new(aqh->httpService);
|
|
||||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
|
||||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/login");
|
|
||||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createUrlHandler_rooms(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_RoomsHttpUrlHandler_new(aqh->httpService);
|
|
||||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
|
||||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/rooms/*");
|
|
||||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createUrlHandler_devices(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_DevicesHttpUrlHandler_new(aqh->httpService);
|
|
||||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
|
||||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/devices/*");
|
|
||||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createUrlHandler_topics(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_MqttTopicsHttpUrlHandler_new(aqh->httpService);
|
|
||||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
|
||||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/mqtttopics/*");
|
|
||||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createUrlHandler_values(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_ValuesHttpUrlHandler_new(aqh->httpService);
|
|
||||||
AQH_HttpUrlHandler_SetContentProvider(uh, AqHomeHttpService_GetContentTree(aqh->httpService));
|
|
||||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/values/*");
|
|
||||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _createUrlHandler_static(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
GWEN_BUFFER *nameBuf;
|
|
||||||
const char *sourceFolder;
|
|
||||||
|
|
||||||
sourceFolder=AQH_HttpService_GetSourceFolder(aqh->httpService);
|
|
||||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, sourceFolder);
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S AQHOME_STORAGE_STATIC_RELFOLDER GWEN_DIR_SEPARATOR_S "pics");
|
|
||||||
|
|
||||||
uh=AQH_StaticHttpUrlHandler_new(aqh->httpService, GWEN_Buffer_GetStart(nameBuf));
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
AQH_HttpUrlHandler_AddUrlPattern(uh, "/pics/*");
|
|
||||||
AQH_HttpService_AddUrlHandler(aqh->httpService, uh);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_INIT_HTTP_H
|
|
||||||
#define AQHOME_STORAGE_INIT_HTTP_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./init_mqtt.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "./u_login.h"
|
|
||||||
#include "./u_rooms.h"
|
|
||||||
#include "./u_devices.h"
|
|
||||||
#include "./u_mqtttopics.h"
|
|
||||||
#include "./u_values.h"
|
|
||||||
#include "./u_static.h"
|
|
||||||
|
|
||||||
#include "aqhome/msg/endpoint_tty.h"
|
|
||||||
#include "aqhome/ipc/endpoint_ipc.h"
|
|
||||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
|
||||||
#include <aqhome/mqtt/msg_mqtt_subscribe.h>
|
|
||||||
#include <aqhome/mqtt/msg_mqtt_suback.h>
|
|
||||||
#include "aqhome/http/endpoint_http.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
#include "aqhome/http/content_files.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint_tcpd.h>
|
|
||||||
#include <gwenhywfar/endpoint_msgio.h>
|
|
||||||
#include <gwenhywfar/directory.h>
|
|
||||||
#include <gwenhywfar/text.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
|
||||||
# include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
|
||||||
# include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
//#define I18N(msg) msg
|
|
||||||
#define I18S(msg) msg
|
|
||||||
|
|
||||||
#define AQHOME_STORAGE_DEFAULT_CMDTIMEOUT 10000
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _mqttConnect(GWEN_MSG_ENDPOINT *epTcp);
|
|
||||||
static int _subscribe(AQHOME_STORAGE *aqh, const char *topicFilter);
|
|
||||||
static GWEN_MSG *_awaitPacket(GWEN_MSG_ENDPOINT *epTcp, uint8_t expectedPacketType, int timeoutInSeconds);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_SetupMqtt(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs)
|
|
||||||
{
|
|
||||||
const char *mqttAddress;
|
|
||||||
int mqttPort;
|
|
||||||
const char *mqttClientId;
|
|
||||||
int mqttKeepAlive;
|
|
||||||
|
|
||||||
mqttAddress=GWEN_DB_GetCharValue(dbArgs, "mqttAddress", 0, NULL);
|
|
||||||
mqttPort=GWEN_DB_GetIntValue(dbArgs, "mqttPort", 0, AQHOME_STORAGE_DEFAULT_MQTT_PORT);
|
|
||||||
mqttClientId=GWEN_DB_GetCharValue(dbArgs, "mqttClientId", 0, AQHOME_STORAGE_DEFAULT_MQTT_CLIENTID);
|
|
||||||
mqttKeepAlive=GWEN_DB_GetIntValue(dbArgs, "mqttKeepAlive", 0, AQHOME_STORAGE_DEFAULT_MQTT_KEEPALIVE);
|
|
||||||
|
|
||||||
if (mqttAddress && *mqttAddress && mqttPort) {
|
|
||||||
GWEN_MSG_ENDPOINT *ep;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
ep=AQH_MqttClientEndpoint_new(mqttClientId, mqttAddress, mqttPort, NULL, 0);
|
|
||||||
AQH_MqttClientEndpoint_SetKeepAliveTime(ep, mqttKeepAlive);
|
|
||||||
|
|
||||||
GWEN_MsgEndpoint_Tree2_AddChild(aqh->rootEndpoint, ep);
|
|
||||||
aqh->mqttEndpoint=ep;
|
|
||||||
|
|
||||||
rv=_mqttConnect(ep);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error connecting to MQTT server %s:%d (%d)", mqttAddress, mqttPort, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_subscribe(aqh, "#");
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error subscribingconnecting to MQTT server %s:%d (%d)", mqttAddress, mqttPort, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _mqttConnect(GWEN_MSG_ENDPOINT *epTcp)
|
|
||||||
{
|
|
||||||
if (GWEN_MsgEndpoint_GetState(epTcp)==GWEN_MSG_ENDPOINT_STATE_UNCONNECTED) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=AQH_MqttClientEndpoint_StartConnect(epTcp);
|
|
||||||
if (rv<0 && rv!=GWEN_ERROR_IN_PROGRESS) {
|
|
||||||
DBG_ERROR(NULL, "Error starting to connect (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while(GWEN_MsgEndpoint_GetState(epTcp)!=GWEN_MSG_ENDPOINT_STATE_CONNECTED) {
|
|
||||||
DBG_DEBUG(NULL, "Next loop");
|
|
||||||
GWEN_MsgEndpoint_IoLoop(epTcp, 2000); /* 2000 ms */
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _subscribe(AQHOME_STORAGE *aqh, const char *topicFilter)
|
|
||||||
{
|
|
||||||
uint16_t pckId;
|
|
||||||
GWEN_MSG *msgOut;
|
|
||||||
GWEN_MSG *msgIn;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Sending SUBSCRIBE %s", topicFilter);
|
|
||||||
pckId=AQH_MqttClientEndpoint_GetNextPacketId(aqh->mqttEndpoint);
|
|
||||||
msgOut=GWEN_SubscribeMqttMsg_new(AQH_MQTTMSG_MSGTYPE_SUBSCRIBE, pckId, topicFilter, 0);
|
|
||||||
if (msgOut==NULL) {
|
|
||||||
DBG_ERROR(NULL, "Error creating message");
|
|
||||||
return GWEN_ERROR_INTERNAL;
|
|
||||||
}
|
|
||||||
GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, msgOut);
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Waiting for response");
|
|
||||||
msgIn=_awaitPacket(aqh->mqttEndpoint, AQH_MQTTMSG_MSGTYPE_SUBACK, AQHOME_STORAGE_DEFAULT_CMDTIMEOUT);
|
|
||||||
if (msgIn) {
|
|
||||||
GWEN_BUFFER *buf;
|
|
||||||
|
|
||||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
AQH_SubAckMqttMsg_DumpToBuffer(msgIn, buf, "received");
|
|
||||||
DBG_INFO(NULL, "%s", GWEN_Buffer_GetStart(buf));
|
|
||||||
GWEN_Buffer_free(buf);
|
|
||||||
GWEN_Msg_free(msgIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_awaitPacket(GWEN_MSG_ENDPOINT *epTcp, uint8_t expectedPacketType, int timeoutInSeconds)
|
|
||||||
{
|
|
||||||
time_t startTime;
|
|
||||||
|
|
||||||
startTime=time(NULL);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
GWEN_MSG *msg;
|
|
||||||
time_t now;
|
|
||||||
|
|
||||||
GWEN_MsgEndpoint_IoLoop(epTcp, 2000); /* 2000 ms */
|
|
||||||
msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(epTcp);
|
|
||||||
if (msg) {
|
|
||||||
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(expectedPacketType & 0xf0)) {
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Received this message:");
|
|
||||||
GWEN_Text_DumpString((const char*) GWEN_Msg_GetConstBuffer(msg), GWEN_Msg_GetBytesInBuffer(msg), 2);
|
|
||||||
}
|
|
||||||
GWEN_Msg_free(msg);
|
|
||||||
}
|
|
||||||
now=time(NULL);
|
|
||||||
if (now-startTime>timeoutInSeconds) {
|
|
||||||
DBG_INFO(NULL, "Timeout");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_INIT_MQTT_H
|
|
||||||
#define AQHOME_STORAGE_INIT_MQTT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_SetupMqtt(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./loop.h"
|
|
||||||
#include "./loop_http.h"
|
|
||||||
#include "./loop_mqtt.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _writeModifiedSessions(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
void AqHomeStorage_Loop(AQHOME_STORAGE *aqh, int timeoutInMsecs)
|
|
||||||
{
|
|
||||||
if (aqh) {
|
|
||||||
GWEN_MsgEndpoint_ChildrenIoLoop(aqh->rootEndpoint, timeoutInMsecs);
|
|
||||||
AqHomeStorage_ReadAndHandleHttpMessages(aqh);
|
|
||||||
AqHomeStorage_ReadAndHandleMqttMessages(aqh);
|
|
||||||
|
|
||||||
// AqHomeStorage_ReadAndHandleIpcMessages(aqh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_WriteStorageIfChanged(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
if (AQH_Storage_GetRuntimeFlags(aqh->storage) & AQH_STORAGE_RTFLAGS_MODIFIED) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Storage modified, writing statefile");
|
|
||||||
rv=AqHomeHttpService_LockStorage(aqh->httpService);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error locking storage (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
rv=AQH_Storage_WriteState(aqh->storage);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error writing state file (%d)", rv);
|
|
||||||
AqHomeHttpService_UnlockStorage(aqh->httpService);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_UnlockStorage(aqh->httpService);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error unlocking storage (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_WriteServiceIfChanged(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=_writeModifiedSessions(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeModifiedSessions(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
AQH_SESSION_LIST *sessionList;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=AQH_HttpService_LockSessions(aqh->httpService);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error locking sessions (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionList=AQH_Service_GetSessionList(aqh->httpService);
|
|
||||||
if (sessionList) {
|
|
||||||
AQH_SESSION *session;
|
|
||||||
|
|
||||||
session=AQH_Session_List_First(sessionList);
|
|
||||||
while(session) {
|
|
||||||
if (AQH_Session_GetRuntimeFlags(session) & AQH_SESSION_RTFLAGS_MODIFIED) {
|
|
||||||
DBG_INFO(NULL, "Session \"%s\" modified, writing", AQH_Session_GetUid(session));
|
|
||||||
rv=AQH_HttpService_SaveSession(aqh->httpService, session);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error writing session \"%s\" (%d)", AQH_Session_GetUid(session), rv);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_DEBUG(NULL, "Session \"%s\" written", AQH_Session_GetUid(session));
|
|
||||||
AQH_Session_SubRuntimeFlags(session, AQH_SESSION_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
session=AQH_Session_List_Next(session);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AQH_HttpService_UnlockSessions(aqh->httpService);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error unlocking sessions (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_LOOP_H
|
|
||||||
#define AQHOME_STORAGE_LOOP_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_Loop(AQHOME_STORAGE *aqh, int timeoutInMsecs);
|
|
||||||
|
|
||||||
int AqHomeStorage_WriteStorageIfChanged(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
int AqHomeStorage_WriteServiceIfChanged(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./loop_http.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
|
|
||||||
#include "aqhome/msg/endpoint_tty.h"
|
|
||||||
#include "aqhome/ipc/endpoint_ipc.h"
|
|
||||||
#include "aqhome/mqtt/endpoint_mqttc.h"
|
|
||||||
#include "aqhome/http/endpoint_http.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/text.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint_tcpd.h>
|
|
||||||
#include <gwenhywfar/endpoint_msgio.h>
|
|
||||||
#include <gwenhywfar/syncio.h>
|
|
||||||
#include <gwenhywfar/url.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
|
||||||
# include <sys/types.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_SYS_STAT_H
|
|
||||||
# include <sys/stat.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
//#define I18N(msg) msg
|
|
||||||
#define I18S(msg) msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void _handleHttpEndpoint(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep);
|
|
||||||
static void _handleHttpMsg(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
void AqHomeStorage_ReadAndHandleHttpMessages(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
if (aqh->httpdEndpoint) {
|
|
||||||
GWEN_MSG_ENDPOINT *ep;
|
|
||||||
|
|
||||||
ep=GWEN_MsgEndpoint_Tree2_GetFirstChild(aqh->httpdEndpoint);
|
|
||||||
while(ep) {
|
|
||||||
_handleHttpEndpoint(aqh, ep);
|
|
||||||
ep=GWEN_MsgEndpoint_Tree2_GetNext(ep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _handleHttpEndpoint(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep)
|
|
||||||
{
|
|
||||||
GWEN_MSG *msg;
|
|
||||||
|
|
||||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(ep)) ) {
|
|
||||||
_handleHttpMsg(aqh, ep, msg);
|
|
||||||
GWEN_Msg_free(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _handleHttpMsg(AQHOME_STORAGE *aqh, GWEN_MSG_ENDPOINT *ep, const GWEN_MSG *msgReceived)
|
|
||||||
{
|
|
||||||
GWEN_MSG *msgResponse;
|
|
||||||
|
|
||||||
msgResponse=AQH_HttpService_HandleHttpRequest(aqh->httpService, ep, msgReceived);
|
|
||||||
if (msgResponse) {
|
|
||||||
DBG_INFO(NULL, "Sending response message");
|
|
||||||
GWEN_MsgEndpoint_AddSendMessage(ep, msgResponse);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "No response for message");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_HTTP_H
|
|
||||||
#define AQHOME_STORAGE_HTTP_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_ReadAndHandleHttpMessages(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./loop_mqtt.h"
|
|
||||||
#include "./aqhomestorage_p.h"
|
|
||||||
|
|
||||||
#include "aqhome/mqtt/msg_mqtt_publish.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
//#define I18N(msg) msg
|
|
||||||
#define I18S(msg) msg
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void _handlePublishMsg(AQHOME_STORAGE *aqh, GWEN_MSG *msg);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_ReadAndHandleMqttMessages(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
GWEN_MSG *msg;
|
|
||||||
|
|
||||||
while( (msg=GWEN_MsgEndpoint_TakeFirstReceivedMessage(aqh->mqttEndpoint)) ) {
|
|
||||||
if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PUBLISH & 0xf0)) {
|
|
||||||
_handlePublishMsg(aqh, msg);
|
|
||||||
}
|
|
||||||
else if ((AQH_MqttMsg_GetMsgTypeAndFlags(msg) & 0xf0)==(AQH_MQTTMSG_MSGTYPE_PINGRESP & 0xf0)) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "PING response received");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "Received unexpected MQTT message %02x", AQH_MqttMsg_GetMsgTypeAndFlags(msg));
|
|
||||||
}
|
|
||||||
GWEN_Msg_free(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AqHomeStorage_MqttPing(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
GWEN_MSG *msgOut;
|
|
||||||
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Sending PING");
|
|
||||||
msgOut=GWEN_MqttMsg_new(AQH_MQTTMSG_MSGTYPE_PINGREQ, 0, NULL);
|
|
||||||
if (msgOut==NULL) {
|
|
||||||
DBG_ERROR(NULL, "Error creating message");
|
|
||||||
return GWEN_ERROR_INTERNAL;
|
|
||||||
}
|
|
||||||
GWEN_MsgEndpoint_AddSendMessage(aqh->mqttEndpoint, msgOut);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _handlePublishMsg(AQHOME_STORAGE *aqh, GWEN_MSG *msg)
|
|
||||||
{
|
|
||||||
char *topic;
|
|
||||||
char *value;
|
|
||||||
|
|
||||||
topic=AQH_PublishMqttMsg_ExtractTopic(msg);
|
|
||||||
value=AQH_PublishMqttMsg_ExtractValue(msg);
|
|
||||||
|
|
||||||
if (topic && value)
|
|
||||||
AQH_Storage_HandleMqttPublish(aqh->storage, topic, value);
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Either topic or value missing in PUBLISH msg");
|
|
||||||
}
|
|
||||||
free(value);
|
|
||||||
free(topic);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_MQTT_H
|
|
||||||
#define AQHOME_STORAGE_MQTT_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
|
|
||||||
|
|
||||||
void AqHomeStorage_ReadAndHandleMqttMessages(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
int AqHomeStorage_MqttPing(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,269 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <aqhome/api.h>
|
|
||||||
#include <aqhome/aqhome.h>
|
|
||||||
|
|
||||||
#include "./aqhomestorage.h"
|
|
||||||
#include "./init.h"
|
|
||||||
#include "./fini.h"
|
|
||||||
#include "./loop.h"
|
|
||||||
#include "./loop_mqtt.h"
|
|
||||||
#include "./cleanup.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 CLEANUP_INTERVAL_IN_SECS (5*60)
|
|
||||||
//#define WRITE_INTERVAL_IN_SECS (5*60)
|
|
||||||
|
|
||||||
#define CLEANUP_INTERVAL_IN_SECS (60)
|
|
||||||
#define WRITE_INTERVAL_IN_SECS (60)
|
|
||||||
#define PING_INTERVAL 120
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* 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(AQHOME_STORAGE *aqh);
|
|
||||||
static void _writeCurrentState(AQHOME_STORAGE *aqh);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* static vars
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_SIGNAL_H
|
|
||||||
static struct sigaction saINT,saTERM, saHUP, saTSTP, saCONT;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int stopService=0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
AQHOME_STORAGE *aqh;
|
|
||||||
GWEN_GUI *gui;
|
|
||||||
|
|
||||||
rv=GWEN_Init();
|
|
||||||
if (rv) {
|
|
||||||
fprintf(stderr, "ERROR: Unable to init Gwen.\n");
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
GWEN_Logger_Open(0, "aqhome-storage", 0, GWEN_LoggerType_Console, GWEN_LoggerFacility_User);
|
|
||||||
//GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Warning);
|
|
||||||
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Info);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
aqh=AqHomeStorage_new();
|
|
||||||
rv=AqHomeStorage_Init(aqh, argc, argv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
_runService(aqh);
|
|
||||||
|
|
||||||
AqHomeStorage_Fini(aqh);
|
|
||||||
AqHomeStorage_free(aqh);
|
|
||||||
|
|
||||||
GWEN_Gui_SetGui(NULL);
|
|
||||||
GWEN_Gui_free(gui);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _runService(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
time_t timeStart;
|
|
||||||
time_t timeLastCleanup;
|
|
||||||
time_t timeLastWrite;
|
|
||||||
time_t timeLastPing;
|
|
||||||
int timeout;
|
|
||||||
|
|
||||||
timeout=AqHomeStorage_GetTimeout(aqh);
|
|
||||||
timeStart=time(NULL);
|
|
||||||
timeLastCleanup=time(NULL);
|
|
||||||
timeLastWrite=time(NULL);
|
|
||||||
timeLastPing=time(NULL);
|
|
||||||
|
|
||||||
while(!stopService) {
|
|
||||||
time_t now;
|
|
||||||
|
|
||||||
DBG_DEBUG(NULL, "Next loop");
|
|
||||||
AqHomeStorage_Loop(aqh, 2000);
|
|
||||||
|
|
||||||
now=time(NULL);
|
|
||||||
|
|
||||||
if (((int)difftime(now, timeLastCleanup))>CLEANUP_INTERVAL_IN_SECS) {
|
|
||||||
DBG_INFO(NULL, "Cleanup time");
|
|
||||||
AqHomeStorage_Cleanup(aqh);
|
|
||||||
timeLastCleanup=now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((int)difftime(now, timeLastWrite))>WRITE_INTERVAL_IN_SECS) {
|
|
||||||
DBG_INFO(NULL, "Write time");
|
|
||||||
_writeCurrentState(aqh);
|
|
||||||
timeLastWrite=now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timeout && ((int)difftime(now, timeLastPing))>timeout) {
|
|
||||||
DBG_INFO(NULL, "Sending ping");
|
|
||||||
AqHomeStorage_MqttPing(aqh);
|
|
||||||
timeLastPing=now;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (timeout && ((int)difftime(now, timeStart))>timeout) {
|
|
||||||
DBG_INFO(NULL, "Timeout");
|
|
||||||
_writeCurrentState(aqh);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} /* while */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _writeCurrentState(AQHOME_STORAGE *aqh)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=AqHomeStorage_WriteStorageIfChanged(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "ATTENTION: Could not write storage statefile (%d)", rv);
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeStorage_WriteServiceIfChanged(aqh);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "ATTENTION: Could not write current config (%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;
|
|
||||||
|
|
||||||
# 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;
|
|
||||||
default:
|
|
||||||
DBG_WARN(0, "Unknown signal %d",s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_base.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
AQH_HTTP_REQUEST *rq,
|
|
||||||
int rv,
|
|
||||||
AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb,
|
|
||||||
GWEN_DB_NODE *db)
|
|
||||||
{
|
|
||||||
if (rv<0) {
|
|
||||||
switch(rv) {
|
|
||||||
case GWEN_ERROR_INVALID:
|
|
||||||
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Missing fields"), 1, db, cb);
|
|
||||||
case GWEN_ERROR_FOUND:
|
|
||||||
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Object already exists"), 1, db, cb);
|
|
||||||
case GWEN_ERROR_NOT_FOUND:
|
|
||||||
return AQH_HttpUrlHandler_CreatePageMessage(uh, rq, "red", I18N("Object not found"), 1, db, cb);
|
|
||||||
case GWEN_ERROR_IO:
|
|
||||||
case GWEN_ERROR_INTERNAL:
|
|
||||||
default:
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh),
|
|
||||||
500, "Internal error",
|
|
||||||
AQH_HttpRequest_GetProtocol(rq), NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_BASE_H
|
|
||||||
#define AQHOME_STORAGE_U_BASE_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
AQH_HTTP_REQUEST *rq,
|
|
||||||
int rv,
|
|
||||||
AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb,
|
|
||||||
GWEN_DB_NODE *db);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,351 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_devices.h"
|
|
||||||
#include "./u_objects.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
|
|
||||||
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
|
|
||||||
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _setFromObject(AQH_DEVICE *device, const AQH_DEVICE *srcDevice);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_DevicesHttpUrlHandler_new(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_ObjectsHttpUrlHandler_new(sv,
|
|
||||||
AQHOME_HTTP_PERMS_LIST_DEVICES,
|
|
||||||
AQHOME_HTTP_PERMS_ADD_DEVICE,
|
|
||||||
AQHOME_HTTP_PERMS_DEL_DEVICE,
|
|
||||||
AQHOME_HTTP_PERMS_EDIT_DEVICE,
|
|
||||||
"/devices/list");
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
AQH_DEVICE *newDevice;
|
|
||||||
const char *deviceName;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
newDevice=AQH_Device_fromDb(db);
|
|
||||||
|
|
||||||
deviceName=AQH_Device_GetName(newDevice);
|
|
||||||
if (!(deviceName && *deviceName)) {
|
|
||||||
DBG_INFO(NULL, "Missing device name");
|
|
||||||
AQH_Device_free(newDevice);
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_LockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error locking storage");
|
|
||||||
AQH_Device_free(newDevice);
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id>0) {
|
|
||||||
AQH_DEVICE *device;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Edit existing device");
|
|
||||||
device=AQH_Storage_GetDeviceById(sto, id);
|
|
||||||
if (device==NULL) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "Device %d not found", id);
|
|
||||||
AQH_Device_free(newDevice);
|
|
||||||
return GWEN_ERROR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
AQH_Device_SetId(device, id);
|
|
||||||
_setFromObject(device, newDevice);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AQH_DEVICE *device;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Adding new device");
|
|
||||||
device=AQH_Storage_GetDeviceByName(sto, deviceName);
|
|
||||||
if (device) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "Device %s exists", deviceName);
|
|
||||||
AQH_Device_free(newDevice);
|
|
||||||
return GWEN_ERROR_FOUND;
|
|
||||||
}
|
|
||||||
device=AQH_Device_new();
|
|
||||||
AQH_Device_SetId(device, 0);
|
|
||||||
_setFromObject(device, newDevice);
|
|
||||||
AQH_Storage_AddDevice(sto, device);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
AQH_Device_free(newDevice);
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error unlocking storage");
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _setFromObject(AQH_DEVICE *device, const AQH_DEVICE *srcDevice)
|
|
||||||
{
|
|
||||||
AQH_Device_SetRoomId(device, AQH_Device_GetRoomId(srcDevice));
|
|
||||||
AQH_Device_SetName(device, AQH_Device_GetName(srcDevice));
|
|
||||||
AQH_Device_SetDeviceType(device, AQH_Device_GetDeviceType(srcDevice));
|
|
||||||
AQH_Device_SetLocation(device, AQH_Device_GetLocation(srcDevice));
|
|
||||||
AQH_Device_SetDescription(device, AQH_Device_GetDescription(srcDevice));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_DEVICE *device;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
device=AQH_Storage_GetDeviceById(sto, id);
|
|
||||||
if (device) {
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
db=GWEN_DB_Group_new("device");
|
|
||||||
AQH_Device_toDb(device, db);
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/devices/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Add Device"));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/devices/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Edit Device"),
|
|
||||||
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_ROOM_LIST *roomList;
|
|
||||||
unsigned long int selectedRoomId=0;
|
|
||||||
char numbuf[16];
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
roomList=AQH_Storage_GetRoomList(sto);
|
|
||||||
|
|
||||||
selectedRoomId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "roomId", 0, 0):0);
|
|
||||||
snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedRoomId);
|
|
||||||
numbuf[sizeof(numbuf)-1]=0;
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <table>"
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"name\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
|
|
||||||
" </tr>",
|
|
||||||
I18N("Name"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td><label for=\"roomId\">%s: </label></td>"
|
|
||||||
"<td><select id=\"roomId\" name=\"roomId\">",
|
|
||||||
I18N("Room"));
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>", I18N("-- select room --"));
|
|
||||||
|
|
||||||
if (roomList) {
|
|
||||||
const AQH_ROOM *r;
|
|
||||||
|
|
||||||
r=AQH_Room_List_First(roomList);
|
|
||||||
while(r) {
|
|
||||||
const char *roomName;
|
|
||||||
|
|
||||||
roomName=AQH_Room_GetName(r);
|
|
||||||
if (roomName && *roomName) {
|
|
||||||
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_Room_GetId(r));
|
|
||||||
numbuf[sizeof(numbuf)-1]=0;
|
|
||||||
if (selectedRoomId && AQH_Room_GetId(r)==selectedRoomId)
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>", numbuf, roomName);
|
|
||||||
else
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>", numbuf, roomName);
|
|
||||||
}
|
|
||||||
r=AQH_Room_List_Next(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>");
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"deviceType\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"deviceType\" value=\"%s\"></td>"
|
|
||||||
" </tr>",
|
|
||||||
I18N("Type"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "deviceType", 0, ""):"");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"location\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"location\" value=\"%s\"></td>"
|
|
||||||
" </tr>",
|
|
||||||
I18N("Location"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "location", 0, ""):"");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"description\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"description\" value=\"%s\"></td>"
|
|
||||||
" </tr>"
|
|
||||||
" </table>",
|
|
||||||
I18N("Description"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "description", 0, ""):"");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_DEVICE_LIST *rl;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2>"
|
|
||||||
"<table class=\"dataTable\">"
|
|
||||||
"<thead>"
|
|
||||||
" <tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
|
|
||||||
"</thead>",
|
|
||||||
I18N("Devices"),
|
|
||||||
I18N("Name"),
|
|
||||||
I18N("Room"),
|
|
||||||
I18N("Type"),
|
|
||||||
I18N("Location"),
|
|
||||||
I18N("Description"));
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
|
|
||||||
rl=AQH_Storage_GetDeviceList(sto);
|
|
||||||
if (rl) {
|
|
||||||
const AQH_DEVICE *device;
|
|
||||||
|
|
||||||
device=AQH_Device_List_First(rl);
|
|
||||||
while(device) {
|
|
||||||
long unsigned int id;
|
|
||||||
int roomId;
|
|
||||||
const char *name;
|
|
||||||
const char *roomName=NULL;
|
|
||||||
const char *devType;
|
|
||||||
const char *descr;
|
|
||||||
const char *location;
|
|
||||||
const AQH_ROOM *r=NULL;
|
|
||||||
|
|
||||||
id=(long unsigned int) AQH_Device_GetId(device);
|
|
||||||
roomId=(long unsigned int) AQH_Device_GetRoomId(device);
|
|
||||||
if (roomId>0)
|
|
||||||
r=AQH_Storage_GetRoomById(sto, roomId);
|
|
||||||
if (r)
|
|
||||||
roomName=AQH_Room_GetName(r);
|
|
||||||
|
|
||||||
name=AQH_Device_GetName(device);
|
|
||||||
devType=AQH_Device_GetDeviceType(device);
|
|
||||||
descr=AQH_Device_GetDescription(device);
|
|
||||||
location=AQH_Device_GetLocation(device);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
|
|
||||||
"<td><a href=\"/devices/edit/%lu\">"
|
|
||||||
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
|
|
||||||
"</tr>",
|
|
||||||
name?name:"",
|
|
||||||
roomName?roomName:"",
|
|
||||||
devType?devType:"",
|
|
||||||
location?location:"",
|
|
||||||
descr?descr:"", id);
|
|
||||||
|
|
||||||
device=AQH_Device_List_Next(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/devices/add\">%s</a><br>", I18N("Add Device"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_DEVICES_H
|
|
||||||
#define AQHOME_STORAGE_U_DEVICES_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_DevicesHttpUrlHandler_new(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,394 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_login.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/args.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
#include <gwenhywfar/mdigest.h>
|
|
||||||
#include <gwenhywfar/text.h>
|
|
||||||
#include <gwenhywfar/timestamp.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
|
|
||||||
static int _loginUser(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static int _verifyPass(AQH_USER *u, const char *userName, const char *password);
|
|
||||||
static AQH_SESSION *_generateSessionForUser(AQH_SERVICE *sv, AQH_USER *u);
|
|
||||||
static GWEN_BUFFER *_generateSessionUid(void);
|
|
||||||
static void _headerSetCookie(GWEN_DB_NODE *db, uint32_t flags, const char *cookieName, const char *cookieValue);
|
|
||||||
static GWEN_MSG *_createLoginResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *sessionId, const char *newPage);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_LoginHttpUrlHandler_new(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_HttpUrlHandler_new(sv);
|
|
||||||
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
const char *protocol;
|
|
||||||
const char *cmd;
|
|
||||||
GWEN_MSG *msgOut=NULL;
|
|
||||||
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
|
||||||
if (cmd && *cmd) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (strcasecmp(cmd, "GET")==0) {
|
|
||||||
rv=_handleGet(uh, rq);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strcasecmp(cmd, "POST")==0) {
|
|
||||||
rv=_handlePost(uh, rq);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
GWEN_BUFFER *pageBuf;
|
|
||||||
int rv;
|
|
||||||
GWEN_MSG *msgOut=NULL;
|
|
||||||
const char *protocol;
|
|
||||||
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
pageBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AQH_HttpService_AddFile(AQH_HttpUrlHandler_GetHttpService(uh), NULL, "login.html", pageBuf);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error reading file \"login.html\"");
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "Login POST:");
|
|
||||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
|
||||||
GWEN_DB_Dump(db, 2);
|
|
||||||
|
|
||||||
rv=_loginUser(uh, rq);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "here (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _loginUser(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
GWEN_MSG *msgOut=NULL;
|
|
||||||
const char *protocol;
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
const char *userName;
|
|
||||||
const char *password;
|
|
||||||
AQH_USER *u;
|
|
||||||
AQH_SESSION *session;
|
|
||||||
int i;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
|
|
||||||
userName=GWEN_DB_GetCharValue(db, "username", 0, NULL);
|
|
||||||
password=GWEN_DB_GetCharValue(db, "password", 0, NULL);
|
|
||||||
if (!(userName && *userName && password && *password)) {
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(sv, 401, "Unauthorized", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u=AQH_HttpService_GetUser(sv, userName);
|
|
||||||
if (u==NULL) {
|
|
||||||
DBG_INFO(NULL, "User \"%s\" not found", userName);
|
|
||||||
/* TODO: sleep */
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i=AQH_User_GetState(u);
|
|
||||||
if (i==AQH_UserState_Suspended) {
|
|
||||||
DBG_INFO(NULL, "User \"%s\" suspended", userName);
|
|
||||||
/* TODO: sleep */
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_verifyPass(u, userName, password);
|
|
||||||
if (rv<0) {
|
|
||||||
if (rv==GWEN_ERROR_VERIFY)
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 401, "Unauthorized", protocol, "error");
|
|
||||||
else
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
/* TODO: sleep */
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
session=_generateSessionForUser(sv, u);
|
|
||||||
if (session==NULL) {
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
/* TODO: sleep */
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "Session generated");
|
|
||||||
AQH_User_SetTimestampLastLogin(u, AQH_Session_GetTimestampCreation(session));
|
|
||||||
rv=AQH_HttpService_WriteUser(sv, u);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
msgOut=_createLoginResponseMsg(sv, protocol, AQH_Session_GetUid(session), "/rooms/list");
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _verifyPass(AQH_USER *u, const char *userName, const char *password)
|
|
||||||
{
|
|
||||||
GWEN_MDIGEST *md;
|
|
||||||
int rv;
|
|
||||||
const char *storedPasswordHash;
|
|
||||||
char buffer[70];
|
|
||||||
|
|
||||||
storedPasswordHash=AQH_User_GetHashedPassword(u);
|
|
||||||
if (!(storedPasswordHash && *storedPasswordHash)) {
|
|
||||||
DBG_ERROR(NULL, "No password hash stored with user \"%s\"", userName);
|
|
||||||
return GWEN_ERROR_INTERNAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
md=GWEN_MDigest_Sha256_new();
|
|
||||||
rv=GWEN_MDigest_Begin(md);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error digesting given password [begin] (%d)", rv);
|
|
||||||
GWEN_MDigest_free(md);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=GWEN_MDigest_Update(md, (const uint8_t*) password, strlen(password));
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error digesting given password [update] (%d)", rv);
|
|
||||||
GWEN_MDigest_free(md);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=GWEN_MDigest_End(md);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error digesting given password [end] (%d)", rv);
|
|
||||||
GWEN_MDigest_free(md);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "Digest needs %d bytes", (GWEN_MDigest_GetDigestSize(md)*2)+1);
|
|
||||||
if (NULL==GWEN_Text_ToHex((const char*) GWEN_MDigest_GetDigestPtr(md), GWEN_MDigest_GetDigestSize(md), buffer, sizeof(buffer)-1)) {
|
|
||||||
DBG_ERROR(NULL, "Buffer too small (need %d)", (GWEN_MDigest_GetDigestSize(md)*2)+1);
|
|
||||||
GWEN_MDigest_free(md);
|
|
||||||
return GWEN_ERROR_INTERNAL;
|
|
||||||
}
|
|
||||||
GWEN_MDigest_free(md);
|
|
||||||
|
|
||||||
if (strcasecmp(buffer, storedPasswordHash)!=0) {
|
|
||||||
DBG_ERROR(NULL, "Bad password for user \"%s\"", userName);
|
|
||||||
return GWEN_ERROR_VERIFY;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "Valid password for user \"%s\"", userName);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_SESSION *_generateSessionForUser(AQH_SERVICE *sv, AQH_USER *u)
|
|
||||||
{
|
|
||||||
AQH_SESSION *session;
|
|
||||||
GWEN_BUFFER *buf;
|
|
||||||
GWEN_TIMESTAMP *ts;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
buf=_generateSessionUid();
|
|
||||||
if (buf==NULL) {
|
|
||||||
DBG_INFO(NULL, "here");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
DBG_INFO(NULL, "New session id: [%s]", GWEN_Buffer_GetStart(buf));
|
|
||||||
|
|
||||||
session=AQH_Session_new();
|
|
||||||
AQH_Session_SetUid(session, GWEN_Buffer_GetStart(buf));
|
|
||||||
GWEN_Buffer_free(buf);
|
|
||||||
|
|
||||||
ts=GWEN_Timestamp_NowInLocalTime();
|
|
||||||
AQH_Session_SetTimestampCreation(session, ts);
|
|
||||||
AQH_Session_SetTimestampLastAccess(session, ts);
|
|
||||||
GWEN_Timestamp_free(ts);
|
|
||||||
|
|
||||||
AQH_Session_SetUserAlias(session, AQH_User_GetAlias(u));
|
|
||||||
AQH_Session_SetUser(session, u);
|
|
||||||
|
|
||||||
rv=AQH_HttpService_AddSession(sv, session);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(NULL, "Error adding session \"%s\" (%d)", AQH_Session_GetUid(session), rv);
|
|
||||||
AQH_Session_free(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_BUFFER *_generateSessionUid(void)
|
|
||||||
{
|
|
||||||
uint8_t binbuf[8];
|
|
||||||
GWEN_BUFFER *buf;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
rv=GWEN_SyncIo_Helper_PartiallyReadFile("/dev/urandom", binbuf, sizeof(binbuf));
|
|
||||||
if (rv<sizeof(binbuf)) {
|
|
||||||
DBG_ERROR(NULL, "Error reading from /dev/urandom: %d", rv);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf=GWEN_Buffer_new(0, 20, 0, 1);
|
|
||||||
rv=GWEN_Text_ToHexBuffer((const char*) binbuf, rv, buf, 0, 0, 0);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error converting random bytes to hex (%d)", rv);
|
|
||||||
GWEN_Buffer_free(buf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_createLoginResponseMsg(AQH_SERVICE *sv, const char *protocol, const char *sessionId, const char *newPage)
|
|
||||||
{
|
|
||||||
GWEN_BUFFER *buf;
|
|
||||||
GWEN_MSG *msg;
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
buf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
AQH_HttpService_AddStatusLine(sv, 303, "OK, redirecting to content", protocol, buf);
|
|
||||||
db=GWEN_DB_Group_new("header");
|
|
||||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
|
|
||||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", "text/html; charset=utf-8");
|
|
||||||
_headerSetCookie(db, GWEN_DB_FLAGS_OVERWRITE_VARS, AQH_HTTP_REQUEST_SESSIONCOOKIE, sessionId);
|
|
||||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Location", newPage);
|
|
||||||
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", 0);
|
|
||||||
AQH_HttpService_AddHeader(sv, db, buf);
|
|
||||||
GWEN_DB_Group_free(db);
|
|
||||||
|
|
||||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
|
||||||
GWEN_Buffer_free(buf);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _headerSetCookie(GWEN_DB_NODE *db, uint32_t flags, const char *cookieName, const char *cookieValue)
|
|
||||||
{
|
|
||||||
if (cookieName && cookieValue) {
|
|
||||||
GWEN_BUFFER *dbuf;
|
|
||||||
|
|
||||||
dbuf=GWEN_Buffer_new(0, 32, 0, 1);
|
|
||||||
GWEN_Buffer_AppendArgs(dbuf, "%s=%s", cookieName, cookieValue);
|
|
||||||
GWEN_DB_SetCharValue(db, flags, "Set-Cookie", GWEN_Buffer_GetStart(dbuf));
|
|
||||||
GWEN_Buffer_free(dbuf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_LOGIN_H
|
|
||||||
#define AQHOME_STORAGE_U_LOGIN_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_LoginHttpUrlHandler_new(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,379 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_mqtttopics.h"
|
|
||||||
#include "./u_objects.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
|
|
||||||
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
|
|
||||||
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _setFromObject(AQH_MQTT_TOPIC *mqttTopic, const AQH_MQTT_TOPIC *srcMqttTopic);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_MqttTopicsHttpUrlHandler_new(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_ObjectsHttpUrlHandler_new(sv,
|
|
||||||
AQHOME_HTTP_PERMS_LIST_TOPICS,
|
|
||||||
AQHOME_HTTP_PERMS_ADD_TOPIC,
|
|
||||||
AQHOME_HTTP_PERMS_DEL_TOPIC,
|
|
||||||
AQHOME_HTTP_PERMS_EDIT_TOPIC,
|
|
||||||
"/mqtttopics/list");
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
AQH_MQTT_TOPIC *newMqttTopic;
|
|
||||||
const char *topic;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
newMqttTopic=AQH_MqttTopic_fromDb(db);
|
|
||||||
|
|
||||||
topic=AQH_MqttTopic_GetTopic(newMqttTopic);
|
|
||||||
if (!(topic && *topic)) {
|
|
||||||
DBG_INFO(NULL, "Missing mqttTopic topic");
|
|
||||||
AQH_MqttTopic_free(newMqttTopic);
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_LockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error locking storage");
|
|
||||||
AQH_MqttTopic_free(newMqttTopic);
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id>0) {
|
|
||||||
AQH_MQTT_TOPIC *mqttTopic;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Edit existing mqttTopic");
|
|
||||||
mqttTopic=AQH_Storage_GetMqttTopicById(sto, id);
|
|
||||||
if (mqttTopic==NULL) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "MqttTopic %d not found", id);
|
|
||||||
AQH_MqttTopic_free(newMqttTopic);
|
|
||||||
return GWEN_ERROR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
AQH_MqttTopic_SetId(mqttTopic, id);
|
|
||||||
_setFromObject(mqttTopic, newMqttTopic);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AQH_MQTT_TOPIC *mqttTopic;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Adding new mqttTopic");
|
|
||||||
mqttTopic=AQH_Storage_GetMqttTopicByTopic(sto, topic);
|
|
||||||
if (mqttTopic) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "MqttTopic %s exists", topic);
|
|
||||||
AQH_MqttTopic_free(newMqttTopic);
|
|
||||||
return GWEN_ERROR_FOUND;
|
|
||||||
}
|
|
||||||
mqttTopic=AQH_MqttTopic_new();
|
|
||||||
AQH_MqttTopic_SetId(mqttTopic, 0);
|
|
||||||
_setFromObject(mqttTopic, newMqttTopic);
|
|
||||||
AQH_Storage_AddMqttTopic(sto, mqttTopic);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
AQH_MqttTopic_free(newMqttTopic);
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error unlocking storage");
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _setFromObject(AQH_MQTT_TOPIC *mqttTopic, const AQH_MQTT_TOPIC *srcMqttTopic)
|
|
||||||
{
|
|
||||||
AQH_MqttTopic_SetDeviceId(mqttTopic, AQH_MqttTopic_GetDeviceId(srcMqttTopic));
|
|
||||||
AQH_MqttTopic_SetTopic(mqttTopic, AQH_MqttTopic_GetTopic(srcMqttTopic));
|
|
||||||
AQH_MqttTopic_SetDataType(mqttTopic, AQH_MqttTopic_GetDataType(srcMqttTopic));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_MQTT_TOPIC *mqttTopic;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
mqttTopic=AQH_Storage_GetMqttTopicById(sto, id);
|
|
||||||
if (mqttTopic) {
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
db=GWEN_DB_Group_new("mqttTopic");
|
|
||||||
AQH_MqttTopic_toDb(mqttTopic, db);
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/mqtttopics/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Add MQTT Topic"));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/mqtttopics/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Edit MQTT Topic"),
|
|
||||||
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const GWEN_STRINGLIST *seenTopicsList;
|
|
||||||
const AQH_DEVICE_LIST *deviceList;
|
|
||||||
unsigned long int selectedDeviceId=0;
|
|
||||||
int dataType;
|
|
||||||
char numbuf[16];
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
deviceList=AQH_Storage_GetDeviceList(sto);
|
|
||||||
|
|
||||||
selectedDeviceId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "deviceId", 0, 0):0);
|
|
||||||
snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedDeviceId);
|
|
||||||
numbuf[sizeof(numbuf)-1]=0;
|
|
||||||
dataType=dbValues?GWEN_DB_GetIntValue(dbValues, "dataType", 0, AQH_MqttTopicType_Num):0;
|
|
||||||
|
|
||||||
/* topic */
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<table>"
|
|
||||||
"<tr>"
|
|
||||||
" <td><label for=\"topic\">%s: </label></td>"
|
|
||||||
" <td>"
|
|
||||||
" <input list=\"seenTopics\" type=\"text\" name=\"topic\" id=\"topic\" value=\"%s\" size=\"64\" required>\n"
|
|
||||||
" <datalist id=\"seenTopics\">",
|
|
||||||
I18N("MQTT Topic"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "topic", 0, ""):"");
|
|
||||||
seenTopicsList=AQH_Storage_GetRecvdTopicList(sto);
|
|
||||||
if (seenTopicsList && GWEN_StringList_Count(seenTopicsList)) {
|
|
||||||
GWEN_STRINGLISTENTRY *se;
|
|
||||||
|
|
||||||
se=GWEN_StringList_FirstEntry(seenTopicsList);
|
|
||||||
while(se) {
|
|
||||||
const char *s=GWEN_StringListEntry_Data(se);
|
|
||||||
if (s && *s) {
|
|
||||||
DBG_INFO(NULL, "Adding MQTT string %s", s);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">\n", s);
|
|
||||||
}
|
|
||||||
se=GWEN_StringListEntry_Next(se);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</datalist></td></tr>");
|
|
||||||
|
|
||||||
|
|
||||||
/* device */
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td><label for=\"deviceId\">%s: </label></td>"
|
|
||||||
"<td><select id=\"deviceId\" name=\"deviceId\">",
|
|
||||||
I18N("Device"));
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>\n", I18N("-- select device --"));
|
|
||||||
|
|
||||||
if (deviceList) {
|
|
||||||
const AQH_DEVICE *device;
|
|
||||||
|
|
||||||
device=AQH_Device_List_First(deviceList);
|
|
||||||
while(device) {
|
|
||||||
const char *deviceName;
|
|
||||||
|
|
||||||
deviceName=AQH_Device_GetName(device);
|
|
||||||
if (deviceName && *deviceName) {
|
|
||||||
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_Device_GetId(device));
|
|
||||||
numbuf[sizeof(numbuf)-1]=0;
|
|
||||||
if (selectedDeviceId && AQH_Device_GetId(device)==selectedDeviceId)
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>\n", numbuf, deviceName);
|
|
||||||
else
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>\n", numbuf, deviceName);
|
|
||||||
}
|
|
||||||
device=AQH_Device_List_Next(device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>\n");
|
|
||||||
|
|
||||||
/* data type */
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td><label for=\"dataType\">%s: </label></td>"
|
|
||||||
"<td><select id=\"dataType\" name=\"dataType\">",
|
|
||||||
I18N("Data Type"));
|
|
||||||
if (dataType==AQH_MqttTopicType_Num)
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" selected>%s</option>", AQH_MqttTopicType_Num, I18N("numeric"));
|
|
||||||
else
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" >%s</option>", AQH_MqttTopicType_Num, I18N("numeric"));
|
|
||||||
if (dataType==AQH_MqttTopicType_Json)
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" selected>%s</option>", AQH_MqttTopicType_Json, I18N("JSON"));
|
|
||||||
else
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%d\" >%s</option>", AQH_MqttTopicType_Json, I18N("JSON"));
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>\n");
|
|
||||||
|
|
||||||
|
|
||||||
if (seenTopicsList && GWEN_StringList_Count(seenTopicsList)) {
|
|
||||||
GWEN_STRINGLISTENTRY *se;
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<tr><td valign=\"top\"><label for=\"receivedTopicsList\">%s: </label></td>", I18N("Received Topics"));
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "<td><output name=\"receivedTopicsList\" id=\"receivedTopicsList\">");
|
|
||||||
|
|
||||||
se=GWEN_StringList_FirstEntry(seenTopicsList);
|
|
||||||
while(se) {
|
|
||||||
const char *s=GWEN_StringListEntry_Data(se);
|
|
||||||
if (s && *s)
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "%s<br>\n", s);
|
|
||||||
se=GWEN_StringListEntry_Next(se);
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</output></td></tr>");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</tbody></table>\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_MQTT_TOPIC_LIST *rl;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2>"
|
|
||||||
"<table class=\"dataTable\">"
|
|
||||||
"<thead>"
|
|
||||||
" <tr><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
|
|
||||||
"</thead>",
|
|
||||||
I18N("Mqtt Topics"),
|
|
||||||
I18N("Topic"),
|
|
||||||
I18N("Device"),
|
|
||||||
I18N("Datatype"));
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
|
|
||||||
rl=AQH_Storage_GetMqttTopicList(sto);
|
|
||||||
if (rl) {
|
|
||||||
const AQH_MQTT_TOPIC *mqttTopic;
|
|
||||||
|
|
||||||
mqttTopic=AQH_MqttTopic_List_First(rl);
|
|
||||||
while(mqttTopic) {
|
|
||||||
long unsigned int id;
|
|
||||||
int deviceId;
|
|
||||||
const char *topic;
|
|
||||||
int dataType;
|
|
||||||
const char *deviceName=NULL;
|
|
||||||
const AQH_DEVICE *device=NULL;
|
|
||||||
|
|
||||||
id=(long unsigned int) AQH_MqttTopic_GetId(mqttTopic);
|
|
||||||
deviceId=(long unsigned int) AQH_MqttTopic_GetDeviceId(mqttTopic);
|
|
||||||
if (deviceId>0)
|
|
||||||
device=AQH_Storage_GetDeviceById(sto, deviceId);
|
|
||||||
if (device)
|
|
||||||
deviceName=AQH_Device_GetName(device);
|
|
||||||
|
|
||||||
topic=AQH_MqttTopic_GetTopic(mqttTopic);
|
|
||||||
dataType=AQH_MqttTopic_GetDataType(mqttTopic);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td>%s</td><td>%s</td><td>%s</td>"
|
|
||||||
"<td><a href=\"/mqtttopics/edit/%lu\">"
|
|
||||||
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
|
|
||||||
"</tr>",
|
|
||||||
topic?topic:"",
|
|
||||||
deviceName?deviceName:"",
|
|
||||||
AQH_MqttTopicType_toString(dataType),
|
|
||||||
id);
|
|
||||||
mqttTopic=AQH_MqttTopic_List_Next(mqttTopic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/mqtttopics/add\">%s</a><br>", I18N("Add MqttTopic"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_MQTTTOPICS_H
|
|
||||||
#define AQHOME_STORAGE_U_MQTTTOPICS_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_MqttTopicsHttpUrlHandler_new(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,458 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_objects_p.h"
|
|
||||||
#include "./u_base.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_INHERIT(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
|
||||||
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
|
|
||||||
static void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
static void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf);
|
|
||||||
static GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id);
|
|
||||||
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static GWEN_MSG *_addOrEditAndCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb);
|
|
||||||
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
|
|
||||||
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
|
|
||||||
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_ObjectsHttpUrlHandler_new(AQH_SERVICE *sv,
|
|
||||||
uint32_t neededPermsList,
|
|
||||||
uint32_t neededPermsAdd,
|
|
||||||
uint32_t neededPermsDel,
|
|
||||||
uint32_t neededPermsEdit,
|
|
||||||
const char *urlForObjectList)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh;
|
|
||||||
|
|
||||||
uh=AQH_HttpUrlHandler_new(sv);
|
|
||||||
GWEN_NEW_OBJECT(AQH_URLHANDLER_OBJECTS, xuh);
|
|
||||||
GWEN_INHERIT_SETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh, xuh, _freeData);
|
|
||||||
|
|
||||||
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
|
|
||||||
|
|
||||||
xuh->neededPermsList=neededPermsList;
|
|
||||||
xuh->neededPermsAdd=neededPermsAdd;
|
|
||||||
xuh->neededPermsDel=neededPermsDel;
|
|
||||||
xuh->neededPermsEdit=neededPermsEdit;
|
|
||||||
xuh->urlForObjectList=urlForObjectList?strdup(urlForObjectList):NULL;
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _freeData(void *bp, void *p)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh;
|
|
||||||
|
|
||||||
xuh=(AQH_URLHANDLER_OBJECTS*)p;
|
|
||||||
free(xuh->urlForObjectList);
|
|
||||||
GWEN_FREE_OBJECT(xuh);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN fn)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh) {
|
|
||||||
xuh->addOrEditObjectFn=fn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN fn)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh) {
|
|
||||||
xuh->findObjectByIdAndReturnAsDbFn=fn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN fn)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh) {
|
|
||||||
xuh->writeAddPageFn=fn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN fn)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh) {
|
|
||||||
xuh->writeEditPageFn=fn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN fn)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh) {
|
|
||||||
xuh->listObjectsIntoBufferFn=fn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
if (GWEN_INHERIT_ISOFTYPE(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh)) {
|
|
||||||
const char *protocol;
|
|
||||||
const char *cmd;
|
|
||||||
GWEN_MSG *msgOut;
|
|
||||||
|
|
||||||
AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome");
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
|
|
||||||
AQH_HttpRequest_SetupUrlPathMembers(rq);
|
|
||||||
if (AQH_HttpRequest_GetUrlPathMembers(rq)==NULL) {
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
|
||||||
if (cmd && *cmd) {
|
|
||||||
if (strcasecmp(cmd, "GET")==0)
|
|
||||||
msgOut=_handleGet(uh, rq);
|
|
||||||
else if (strcasecmp(cmd, "POST")==0)
|
|
||||||
msgOut=_handlePost(uh, rq);
|
|
||||||
else {
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
|
|
||||||
}
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Not an AQH_URLHANDLER_OBJECTS object");
|
|
||||||
return GWEN_ERROR_INTERNAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
GWEN_BUFFER *pageBuf;
|
|
||||||
int rv;
|
|
||||||
GWEN_MSG *msgOut=NULL;
|
|
||||||
const char *protocol;
|
|
||||||
const GWEN_STRINGLIST *sl;
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
pageBuf=GWEN_Buffer_new(0, 2048, 0, 1);
|
|
||||||
/* header */
|
|
||||||
rv=AQH_HttpUrlHandler_AddContentHeaders(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding headers");
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* middle part (header - middle - footer) */
|
|
||||||
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
|
|
||||||
|
|
||||||
s=GWEN_StringList_StringAt(sl, 1);
|
|
||||||
if (!(s && *s))
|
|
||||||
s="list";
|
|
||||||
|
|
||||||
if (strcasecmp(s, "list")==0)
|
|
||||||
_handleGetList(uh, rq, pageBuf);
|
|
||||||
else if (strcasecmp(s, "add")==0)
|
|
||||||
_handleGetAdd(uh, rq, pageBuf);
|
|
||||||
else if (strcasecmp(s, "edit")==0)
|
|
||||||
_handleGetEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0), pageBuf);
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* footer */
|
|
||||||
rv=AQH_HttpUrlHandler_AddContentFooters(uh, AQH_HTTP_CONTENT_MODE_DESKTOP, pageBuf);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error adding footers");
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, GWEN_Buffer_GetStart(pageBuf));
|
|
||||||
GWEN_Buffer_free(pageBuf);
|
|
||||||
return msgOut;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_handlePost(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
const GWEN_STRINGLIST *sl;
|
|
||||||
const char *protocol;
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "POST:");
|
|
||||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
|
||||||
GWEN_DB_Dump(db, 2);
|
|
||||||
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
|
|
||||||
|
|
||||||
s=GWEN_StringList_StringAt(sl, 1);
|
|
||||||
if (s && *s) {
|
|
||||||
if (strcasecmp(s, "add")==0)
|
|
||||||
return _handlePostAdd(uh, rq);
|
|
||||||
else if (strcasecmp(s, "edit")==0)
|
|
||||||
return _handlePostEdit(uh, rq, GWEN_StringList_StringAsIntAt(sl, 2, 0));
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Invalid url (2nd member missing)");
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _handleGetList(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
uint32_t perms;
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "LIST");
|
|
||||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
|
||||||
if (perms & xuh->neededPermsList) {
|
|
||||||
_listObjectsIntoBuffer(uh, pageBuf);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<p>%s</p>", I18N("No permissions to see list of objects."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _handleGetAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
uint32_t perms;
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "ADD");
|
|
||||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
|
||||||
if (perms & xuh->neededPermsAdd) {
|
|
||||||
_writeAddPage(uh, rq, NULL, pageBuf);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "No permissions to add.");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"red\">%s</font></p>", I18N("No permissions to add an object."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _handleGetEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
uint32_t perms;
|
|
||||||
|
|
||||||
DBG_ERROR(NULL, "EDIT");
|
|
||||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
|
||||||
if (perms & xuh->neededPermsEdit) {
|
|
||||||
if (id>0) {
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
db=_findObjectByIdAndReturnAsDb(uh, id);
|
|
||||||
if (db) {
|
|
||||||
_writeEditPage(uh, rq, db, pageBuf);
|
|
||||||
GWEN_DB_Group_free(db);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Object %d not found", id);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"red\">%s</font></p>", I18N("Object not found."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "Missing object id");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<p><font color=\"red\">%s</font></p>", I18N("Missing or invalid object id."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "No permissions to edit.");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<p>%s</p>", I18N("No permissions to edit."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_handlePostAdd(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
uint32_t perms;
|
|
||||||
|
|
||||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
|
||||||
if (perms & xuh->neededPermsAdd)
|
|
||||||
return _addOrEditAndCreateResponse(uh, rq, 0, _writeAddPage);
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "No perms to add object");
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 403, "Forbidden",
|
|
||||||
AQH_HttpRequest_GetProtocol(rq), NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_handlePostEdit(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
uint32_t perms;
|
|
||||||
|
|
||||||
perms=AQH_HttpRequest_GetModulePerms(rq);
|
|
||||||
if (perms & xuh->neededPermsEdit) {
|
|
||||||
return _addOrEditAndCreateResponse(uh, rq, id, _writeEditPage);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "No perms to edit");
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 403, "Forbidden",
|
|
||||||
AQH_HttpRequest_GetProtocol(rq), NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_addOrEditAndCreateResponse(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, int id, AQH_HTTP_URLHANDLER_WRITEPAGE_CB cb)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
db=AQH_HttpRequest_GetDbPostBody(rq);
|
|
||||||
rv=_addOrEditObject(uh, db, id);
|
|
||||||
if (rv<0)
|
|
||||||
return AQH_BaseHttpUrlHandler_CreateResponseForErrorCode(uh, rq, rv, cb, db);
|
|
||||||
return AQH_HttpService_CreateRedirectingResponseMsg(sv, AQH_HttpRequest_GetProtocol(rq), xuh->urlForObjectList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh->addOrEditObjectFn)
|
|
||||||
return xuh->addOrEditObjectFn(uh, db, id);
|
|
||||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh->findObjectByIdAndReturnAsDbFn)
|
|
||||||
return xuh->findObjectByIdAndReturnAsDbFn(uh, id);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh->writeAddPageFn)
|
|
||||||
return xuh->writeAddPageFn(uh, rq, dbValues, pageBuf);
|
|
||||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh->writeEditPageFn)
|
|
||||||
return xuh->writeEditPageFn(uh, rq, dbValues, pageBuf);
|
|
||||||
return GWEN_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_OBJECTS *xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_OBJECTS, uh);
|
|
||||||
|
|
||||||
if (xuh->listObjectsIntoBufferFn)
|
|
||||||
xuh->listObjectsIntoBufferFn(uh, pageBuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_OBJECTS_H
|
|
||||||
#define AQHOME_STORAGE_U_OBJECTS_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_ObjectsHttpUrlHandler_new(AQH_SERVICE *sv,
|
|
||||||
uint32_t neededPermsList,
|
|
||||||
uint32_t neededPermsAdd,
|
|
||||||
uint32_t neededPermsDel,
|
|
||||||
uint32_t neededPermsEdit,
|
|
||||||
const char *urlForObjectList);
|
|
||||||
|
|
||||||
|
|
||||||
typedef int (*AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN)(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
|
|
||||||
typedef GWEN_DB_NODE* (*AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN)(AQH_HTTP_URLHANDLER *uh, int id);
|
|
||||||
typedef int (*AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN)(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq,
|
|
||||||
GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
typedef int (*AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN)(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq,
|
|
||||||
GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
typedef void (*AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN)(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN fn);
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN fn);
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN fn);
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(AQH_HTTP_URLHANDLER *uh, AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN fn);
|
|
||||||
void AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN fn);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_OBJECTS_P_H
|
|
||||||
#define AQHOME_STORAGE_U_OBJECTS_P_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_objects.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/stringlist.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct AQH_URLHANDLER_OBJECTS AQH_URLHANDLER_OBJECTS;
|
|
||||||
struct AQH_URLHANDLER_OBJECTS {
|
|
||||||
uint32_t neededPermsList;
|
|
||||||
uint32_t neededPermsAdd;
|
|
||||||
uint32_t neededPermsDel;
|
|
||||||
uint32_t neededPermsEdit; /* e.g. AQHOME_HTTP_PERMS_EDIT_ROOM */
|
|
||||||
|
|
||||||
char *urlForObjectList;
|
|
||||||
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_ADDOREDITOBJECT_FN addOrEditObjectFn;
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_FINDOBJECTBYIDANDRETURNASDB_FN findObjectByIdAndReturnAsDbFn;
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_WRITEADDPAGE_FN writeAddPageFn;
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_WRITEEDITPAGE_FN writeEditPageFn;
|
|
||||||
AQH_OBJECTSHTTPURLHANDLER_LISTOBJECTSINTOBUFFER_FN listObjectsIntoBufferFn;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,272 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_rooms.h"
|
|
||||||
#include "./u_objects.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
|
|
||||||
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
|
|
||||||
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _setFromObject(AQH_ROOM *r, const AQH_ROOM *srcRoom);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_ObjectsHttpUrlHandler_new(sv,
|
|
||||||
AQHOME_HTTP_PERMS_LIST_ROOMS,
|
|
||||||
AQHOME_HTTP_PERMS_ADD_ROOM,
|
|
||||||
AQHOME_HTTP_PERMS_DEL_ROOM,
|
|
||||||
AQHOME_HTTP_PERMS_EDIT_ROOM,
|
|
||||||
"/rooms/list");
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
AQH_ROOM *newRoom;
|
|
||||||
const char *roomName;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
newRoom=AQH_Room_fromDb(db);
|
|
||||||
|
|
||||||
roomName=AQH_Room_GetName(newRoom);
|
|
||||||
if (!(roomName && *roomName)) {
|
|
||||||
DBG_INFO(NULL, "Missing room name");
|
|
||||||
AQH_Room_free(newRoom);
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_LockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error locking storage");
|
|
||||||
AQH_Room_free(newRoom);
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id>0) {
|
|
||||||
AQH_ROOM *r;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Edit existing room");
|
|
||||||
r=AQH_Storage_GetRoomById(sto, id);
|
|
||||||
if (r==NULL) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "Room %d not found", id);
|
|
||||||
AQH_Room_free(newRoom);
|
|
||||||
return GWEN_ERROR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
AQH_Room_SetId(r, id);
|
|
||||||
_setFromObject(r, newRoom);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AQH_ROOM *r;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Adding new room");
|
|
||||||
r=AQH_Storage_GetRoomByName(sto, roomName);
|
|
||||||
if (r) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "Room %s exists", roomName);
|
|
||||||
AQH_Room_free(newRoom);
|
|
||||||
return GWEN_ERROR_FOUND;
|
|
||||||
}
|
|
||||||
r=AQH_Room_new();
|
|
||||||
AQH_Room_SetId(r, 0);
|
|
||||||
_setFromObject(r, newRoom);
|
|
||||||
AQH_Storage_AddRoom(sto, r);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
AQH_Room_free(newRoom);
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error unlocking storage");
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _setFromObject(AQH_ROOM *r, const AQH_ROOM *srcRoom)
|
|
||||||
{
|
|
||||||
AQH_Room_SetName(r, AQH_Room_GetName(srcRoom));
|
|
||||||
AQH_Room_SetDescription(r, AQH_Room_GetDescription(srcRoom));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_ROOM *r;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
r=AQH_Storage_GetRoomById(sto, id);
|
|
||||||
if (r) {
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
db=GWEN_DB_Group_new("room");
|
|
||||||
AQH_Room_toDb(r, db);
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/rooms/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Add Room"));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/rooms/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Edit Room"),
|
|
||||||
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <table>"
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"name\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
|
|
||||||
" </tr>"
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"description\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"description\" value=\"%s\" ></td>"
|
|
||||||
" </tr>"
|
|
||||||
" </table>",
|
|
||||||
I18N("Name"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"",
|
|
||||||
I18N("Description"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "description", 0, ""):"");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_ROOM_LIST *rl;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2>"
|
|
||||||
"<table class=\"dataTable\">"
|
|
||||||
"<thead>"
|
|
||||||
" <tr><th>%s</th><th>%s</th><th></th></tr>"
|
|
||||||
"</thead>",
|
|
||||||
I18N("Rooms"),
|
|
||||||
I18N("Name"),
|
|
||||||
I18N("Description"));
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
|
|
||||||
rl=AQH_Storage_GetRoomList(sto);
|
|
||||||
if (rl) {
|
|
||||||
const AQH_ROOM *r;
|
|
||||||
|
|
||||||
r=AQH_Room_List_First(rl);
|
|
||||||
while(r) {
|
|
||||||
long unsigned int id;
|
|
||||||
const char *name;
|
|
||||||
const char *descr;
|
|
||||||
|
|
||||||
id=(long unsigned int) AQH_Room_GetId(r);
|
|
||||||
name=AQH_Room_GetName(r);
|
|
||||||
descr=AQH_Room_GetDescription(r);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td>%s</td><td>%s</td>"
|
|
||||||
"<td><a href=\"/rooms/edit/%lu\">"
|
|
||||||
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
|
|
||||||
"</tr>",
|
|
||||||
name?name:"", descr?descr:"", id);
|
|
||||||
r=AQH_Room_List_Next(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/rooms/add\">%s</a><br>", I18N("Add Room"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_ROOMS_H
|
|
||||||
#define AQHOME_STORAGE_U_ROOMS_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_RoomsHttpUrlHandler_new(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_static_p.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
#include "aqhome/http/httpservice.h"
|
|
||||||
#include "aqhome/http/httpservice_http.h"
|
|
||||||
#include "aqhome/http/httpservice_conf.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_INHERIT(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
|
|
||||||
static int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq);
|
|
||||||
static void _readFileList(AQH_HTTP_URLHANDLER *uh);
|
|
||||||
static GWEN_BUFFER *_readFileIntoBuffer(AQH_HTTP_URLHANDLER *uh, const char *requestedFilename);
|
|
||||||
static const char *_getContentTypeFromFilename(const char *filename);
|
|
||||||
static GWEN_MSG *_createFileResponseMsg(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
const char *protocol,
|
|
||||||
const char *contentType,
|
|
||||||
const uint8_t *ptr, uint32_t len);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_StaticHttpUrlHandler_new(AQH_SERVICE *sv, const char *folder)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
AQH_URLHANDLER_STATIC *xuh;
|
|
||||||
|
|
||||||
uh=AQH_HttpUrlHandler_new(sv);
|
|
||||||
GWEN_NEW_OBJECT(AQH_URLHANDLER_STATIC, xuh);
|
|
||||||
GWEN_INHERIT_SETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh, xuh, _freeData);
|
|
||||||
|
|
||||||
AQH_HttpUrlHandler_SetFolder(uh, folder);
|
|
||||||
AQH_HttpUrlHandler_SetHandleFn(uh, _handleUrl);
|
|
||||||
|
|
||||||
_readFileList(uh);
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _freeData(void *bp, void *p)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_STATIC *xuh;
|
|
||||||
|
|
||||||
xuh=(AQH_URLHANDLER_STATIC*)p;
|
|
||||||
GWEN_StringList_free(xuh->fileList);
|
|
||||||
GWEN_FREE_OBJECT(xuh);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _handleUrl(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
const char *protocol;
|
|
||||||
const char *cmd;
|
|
||||||
GWEN_MSG *msgOut;
|
|
||||||
|
|
||||||
AQH_HttpService_SetupModuleAndPerms(AQH_HttpUrlHandler_GetHttpService(uh), rq, "aqhome");
|
|
||||||
AQH_HttpRequest_SetupUrlPathMembers(rq);
|
|
||||||
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
cmd=AQH_HttpRequest_GetCommand(rq);
|
|
||||||
if (cmd && *cmd) {
|
|
||||||
if (strcasecmp(cmd, "GET")==0)
|
|
||||||
msgOut=_handleGet(uh, rq);
|
|
||||||
else {
|
|
||||||
msgOut=AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 405, "Method not allowed", protocol, NULL);
|
|
||||||
}
|
|
||||||
AQH_HttpRequest_SetResponseMsg(rq, msgOut);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "No command in request");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_handleGet(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_STATIC *xuh;
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
const char *protocol;
|
|
||||||
const GWEN_STRINGLIST *sl;
|
|
||||||
|
|
||||||
xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh);
|
|
||||||
if (xuh==NULL) {
|
|
||||||
DBG_ERROR(NULL, "Not a AQH_URLHANDLER_STATIC object");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
protocol=AQH_HttpRequest_GetProtocol(rq);
|
|
||||||
|
|
||||||
/* handle middle part (header - middle - footer) */
|
|
||||||
sl=AQH_HttpRequest_GetUrlPathMembers(rq);
|
|
||||||
if (sl) {
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
s=GWEN_StringList_StringAt(sl, 1);
|
|
||||||
if (!(s && *s)) {
|
|
||||||
DBG_ERROR(NULL, "Invalid url (2nd member is [%s])", s);
|
|
||||||
return AQH_HttpService_CreateResponseMsg(sv, 404, "Not found", protocol, NULL);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
GWEN_BUFFER *fileBuf;
|
|
||||||
const char *contentType;
|
|
||||||
GWEN_MSG *msgOut;
|
|
||||||
|
|
||||||
contentType=_getContentTypeFromFilename(s);
|
|
||||||
DBG_INFO(NULL, "Reading file \"%s\" (%s)", s, contentType);
|
|
||||||
fileBuf=_readFileIntoBuffer(uh, s);
|
|
||||||
if (fileBuf==NULL) {
|
|
||||||
DBG_INFO(NULL, "here");
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 404, "Not found", protocol, NULL);
|
|
||||||
}
|
|
||||||
msgOut=_createFileResponseMsg(uh, protocol, contentType,
|
|
||||||
(const uint8_t*) GWEN_Buffer_GetStart(fileBuf), GWEN_Buffer_GetUsedBytes(fileBuf));
|
|
||||||
GWEN_Buffer_free(fileBuf);
|
|
||||||
return msgOut;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(NULL, "No list of url members");
|
|
||||||
return AQH_HttpService_CreateResponseMsg(AQH_HttpUrlHandler_GetHttpService(uh), 500, "Internal Error", protocol, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _readFileList(AQH_HTTP_URLHANDLER *uh)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_STATIC *xuh;
|
|
||||||
const char *folder;
|
|
||||||
|
|
||||||
xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh);
|
|
||||||
|
|
||||||
GWEN_StringList_free(xuh->fileList);
|
|
||||||
xuh->fileList=NULL;
|
|
||||||
folder=AQH_HttpUrlHandler_GetFolder(uh);
|
|
||||||
if (folder && *folder) {
|
|
||||||
GWEN_STRINGLIST *fileList;
|
|
||||||
|
|
||||||
fileList=AQH_HttpService_GetFolderFileList(folder, NULL, 1);
|
|
||||||
if (fileList) {
|
|
||||||
GWEN_StringList_RemoveString(fileList, ".");
|
|
||||||
GWEN_StringList_RemoveString(fileList, "..");
|
|
||||||
GWEN_StringList_free(xuh->fileList);
|
|
||||||
xuh->fileList=fileList;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "No file list (empty folder?)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_BUFFER *_readFileIntoBuffer(AQH_HTTP_URLHANDLER *uh, const char *requestedFilename)
|
|
||||||
{
|
|
||||||
AQH_URLHANDLER_STATIC *xuh;
|
|
||||||
const char *folder;
|
|
||||||
|
|
||||||
xuh=GWEN_INHERIT_GETDATA(AQH_HTTP_URLHANDLER, AQH_URLHANDLER_STATIC, uh);
|
|
||||||
folder=AQH_HttpUrlHandler_GetFolder(uh);
|
|
||||||
|
|
||||||
if (!(xuh->fileList && GWEN_StringList_Count(xuh->fileList)>0)) {
|
|
||||||
DBG_INFO(NULL, "Reading file list for folder \"%s\"", folder);
|
|
||||||
_readFileList(uh);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(xuh->fileList && GWEN_StringList_Count(xuh->fileList)>0)) {
|
|
||||||
DBG_INFO(NULL, "No file list (empty or missing/bad folder? Permissions?");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GWEN_StringList_HasString(xuh->fileList, requestedFilename)) {
|
|
||||||
GWEN_BUFFER *nameBuf;
|
|
||||||
GWEN_BUFFER *fileBuf;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
fileBuf=GWEN_Buffer_new(0, 1024, 0, 1);
|
|
||||||
nameBuf=GWEN_Buffer_new(0, 256, 0, 1);
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, folder);
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, GWEN_DIR_SEPARATOR_S);
|
|
||||||
GWEN_Buffer_AppendString(nameBuf, requestedFilename);
|
|
||||||
DBG_INFO(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(nameBuf));
|
|
||||||
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(nameBuf), fileBuf);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error reading file \"%s\" (%d)", GWEN_Buffer_GetStart(nameBuf), rv);
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
GWEN_Buffer_free(fileBuf);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
GWEN_Buffer_free(nameBuf);
|
|
||||||
return fileBuf;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_INFO(NULL, "File \"%s\" not found in folder \"%s\"", requestedFilename, folder);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_MSG *_createFileResponseMsg(AQH_HTTP_URLHANDLER *uh,
|
|
||||||
const char *protocol,
|
|
||||||
const char *contentType,
|
|
||||||
const uint8_t *ptr, uint32_t len)
|
|
||||||
{
|
|
||||||
GWEN_BUFFER *buf;
|
|
||||||
GWEN_MSG *msg;
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
buf=GWEN_Buffer_new(0, len+256, 0, 1);
|
|
||||||
AQH_HttpService_AddStatusLine(AQH_HttpUrlHandler_GetHttpService(uh), 200, "OK", protocol, buf);
|
|
||||||
|
|
||||||
db=GWEN_DB_Group_new("header");
|
|
||||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Connection", "Keep-Alive");
|
|
||||||
GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Type", contentType);
|
|
||||||
GWEN_DB_SetIntValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Content-Length", len);
|
|
||||||
AQH_HttpService_AddHeader(AQH_HttpUrlHandler_GetHttpService(uh), db, buf);
|
|
||||||
GWEN_DB_Group_free(db);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendBytes(buf, (const char *) ptr, len);
|
|
||||||
|
|
||||||
msg=GWEN_Msg_fromBytes((const uint8_t*)GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf));
|
|
||||||
GWEN_Buffer_free(buf);
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *_getContentTypeFromFilename(const char *filename)
|
|
||||||
{
|
|
||||||
if (filename) {
|
|
||||||
const char *s;
|
|
||||||
|
|
||||||
s=strrchr(filename, '.');
|
|
||||||
if (s) {
|
|
||||||
if (strcasecmp(s, ".png")==0)
|
|
||||||
return "image/png";
|
|
||||||
else if (strcasecmp(s, ".jpg")==0)
|
|
||||||
return "image/jpg";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "application/x-binary";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_STATIC_H
|
|
||||||
#define AQHOME_STORAGE_U_STATIC_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/endpoint.h>
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_StaticHttpUrlHandler_new(AQH_SERVICE *sv, const char *folder);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_STATIC_P_H
|
|
||||||
#define AQHOME_STORAGE_U_STATIC_P_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_static.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/stringlist.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct AQH_URLHANDLER_STATIC AQH_URLHANDLER_STATIC;
|
|
||||||
struct AQH_URLHANDLER_STATIC {
|
|
||||||
GWEN_STRINGLIST *fileList;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,340 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "./u_values.h"
|
|
||||||
#include "./u_objects.h"
|
|
||||||
#include "./aqhomehttp.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/gwenhywfar.h>
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/i18n.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* defines
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id);
|
|
||||||
static GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id);
|
|
||||||
static int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf);
|
|
||||||
|
|
||||||
static void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf);
|
|
||||||
static void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv)
|
|
||||||
{
|
|
||||||
AQH_HTTP_URLHANDLER *uh;
|
|
||||||
|
|
||||||
uh=AQH_ObjectsHttpUrlHandler_new(sv,
|
|
||||||
AQHOME_HTTP_PERMS_LIST_VALUES,
|
|
||||||
AQHOME_HTTP_PERMS_ADD_VALUE,
|
|
||||||
AQHOME_HTTP_PERMS_DEL_VALUE,
|
|
||||||
AQHOME_HTTP_PERMS_EDIT_VALUE,
|
|
||||||
"/values/list");
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetAddOrEditObjectFn(uh, _addOrEditObject);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetFindObjectByIdAndReturnAsDbFn(uh, _findObjectByIdAndReturnAsDb);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteAddPageFn(uh, _writeAddPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetWriteEditPageFn(uh, _writeEditPage);
|
|
||||||
AQH_ObjectsHttpUrlHandler_SetListObjectsIntoBufferFn(uh, _listObjectsIntoBuffer);
|
|
||||||
|
|
||||||
return uh;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _addOrEditObject(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *db, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
AQH_VALUE *newValue;
|
|
||||||
const char *valueName;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
newValue=AQH_Value_fromDb(db);
|
|
||||||
|
|
||||||
valueName=AQH_Value_GetNameForSystem(newValue);
|
|
||||||
if (!(valueName && *valueName)) {
|
|
||||||
DBG_INFO(NULL, "Missing value name");
|
|
||||||
AQH_Value_free(newValue);
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_LockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error locking storage");
|
|
||||||
AQH_Value_free(newValue);
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id>0) {
|
|
||||||
AQH_VALUE *value;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Edit existing value");
|
|
||||||
value=AQH_Storage_GetValueById(sto, id);
|
|
||||||
if (value==NULL) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "Value %d not found", id);
|
|
||||||
AQH_Value_free(newValue);
|
|
||||||
return GWEN_ERROR_NOT_FOUND;
|
|
||||||
}
|
|
||||||
AQH_Value_SetId(value, id);
|
|
||||||
_setFromObject(value, newValue);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AQH_VALUE *value;
|
|
||||||
|
|
||||||
DBG_INFO(NULL, "Adding new value");
|
|
||||||
value=AQH_Storage_GetValueByName(sto, valueName);
|
|
||||||
if (value) {
|
|
||||||
AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
DBG_ERROR(NULL, "Value %s exists", valueName);
|
|
||||||
AQH_Value_free(newValue);
|
|
||||||
return GWEN_ERROR_FOUND;
|
|
||||||
}
|
|
||||||
value=AQH_Value_new();
|
|
||||||
AQH_Value_SetId(value, 0);
|
|
||||||
_setFromObject(value, newValue);
|
|
||||||
AQH_Storage_AddValue(sto, value);
|
|
||||||
AQH_Storage_AddRuntimeFlags(sto, AQH_STORAGE_RTFLAGS_MODIFIED);
|
|
||||||
}
|
|
||||||
AQH_Value_free(newValue);
|
|
||||||
|
|
||||||
rv=AqHomeHttpService_UnlockStorage(sv);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(NULL, "Error unlocking storage");
|
|
||||||
return GWEN_ERROR_IO;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _setFromObject(AQH_VALUE *value, const AQH_VALUE *srcValue)
|
|
||||||
{
|
|
||||||
AQH_Value_SetName(value, AQH_Value_GetName(srcValue));
|
|
||||||
AQH_Value_SetTopicId(value, AQH_Value_GetTopicId(srcValue));
|
|
||||||
AQH_Value_SetValueType(value, AQH_Value_GetValueType(srcValue));
|
|
||||||
AQH_Value_SetValueUnits(value, AQH_Value_GetValueUnits(srcValue));
|
|
||||||
AQH_Value_SetDataPath(value, AQH_Value_GetDataPath(srcValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_DB_NODE *_findObjectByIdAndReturnAsDb(AQH_HTTP_URLHANDLER *uh, int id)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_VALUE *value;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
value=AQH_Storage_GetValueById(sto, id);
|
|
||||||
if (value) {
|
|
||||||
GWEN_DB_NODE *db;
|
|
||||||
|
|
||||||
db=GWEN_DB_Group_new("value");
|
|
||||||
AQH_Value_toDb(value, db);
|
|
||||||
return db;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeAddPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/values/add\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Add Value"));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeEditPage(AQH_HTTP_URLHANDLER *uh, AQH_HTTP_REQUEST *rq, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2><br>\n"
|
|
||||||
"<form action=\"/values/edit/%lu\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">",
|
|
||||||
I18N("Edit Value"),
|
|
||||||
(long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0));
|
|
||||||
_writeEditingTable(uh, dbValues, pageBuf);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<input type=\"submit\" value=\"%s\"></form>", I18N("Submit"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _writeEditingTable(AQH_HTTP_URLHANDLER *uh, GWEN_DB_NODE *dbValues, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_MQTT_TOPIC_LIST *topicList;
|
|
||||||
unsigned long int selectedTopicId=0;
|
|
||||||
char numbuf[16];
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
topicList=AQH_Storage_GetMqttTopicList(sto);
|
|
||||||
|
|
||||||
selectedTopicId=(unsigned long int)(dbValues?GWEN_DB_GetIntValue(dbValues, "TopicId", 0, 0):0);
|
|
||||||
snprintf(numbuf, sizeof(numbuf)-1, "%lu", selectedTopicId);
|
|
||||||
numbuf[sizeof(numbuf)-1]=0;
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <table>"
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"name\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"name\" value=\"%s\" required></td>"
|
|
||||||
" </tr>",
|
|
||||||
I18N("Name"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "name", 0, ""):"");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td><label for=\"topicId\">%s: </label></td>"
|
|
||||||
"<td><select id=\"topicId\" name=\"topicId\">",
|
|
||||||
I18N("Topic"));
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"0\">%s</option>", I18N("-- select topic --"));
|
|
||||||
|
|
||||||
if (topicList) {
|
|
||||||
const AQH_MQTT_TOPIC *topic;
|
|
||||||
|
|
||||||
topic=AQH_MqttTopic_List_First(topicList);
|
|
||||||
while(topic) {
|
|
||||||
const char *topicName;
|
|
||||||
|
|
||||||
topicName=AQH_MqttTopic_GetTopic(topic);
|
|
||||||
if (topicName && *topicName) {
|
|
||||||
snprintf(numbuf, sizeof(numbuf)-1, "%lu", (unsigned long int) AQH_MqttTopic_GetId(topic));
|
|
||||||
numbuf[sizeof(numbuf)-1]=0;
|
|
||||||
if (selectedTopicId && AQH_MqttTopic_GetId(topic)==selectedTopicId)
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\" selected>%s</option>", numbuf, topicName);
|
|
||||||
else
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "<option value=\"%s\">%s</option>", numbuf, topicName);
|
|
||||||
}
|
|
||||||
topic=AQH_MqttTopic_List_Next(topic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</select></td></tr>");
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"valueUnits\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"valueUnits\" value=\"%s\"></td>"
|
|
||||||
" </tr>",
|
|
||||||
I18N("Units"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "valueUnits", 0, ""):"");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
" <tr>"
|
|
||||||
" <td><label for=\"dataPath\">%s: </label></td>"
|
|
||||||
" <td><input type=\"text\" name=\"dataPath\" value=\"%s\"></td>"
|
|
||||||
" </tr>"
|
|
||||||
" </table>",
|
|
||||||
I18N("Data Path (JSON)"),
|
|
||||||
dbValues?GWEN_DB_GetCharValue(dbValues, "dataPath", 0, ""):"");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _listObjectsIntoBuffer(AQH_HTTP_URLHANDLER *uh, GWEN_BUFFER *pageBuf)
|
|
||||||
{
|
|
||||||
AQH_SERVICE *sv;
|
|
||||||
AQH_STORAGE *sto;
|
|
||||||
const AQH_VALUE_LIST *rl;
|
|
||||||
|
|
||||||
sv=AQH_HttpUrlHandler_GetHttpService(uh);
|
|
||||||
sto=AqHomeHttpService_GetStorage(sv);
|
|
||||||
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<h2>%s</h2>"
|
|
||||||
"<table class=\"dataTable\">"
|
|
||||||
"<thead>"
|
|
||||||
" <tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th></th></tr>"
|
|
||||||
"</thead>",
|
|
||||||
I18N("Values"),
|
|
||||||
I18N("Name"),
|
|
||||||
I18N("Topic"),
|
|
||||||
I18N("Units"),
|
|
||||||
I18N("Data Path"));
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "<tbody>");
|
|
||||||
rl=AQH_Storage_GetValueList(sto);
|
|
||||||
if (rl) {
|
|
||||||
const AQH_VALUE *value;
|
|
||||||
|
|
||||||
value=AQH_Value_List_First(rl);
|
|
||||||
while(value) {
|
|
||||||
long unsigned int id;
|
|
||||||
int topicId;
|
|
||||||
const char *name;
|
|
||||||
const char *topicName=NULL;
|
|
||||||
const char *valueUnits;
|
|
||||||
const char *dataPath;
|
|
||||||
const AQH_MQTT_TOPIC *topic=NULL;
|
|
||||||
|
|
||||||
id=(long unsigned int) AQH_Value_GetId(value);
|
|
||||||
topicId=(long unsigned int) AQH_Value_GetTopicId(value);
|
|
||||||
if (topicId>0)
|
|
||||||
topic=AQH_Storage_GetMqttTopicById(sto, topicId);
|
|
||||||
if (topic)
|
|
||||||
topicName=AQH_MqttTopic_GetTopic(topic);
|
|
||||||
|
|
||||||
name=AQH_Value_GetName(value);
|
|
||||||
valueUnits=AQH_Value_GetValueUnits(value);
|
|
||||||
dataPath=AQH_Value_GetDataPath(value);
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf,
|
|
||||||
"<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td>"
|
|
||||||
"<td><a href=\"/values/edit/%lu\">"
|
|
||||||
"<IMG src=\"/pics/edit.png\" width=32 height=32 align=left border=0></a></td>"
|
|
||||||
"</tr>",
|
|
||||||
name?name:"",
|
|
||||||
topicName?topicName:"",
|
|
||||||
valueUnits?valueUnits:"",
|
|
||||||
dataPath?dataPath:"",
|
|
||||||
id);
|
|
||||||
value=AQH_Value_List_Next(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GWEN_Buffer_AppendString(pageBuf, "</tbody>");
|
|
||||||
GWEN_Buffer_AppendArgs(pageBuf, "</table><a href=\"/values/add\">%s</a><br>", I18N("Add Value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project AqHome.
|
|
||||||
* AqHome (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQHOME_STORAGE_U_VALUES_H
|
|
||||||
#define AQHOME_STORAGE_U_VALUES_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/http/urlhandler.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_HTTP_URLHANDLER *AQH_ValuesHttpUrlHandler_new(AQH_SERVICE *sv);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user