Files
SpotMicroESP32-Leika/esp32/lib/ESP32-sveltekit/template/stateful_service.h
T
Rune Harlyk 24d39e540e 📦 Moves templates
2024-11-14 15:56:23 +01:00

177 lines
5.6 KiB
C++

#ifndef StatefulService_h
#define StatefulService_h
/**
* ESP32 SvelteKit
*
* A simple, secure and extensible framework for IoT projects for ESP32 platforms
* with responsive Sveltekit front-end built with TailwindCSS and DaisyUI.
* https://github.com/theelims/ESP32-sveltekit
*
* Copyright (C) 2018 - 2023 rjwats
* Copyright (C) 2023 theelims
* Copyright (C) 2024 runeharlyk
*
* All Rights Reserved. This software may be modified and distributed under
* the terms of the LGPL v3 license. See the LICENSE file for details.
**/
#include <Arduino.h>
#include <ArduinoJson.h>
#include <list>
#include <functional>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <template/state_result.h>
template <typename T>
using JsonStateUpdater = std::function<StateUpdateResult(JsonObject &root, T &settings)>;
template <typename T>
using JsonStateReader = std::function<void(T &settings, JsonObject &root)>;
typedef size_t update_handler_id_t;
typedef size_t hook_handler_id_t;
typedef std::function<void(const String &originId)> StateUpdateCallback;
typedef std::function<void(const String &originId, StateUpdateResult &result)> StateHookCallback;
typedef struct StateUpdateHandlerInfo {
static inline update_handler_id_t currentUpdatedHandlerId = 0;
update_handler_id_t _id;
StateUpdateCallback _cb;
bool _allowRemove;
StateUpdateHandlerInfo(StateUpdateCallback cb, bool allowRemove)
: _id(++currentUpdatedHandlerId), _cb(cb), _allowRemove(allowRemove) {};
} StateUpdateHandlerInfo_t;
typedef struct StateHookHandlerInfo {
static inline hook_handler_id_t currentHookHandlerId = 0;
hook_handler_id_t _id;
StateHookCallback _cb;
bool _allowRemove;
StateHookHandlerInfo(StateHookCallback cb, bool allowRemove)
: _id(++currentHookHandlerId), _cb(cb), _allowRemove(allowRemove) {};
} StateHookHandlerInfo_t;
template <class T>
class StatefulService {
public:
template <typename... Args>
StatefulService(Args &&...args)
: _state(std::forward<Args>(args)...), _accessMutex(xSemaphoreCreateRecursiveMutex()) {}
update_handler_id_t addUpdateHandler(StateUpdateCallback cb, bool allowRemove = true) {
if (!cb) {
return 0;
}
StateUpdateHandlerInfo_t updateHandler(cb, allowRemove);
_updateHandlers.push_back(updateHandler);
return updateHandler._id;
}
void removeUpdateHandler(update_handler_id_t id) {
for (auto i = _updateHandlers.begin(); i != _updateHandlers.end();) {
if ((*i)._allowRemove && (*i)._id == id) {
i = _updateHandlers.erase(i);
} else {
++i;
}
}
}
hook_handler_id_t addHookHandler(StateHookCallback cb, bool allowRemove = true) {
if (!cb) {
return 0;
}
StateHookHandlerInfo_t hookHandler(cb, allowRemove);
_hookHandlers.push_back(hookHandler);
return hookHandler._id;
}
void removeHookHandler(hook_handler_id_t id) {
for (auto i = _hookHandlers.begin(); i != _hookHandlers.end();) {
if ((*i)._allowRemove && (*i)._id == id) {
i = _hookHandlers.erase(i);
} else {
++i;
}
}
}
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater, const String &originId) {
beginTransaction();
StateUpdateResult result = stateUpdater(_state);
endTransaction();
callHookHandlers(originId, result);
if (result == StateUpdateResult::CHANGED) {
callUpdateHandlers(originId);
}
return result;
}
StateUpdateResult updateWithoutPropagation(std::function<StateUpdateResult(T &)> stateUpdater) {
beginTransaction();
StateUpdateResult result = stateUpdater(_state);
endTransaction();
return result;
}
StateUpdateResult update(JsonObject &jsonObject, JsonStateUpdater<T> stateUpdater, const String &originId) {
beginTransaction();
StateUpdateResult result = stateUpdater(jsonObject, _state);
endTransaction();
callHookHandlers(originId, result);
if (result == StateUpdateResult::CHANGED) {
callUpdateHandlers(originId);
}
return result;
}
StateUpdateResult updateWithoutPropagation(JsonObject &jsonObject, JsonStateUpdater<T> stateUpdater) {
beginTransaction();
StateUpdateResult result = stateUpdater(jsonObject, _state);
endTransaction();
return result;
}
void read(std::function<void(T &)> stateReader) {
beginTransaction();
stateReader(_state);
endTransaction();
}
void read(JsonObject &jsonObject, JsonStateReader<T> stateReader) {
beginTransaction();
stateReader(_state, jsonObject);
endTransaction();
}
void callUpdateHandlers(const String &originId) {
for (const StateUpdateHandlerInfo_t &updateHandler : _updateHandlers) {
updateHandler._cb(originId);
}
}
void callHookHandlers(const String &originId, StateUpdateResult &result) {
for (const StateHookHandlerInfo_t &hookHandler : _hookHandlers) {
hookHandler._cb(originId, result);
}
}
protected:
T _state;
inline void beginTransaction() { xSemaphoreTakeRecursive(_accessMutex, portMAX_DELAY); }
inline void endTransaction() { xSemaphoreGiveRecursive(_accessMutex); }
private:
SemaphoreHandle_t _accessMutex;
std::list<StateUpdateHandlerInfo_t> _updateHandlers;
std::list<StateHookHandlerInfo_t> _hookHandlers;
};
#endif // end StatefulService_h