started working on storage service.

This commit is contained in:
Martin Preuss
2023-07-19 18:17:10 +02:00
parent 06b5ab26c8
commit db5d6cb980
20 changed files with 1443 additions and 1 deletions

View File

@@ -73,6 +73,8 @@
<headers dist="true" >
storage_p.h
storage_readxml.h
storage_writexml.h
</headers>
@@ -80,6 +82,8 @@
$(local/typefiles)
storage.c
storage_readxml.c
storage_writexml.c
</sources>

View File

@@ -11,8 +11,12 @@
#endif
#include "aqhome/data/storage_p.h"
#include "aqhome/data/storage_readxml.h"
#include "aqhome/data/storage_writexml.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/xml.h>
#include <gwenhywfar/directory.h>
@@ -25,7 +29,6 @@
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
@@ -37,6 +40,7 @@ AQH_STORAGE *AQH_Storage_new(void)
AQH_STORAGE *sto;
GWEN_NEW_OBJECT(AQH_STORAGE, sto);
sto->roomList=AQH_Room_List_new();
sto->deviceList=AQH_Device_List_new();
sto->mqttTopicList=AQH_MqttTopic_List_new();
sto->valueList=AQH_Value_List_new();
@@ -52,6 +56,8 @@ void AQH_Storage_free(AQH_STORAGE *sto)
AQH_Value_List_free(sto->valueList);
AQH_MqttTopic_List_free(sto->mqttTopicList);
AQH_Device_List_free(sto->deviceList);
AQH_Room_List_free(sto->roomList);
free(sto->stateFile);
GWEN_FREE_OBJECT(sto);
}
@@ -59,6 +65,23 @@ void AQH_Storage_free(AQH_STORAGE *sto)
const char *AQH_Storage_GetStateFile(const AQH_STORAGE *sto)
{
return sto?(sto->stateFile):NULL;
}
void AQH_Storage_SetStateFile(AQH_STORAGE *sto, const char *s)
{
if (sto) {
free(sto->stateFile);
sto->stateFile=s?strdup(s):NULL;
}
}
void AQH_Storage_AddDevice(AQH_STORAGE *sto, AQH_DEVICE *dev)
{
if (sto && dev) {
@@ -154,5 +177,43 @@ void AQH_Storage_HandleMqttPublish(AQH_STORAGE *sto, const char *topic, const ch
int AQH_Storage_Init(AQH_STORAGE *sto)
{
int rv;
rv=GWEN_Directory_GetPath(sto->stateFile,
GWEN_PATH_FLAGS_CHECKROOT | GWEN_PATH_FLAGS_PATHMUSTEXIST | GWEN_PATH_FLAGS_NAMEMUSTEXIST);
if (rv==0) {
rv=AQH_Storage_ReadStateFile(sto, sto->stateFile);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return rv;
}
}
else {
DBG_WARN(AQH_LOGDOMAIN, "State file \"%s\" not available, will try to create it later", sto->stateFile);
}
return 0;
}
int AQH_Storage_WriteState(AQH_STORAGE *sto)
{
int rv;
rv=AQH_Storage_WriteStateFile(sto, sto->stateFile);
if (rv<0) {
DBG_INFO(AQH_LOGDOMAIN, "here (%d)", rv);
return rv;
}
return 0;
}

View File

@@ -59,6 +59,13 @@ AQHOME_API void AQH_Storage_AddValue(AQH_STORAGE *sto, AQH_VALUE *value);
AQHOME_API AQH_VALUE_LIST *AQH_Storage_GetValueList(const AQH_STORAGE *sto);
AQHOME_API AQH_VALUE *AQH_Storage_GetValueById(const AQH_STORAGE *sto, uint64_t id);
AQHOME_API const char *AQH_Storage_GetStateFile(const AQH_STORAGE *sto);
AQHOME_API void AQH_Storage_SetStateFile(AQH_STORAGE *sto, const char *s);
AQHOME_API int AQH_Storage_Init(AQH_STORAGE *sto);
AQHOME_API int AQH_Storage_WriteState(AQH_STORAGE *sto);
AQHOME_API void AQH_Storage_HandleMqttPublish(AQH_STORAGE *sto, const char *topic, const char *value);

View File

@@ -13,15 +13,34 @@
#include "aqhome/data/storage.h"
#define AQH_STORAGE_XML_ELEMENTNAME_LASTIDS "lastIds"
#define AQH_STORAGE_XML_ELEMENTNAME_ROOMS "rooms"
#define AQH_STORAGE_XML_ELEMENTNAME_ROOM "room"
#define AQH_STORAGE_XML_ELEMENTNAME_DEVICES "devices"
#define AQH_STORAGE_XML_ELEMENTNAME_DEVICE "device"
#define AQH_STORAGE_XML_ELEMENTNAME_TOPICS "topics"
#define AQH_STORAGE_XML_ELEMENTNAME_TOPIC "topic"
#define AQH_STORAGE_XML_ELEMENTNAME_VALUES "values"
#define AQH_STORAGE_XML_ELEMENTNAME_VALUE "value"
struct AQH_STORAGE {
AQH_ROOM_LIST *roomList;
AQH_DEVICE_LIST *deviceList;
AQH_MQTT_TOPIC_LIST *mqttTopicList;
AQH_VALUE_LIST *valueList;
uint64_t lastRoomId;
uint64_t lastDeviceId;
uint64_t lastTopicId;
uint64_t lastValueId;
char *stateFile;
};

View File

@@ -0,0 +1,184 @@
/****************************************************************************
* This file is part of the project Gwenhywfar.
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "aqhome/data/storage_readxml.h"
#include "aqhome/data/storage_p.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/xml.h>
#include <gwenhywfar/directory.h>
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _readLastIdsFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _readRoomsFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _readDevicesFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _readTopicsFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _readValuesFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AQH_Storage_ReadStateFile(AQH_STORAGE *sto, const char *sFilename)
{
GWEN_XMLNODE *rootNode;
int rv;
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, NULL);
rv=GWEN_XML_ReadFile(rootNode, sFilename, GWEN_XML_FLAGS_DEFAULT);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error reading XML file \"%s\": %d", sFilename, rv);
GWEN_XMLNode_free(rootNode);
return rv;
}
_readLastIdsFromXml(sto, rootNode);
_readRoomsFromXml(sto, rootNode);
_readDevicesFromXml(sto, rootNode);
_readTopicsFromXml(sto, rootNode);
_readValuesFromXml(sto, rootNode);
return 0;
}
void _readLastIdsFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nLastIds;
nLastIds=GWEN_XMLNode_FindFirstTag(rootNode, AQH_STORAGE_XML_ELEMENTNAME_LASTIDS, NULL, NULL);
if (nLastIds) {
sto->lastRoomId=GWEN_XMLNode_GetIntValue(nLastIds, "lastRoomId", 0);
sto->lastDeviceId=GWEN_XMLNode_GetIntValue(nLastIds, "lastDeviceId", 0);
sto->lastTopicId=GWEN_XMLNode_GetIntValue(nLastIds, "lastTopicId", 0);
sto->lastValueId=GWEN_XMLNode_GetIntValue(nLastIds, "lastValueId", 0);
}
else {
sto->lastRoomId=0;
sto->lastDeviceId=0;
sto->lastTopicId=0;
sto->lastValueId=0;
}
}
void _readRoomsFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nRooms;
nRooms=GWEN_XMLNode_FindFirstTag(rootNode, AQH_STORAGE_XML_ELEMENTNAME_ROOMS, NULL, NULL);
if (nRooms) {
GWEN_XMLNODE *nRoom;
nRoom=GWEN_XMLNode_FindFirstTag(nRooms, AQH_STORAGE_XML_ELEMENTNAME_ROOM, NULL, NULL);
while(nRoom) {
AQH_ROOM *r;
r=AQH_Room_fromXml(nRoom);
if (r) {
AQH_Room_List_Add(r, sto->roomList);
}
nRoom=GWEN_XMLNode_FindNextTag(nRoom, AQH_STORAGE_XML_ELEMENTNAME_ROOM, NULL, NULL);
}
}
}
void _readDevicesFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nDevices;
nDevices=GWEN_XMLNode_FindFirstTag(rootNode, AQH_STORAGE_XML_ELEMENTNAME_DEVICES, NULL, NULL);
if (nDevices) {
GWEN_XMLNODE *nDevice;
nDevice=GWEN_XMLNode_FindFirstTag(nDevices, AQH_STORAGE_XML_ELEMENTNAME_DEVICE, NULL, NULL);
while(nDevice) {
AQH_DEVICE *device;
device=AQH_Device_fromXml(nDevice);
if (device) {
AQH_Device_List_Add(device, sto->deviceList);
}
nDevice=GWEN_XMLNode_FindNextTag(nDevice, AQH_STORAGE_XML_ELEMENTNAME_DEVICE, NULL, NULL);
}
}
}
void _readTopicsFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nTopics;
nTopics=GWEN_XMLNode_FindFirstTag(rootNode, AQH_STORAGE_XML_ELEMENTNAME_TOPICS, NULL, NULL);
if (nTopics) {
GWEN_XMLNODE *nTopic;
nTopic=GWEN_XMLNode_FindFirstTag(nTopics, AQH_STORAGE_XML_ELEMENTNAME_TOPIC, NULL, NULL);
while(nTopic) {
AQH_MQTT_TOPIC *topic;
topic=AQH_MqttTopic_fromXml(nTopic);
if (topic) {
AQH_MqttTopic_List_Add(topic, sto->mqttTopicList);
}
nTopic=GWEN_XMLNode_FindNextTag(nTopic, AQH_STORAGE_XML_ELEMENTNAME_TOPIC, NULL, NULL);
}
}
}
void _readValuesFromXml(AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nValues;
nValues=GWEN_XMLNode_FindFirstTag(rootNode, AQH_STORAGE_XML_ELEMENTNAME_VALUES, NULL, NULL);
if (nValues) {
GWEN_XMLNODE *nValue;
nValue=GWEN_XMLNode_FindFirstTag(nValues, AQH_STORAGE_XML_ELEMENTNAME_VALUE, NULL, NULL);
while(nValue) {
AQH_VALUE *value;
value=AQH_Value_fromXml(nValue);
if (value) {
AQH_Value_List_Add(value, sto->roomList);
}
nValue=GWEN_XMLNode_FindNextTag(nValue, AQH_STORAGE_XML_ELEMENTNAME_VALUE, NULL, NULL);
}
}
}

View File

@@ -0,0 +1,24 @@
/****************************************************************************
* This file is part of the project Gwenhywfar.
* Gwenhywfar (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 AQH_STORAGE_READXML_H
#define AQH_STORAGE_READXML_H
#include "aqhome/data/storage.h"
int AQH_Storage_ReadStateFile(AQH_STORAGE *sto, const char *sFilename);
#endif

View File

@@ -0,0 +1,190 @@
/****************************************************************************
* This file is part of the project Gwenhywfar.
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "aqhome/data/storage_writexml.h"
#include "aqhome/data/storage_p.h"
#include <gwenhywfar/debug.h>
#include <gwenhywfar/xml.h>
#include <gwenhywfar/directory.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void _writeLastIdsToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _writeRoomsToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _writeDevicesToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _writeTopicsToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
static void _writeValuesToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode);
/* ------------------------------------------------------------------------------------------------
* implementations
* ------------------------------------------------------------------------------------------------
*/
int AQH_Storage_WriteStateFile(const AQH_STORAGE *sto, const char *sFilename)
{
GWEN_XMLNODE *rootNode;
int rv;
GWEN_BUFFER *nbuf;
rootNode=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, "root");
_writeLastIdsToXml(sto, rootNode);
_writeRoomsToXml(sto, rootNode);
_writeDevicesToXml(sto, rootNode);
_writeTopicsToXml(sto, rootNode);
_writeValuesToXml(sto, rootNode);
nbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(nbuf, sFilename);
GWEN_Buffer_AppendString(nbuf, ".tmp");
unlink(GWEN_Buffer_GetStart(nbuf));
rv=GWEN_XMLNode_WriteFile(rootNode,
GWEN_Buffer_GetStart(nbuf),
GWEN_XML_FLAGS_SIMPLE | GWEN_XML_FLAGS_HANDLE_HEADERS | GWEN_XML_FLAGS_INDENT);
if (rv<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error writing XML file \"%s\": %d", GWEN_Buffer_GetStart(nbuf), rv);
GWEN_Buffer_free(nbuf);
GWEN_XMLNode_free(rootNode);
return rv;
}
if (rename(GWEN_Buffer_GetStart(nbuf), sFilename)<0) {
DBG_ERROR(AQH_LOGDOMAIN, "Error renaming \"%s\"->\"%s\": %d (%s)",
GWEN_Buffer_GetStart(nbuf), sFilename, errno, strerror(errno));
GWEN_Buffer_free(nbuf);
GWEN_XMLNode_free(rootNode);
return rv;
}
GWEN_XMLNode_free(rootNode);
return 0;
}
void _writeLastIdsToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nLastIds;
nLastIds=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_LASTIDS);
GWEN_XMLNode_SetIntValue(nLastIds, "lastRoomId", sto->lastRoomId);
GWEN_XMLNode_SetIntValue(nLastIds, "lastDeviceId", sto->lastDeviceId);
GWEN_XMLNode_SetIntValue(nLastIds, "lastTopicId", sto->lastTopicId);
GWEN_XMLNode_SetIntValue(nLastIds, "lastValueId", sto->lastValueId);
GWEN_XMLNode_AddChild(rootNode, nLastIds);
}
void _writeRoomsToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nElems;
AQH_ROOM *elem;
nElems=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_ROOMS);
elem=AQH_Room_List_First(sto->roomList);
while(elem) {
GWEN_XMLNODE *nElem;
nElem=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_ROOM);
AQH_Room_toXml(elem, nElem);
GWEN_XMLNode_AddChild(nElems, nElem);
elem=AQH_Room_List_Next(elem);
}
GWEN_XMLNode_AddChild(rootNode, nElems);
}
void _writeDevicesToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nElems;
AQH_DEVICE *elem;
nElems=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_DEVICES);
elem=AQH_Device_List_First(sto->roomList);
while(elem) {
GWEN_XMLNODE *nElem;
nElem=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_DEVICE);
AQH_Device_toXml(elem, nElem);
GWEN_XMLNode_AddChild(nElems, nElem);
elem=AQH_Device_List_Next(elem);
}
GWEN_XMLNode_AddChild(rootNode, nElems);
}
void _writeTopicsToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nElems;
AQH_MQTT_TOPIC *elem;
nElems=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_TOPICS);
elem=AQH_MqttTopic_List_First(sto->mqttTopicList);
while(elem) {
GWEN_XMLNODE *nElem;
nElem=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_TOPIC);
AQH_MqttTopic_toXml(elem, nElem);
GWEN_XMLNode_AddChild(nElems, nElem);
elem=AQH_MqttTopic_List_Next(elem);
}
GWEN_XMLNode_AddChild(rootNode, nElems);
}
void _writeValuesToXml(const AQH_STORAGE *sto, GWEN_XMLNODE *rootNode)
{
GWEN_XMLNODE *nElems;
AQH_VALUE *elem;
nElems=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_VALUES);
elem=AQH_Value_List_First(sto->valueList);
while(elem) {
GWEN_XMLNODE *nElem;
nElem=GWEN_XMLNode_new(GWEN_XMLNodeTypeTag, AQH_STORAGE_XML_ELEMENTNAME_VALUE);
AQH_Value_toXml(elem, nElem);
GWEN_XMLNode_AddChild(nElems, nElem);
elem=AQH_Value_List_Next(elem);
}
GWEN_XMLNode_AddChild(rootNode, nElems);
}

View File

@@ -0,0 +1,24 @@
/****************************************************************************
* This file is part of the project Gwenhywfar.
* Gwenhywfar (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 AQH_STORAGE_WRITEXML_H
#define AQH_STORAGE_WRITEXML_H
#include "aqhome/data/storage.h"
int AQH_Storage_WriteStateFile(const AQH_STORAGE *sto, const char *sFilename);
#endif