Fork of the excellent esp8266-react - https://github.com/rjwats/esp8266-react
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.0 KiB

  1. #ifndef StatefulService_h
  2. #define StatefulService_h
  3. #include <Arduino.h>
  4. #include <ArduinoJson.h>
  5. #include <list>
  6. #include <functional>
  7. #ifdef ESP32
  8. #include <freertos/FreeRTOS.h>
  9. #include <freertos/semphr.h>
  10. #endif
  11. #ifndef DEFAULT_BUFFER_SIZE
  12. #define DEFAULT_BUFFER_SIZE 1024
  13. #endif
  14. enum class StateUpdateResult {
  15. CHANGED = 0, // The update changed the state and propagation should take place if required
  16. UNCHANGED, // The state was unchanged, propagation should not take place
  17. ERROR // There was a problem updating the state, propagation should not take place
  18. };
  19. template <typename T>
  20. using JsonStateUpdater = std::function<StateUpdateResult(JsonObject& root, T& settings)>;
  21. template <typename T>
  22. using JsonStateReader = std::function<void(T& settings, JsonObject& root)>;
  23. typedef size_t update_handler_id_t;
  24. typedef std::function<void(const String& originId)> StateUpdateCallback;
  25. typedef struct StateUpdateHandlerInfo {
  26. static update_handler_id_t currentUpdatedHandlerId;
  27. update_handler_id_t _id;
  28. StateUpdateCallback _cb;
  29. bool _allowRemove;
  30. StateUpdateHandlerInfo(StateUpdateCallback cb, bool allowRemove) :
  31. _id(++currentUpdatedHandlerId), _cb(cb), _allowRemove(allowRemove){};
  32. } StateUpdateHandlerInfo_t;
  33. template <class T>
  34. class StatefulService {
  35. public:
  36. template <typename... Args>
  37. #ifdef ESP32
  38. StatefulService(Args&&... args) :
  39. _state(std::forward<Args>(args)...), _accessMutex(xSemaphoreCreateRecursiveMutex()) {
  40. }
  41. #else
  42. StatefulService(Args&&... args) : _state(std::forward<Args>(args)...) {
  43. }
  44. #endif
  45. update_handler_id_t addUpdateHandler(StateUpdateCallback cb, bool allowRemove = true) {
  46. if (!cb) {
  47. return 0;
  48. }
  49. StateUpdateHandlerInfo_t updateHandler(cb, allowRemove);
  50. _updateHandlers.push_back(updateHandler);
  51. return updateHandler._id;
  52. }
  53. void removeUpdateHandler(update_handler_id_t id) {
  54. for (auto i = _updateHandlers.begin(); i != _updateHandlers.end();) {
  55. if ((*i)._allowRemove && (*i)._id == id) {
  56. i = _updateHandlers.erase(i);
  57. } else {
  58. ++i;
  59. }
  60. }
  61. }
  62. StateUpdateResult update(std::function<StateUpdateResult(T&)> stateUpdater, const String& originId) {
  63. beginTransaction();
  64. StateUpdateResult result = stateUpdater(_state);
  65. endTransaction();
  66. if (result == StateUpdateResult::CHANGED) {
  67. callUpdateHandlers(originId);
  68. }
  69. return result;
  70. }
  71. StateUpdateResult updateWithoutPropagation(std::function<StateUpdateResult(T&)> stateUpdater) {
  72. beginTransaction();
  73. StateUpdateResult result = stateUpdater(_state);
  74. endTransaction();
  75. return result;
  76. }
  77. StateUpdateResult update(JsonObject& jsonObject, JsonStateUpdater<T> stateUpdater, const String& originId) {
  78. beginTransaction();
  79. StateUpdateResult result = stateUpdater(jsonObject, _state);
  80. endTransaction();
  81. if (result == StateUpdateResult::CHANGED) {
  82. callUpdateHandlers(originId);
  83. }
  84. return result;
  85. }
  86. StateUpdateResult updateWithoutPropagation(JsonObject& jsonObject, JsonStateUpdater<T> stateUpdater) {
  87. beginTransaction();
  88. StateUpdateResult result = stateUpdater(jsonObject, _state);
  89. endTransaction();
  90. return result;
  91. }
  92. void read(std::function<void(T&)> stateReader) {
  93. beginTransaction();
  94. stateReader(_state);
  95. endTransaction();
  96. }
  97. void read(JsonObject& jsonObject, JsonStateReader<T> stateReader) {
  98. beginTransaction();
  99. stateReader(_state, jsonObject);
  100. endTransaction();
  101. }
  102. void callUpdateHandlers(const String& originId) {
  103. for (const StateUpdateHandlerInfo_t& updateHandler : _updateHandlers) {
  104. updateHandler._cb(originId);
  105. }
  106. }
  107. protected:
  108. T _state;
  109. inline void beginTransaction() {
  110. #ifdef ESP32
  111. xSemaphoreTakeRecursive(_accessMutex, portMAX_DELAY);
  112. #endif
  113. }
  114. inline void endTransaction() {
  115. #ifdef ESP32
  116. xSemaphoreGiveRecursive(_accessMutex);
  117. #endif
  118. }
  119. private:
  120. #ifdef ESP32
  121. SemaphoreHandle_t _accessMutex;
  122. #endif
  123. std::list<StateUpdateHandlerInfo_t> _updateHandlers;
  124. };
  125. #endif // end StatefulService_h