mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
154 lines
4.4 KiB
C++
154 lines
4.4 KiB
C++
#ifndef StatefulService_h
|
|
#define StatefulService_h
|
|
|
|
#include <Arduino.h>
|
|
#include <ArduinoJson.h>
|
|
|
|
#include <list>
|
|
#include <functional>
|
|
|
|
#ifndef DEFAULT_BUFFER_SIZE
|
|
#define DEFAULT_BUFFER_SIZE 2048
|
|
#endif
|
|
|
|
#ifndef FS_BUFFER_SIZE
|
|
#define FS_BUFFER_SIZE 4096
|
|
#endif
|
|
|
|
enum class StateUpdateResult {
|
|
CHANGED = 0, // The update changed the state and propagation should take place if required
|
|
CHANGED_RESTART, // The update changed the state and the service should be restarted
|
|
UNCHANGED, // The state was unchanged, propagation should not take place
|
|
ERROR // There was a problem updating the state, propagation should not take place
|
|
};
|
|
|
|
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 std::function<void(const String & originId)> StateUpdateCallback;
|
|
|
|
typedef struct StateUpdateHandlerInfo {
|
|
static update_handler_id_t currentUpdatedHandlerId;
|
|
update_handler_id_t _id;
|
|
StateUpdateCallback _cb;
|
|
bool _allowRemove;
|
|
StateUpdateHandlerInfo(StateUpdateCallback cb, bool allowRemove)
|
|
: _id(++currentUpdatedHandlerId)
|
|
, _cb(cb)
|
|
, _allowRemove(allowRemove){};
|
|
} StateUpdateHandlerInfo_t;
|
|
|
|
template <class T>
|
|
class StatefulService {
|
|
public:
|
|
template <typename... Args>
|
|
#ifdef ESP32
|
|
StatefulService(Args &&... args)
|
|
: _state(std::forward<Args>(args)...)
|
|
, _accessMutex(xSemaphoreCreateRecursiveMutex()) {
|
|
}
|
|
#else
|
|
StatefulService(Args &&... args)
|
|
: _state(std::forward<Args>(args)...) {
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater, const String & originId) {
|
|
beginTransaction();
|
|
StateUpdateResult result = stateUpdater(_state);
|
|
endTransaction();
|
|
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();
|
|
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);
|
|
}
|
|
}
|
|
|
|
protected:
|
|
T _state;
|
|
|
|
inline void beginTransaction() {
|
|
#ifdef ESP32
|
|
xSemaphoreTakeRecursive(_accessMutex, portMAX_DELAY);
|
|
#endif
|
|
}
|
|
|
|
inline void endTransaction() {
|
|
#ifdef ESP32
|
|
xSemaphoreGiveRecursive(_accessMutex);
|
|
#endif
|
|
}
|
|
|
|
private:
|
|
#ifdef ESP32
|
|
SemaphoreHandle_t _accessMutex;
|
|
#endif
|
|
std::list<StateUpdateHandlerInfo_t> _updateHandlers;
|
|
};
|
|
|
|
#endif
|