From c5171714b296ef15588ae2ed1bb48f5979bef019 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Fri, 11 Aug 2023 01:24:31 +0200 Subject: [PATCH] added url handler for mqtt topics. --- apps/aqhome-storage/0BUILD | 2 + apps/aqhome-storage/init_http.c | 21 ++ apps/aqhome-storage/u_mqtttopics.c | 340 +++++++++++++++++++++++++++++ apps/aqhome-storage/u_mqtttopics.h | 23 ++ aqhome/data/mqtttopic.t2d | 4 +- aqhome/data/storage.c | 2 +- 6 files changed, 389 insertions(+), 3 deletions(-) create mode 100644 apps/aqhome-storage/u_mqtttopics.c create mode 100644 apps/aqhome-storage/u_mqtttopics.h diff --git a/apps/aqhome-storage/0BUILD b/apps/aqhome-storage/0BUILD index 99d9280..7fe94e3 100644 --- a/apps/aqhome-storage/0BUILD +++ b/apps/aqhome-storage/0BUILD @@ -49,6 +49,7 @@ u_objects_p.h u_rooms.h u_devices.h + u_mqtttopics.h u_static.h u_static_p.h aqhomehttp.h @@ -70,6 +71,7 @@ u_objects.c u_rooms.c u_devices.c + u_mqtttopics.c u_static.c main.c aqhomehttp.c diff --git a/apps/aqhome-storage/init_http.c b/apps/aqhome-storage/init_http.c index 1fbb070..895be5b 100644 --- a/apps/aqhome-storage/init_http.c +++ b/apps/aqhome-storage/init_http.c @@ -17,6 +17,7 @@ #include "./u_login.h" #include "./u_rooms.h" #include "./u_devices.h" +#include "./u_mqtttopics.h" #include "./u_static.h" #include "aqhome/msg/endpoint_tty.h" @@ -75,6 +76,7 @@ static GWEN_MSG_ENDPOINT *_acceptHttpFn(GWEN_MSG_ENDPOINT *ep, GWEN_SOCKET *sk, 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_static(AQHOME_STORAGE *aqh); @@ -126,6 +128,12 @@ int AqHomeStorage_SetupHttp(AQHOME_STORAGE *aqh, GWEN_DB_NODE *dbArgs) return rv; } + rv=_createUrlHandler_topics(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); @@ -270,6 +278,19 @@ int _createUrlHandler_devices(AQHOME_STORAGE *aqh) +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_static(AQHOME_STORAGE *aqh) { AQH_HTTP_URLHANDLER *uh; diff --git a/apps/aqhome-storage/u_mqtttopics.c b/apps/aqhome-storage/u_mqtttopics.c new file mode 100644 index 0000000..4c0fe2b --- /dev/null +++ b/apps/aqhome-storage/u_mqtttopics.c @@ -0,0 +1,340 @@ +/**************************************************************************** + * 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 +#endif + + +#include "./u_mqtttopics.h" +#include "./u_objects.h" +#include "./aqhomehttp.h" + +#include +#include +#include + + + +/* ------------------------------------------------------------------------------------------------ + * 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, + "

%s


\n" + "
", + I18N("Add MQTT Topic")); + _writeEditingTable(uh, dbValues, pageBuf); + GWEN_Buffer_AppendArgs(pageBuf, "
", 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, + "

%s


\n" + "
", + I18N("Edit MQTT Topic"), + (long unsigned int)(dbValues?GWEN_DB_GetIntValue(dbValues, "id", 0, 0):0)); + _writeEditingTable(uh, dbValues, pageBuf); + GWEN_Buffer_AppendArgs(pageBuf, "
", 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_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, + " " + " " + " " + " " + " ", + I18N("MQTT Topic"), + dbValues?GWEN_DB_GetCharValue(dbValues, "topic", 0, ""):""); + + GWEN_Buffer_AppendArgs(pageBuf, + "" + ""); + + /* data type */ + GWEN_Buffer_AppendArgs(pageBuf, + "" + ""); + + GWEN_Buffer_AppendString(pageBuf, "
"); +} + + + +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, + "

%s

" + "" + "" + " " + "", + I18N("Mqtt Topics"), + I18N("Topic"), + I18N("Device"), + I18N("Datatype")); + GWEN_Buffer_AppendString(pageBuf, ""); + 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, + "" + "" + "", + topic?topic:"", + deviceName?deviceName:"", + AQH_MqttTopicType_toString(dataType), + id); + mqttTopic=AQH_MqttTopic_List_Next(mqttTopic); + } + } + GWEN_Buffer_AppendString(pageBuf, ""); + GWEN_Buffer_AppendArgs(pageBuf, "
%s%s%s
%s%s%s" + "
%s
", I18N("Add MqttTopic")); +} + + + + + diff --git a/apps/aqhome-storage/u_mqtttopics.h b/apps/aqhome-storage/u_mqtttopics.h new file mode 100644 index 0000000..c2f5159 --- /dev/null +++ b/apps/aqhome-storage/u_mqtttopics.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * 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 + + diff --git a/aqhome/data/mqtttopic.t2d b/aqhome/data/mqtttopic.t2d index 105fdda..cd6a1f9 100644 --- a/aqhome/data/mqtttopic.t2d +++ b/aqhome/data/mqtttopic.t2d @@ -58,14 +58,14 @@ - + 0 0 public own with_getbymember - + 0 0 public diff --git a/aqhome/data/storage.c b/aqhome/data/storage.c index 201d763..8146c08 100644 --- a/aqhome/data/storage.c +++ b/aqhome/data/storage.c @@ -179,7 +179,7 @@ AQH_MQTT_TOPIC *AQH_Storage_GetMqttTopicById(const AQH_STORAGE *sto, uint64_t id AQH_MQTT_TOPIC *AQH_Storage_GetMqttTopicByTopic(const AQH_STORAGE *sto, const char *topic) { - return sto?AQH_MqttTopic_List_GetByMqttTopic(sto->mqttTopicList, topic):NULL; + return sto?AQH_MqttTopic_List_GetByTopic(sto->mqttTopicList, topic):NULL; }