From abdf763215f9065e1a1938f8fc86b4711523424b Mon Sep 17 00:00:00 2001 From: Rune Harlyk Date: Sat, 23 Nov 2024 13:54:10 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=BD=20Refactors=20stateful=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/stateful_endpoint.h | 8 +- .../template/stateful_persistence.h | 21 +-- .../template/stateful_service.h | 150 ++++++++---------- 3 files changed, 76 insertions(+), 103 deletions(-) diff --git a/esp32/lib/ESP32-sveltekit/template/stateful_endpoint.h b/esp32/lib/ESP32-sveltekit/template/stateful_endpoint.h index 284731a..5a65338 100644 --- a/esp32/lib/ESP32-sveltekit/template/stateful_endpoint.h +++ b/esp32/lib/ESP32-sveltekit/template/stateful_endpoint.h @@ -21,16 +21,14 @@ class StatefulHttpEndpoint { : _stateReader(stateReader), _stateUpdater(stateUpdater), _statefulService(statefulService) {} esp_err_t handleStateUpdate(PsychicRequest *request, JsonVariant &json) { - if (!json.is()) { - return request->reply(400); - } + if (!json.is()) return request->reply(400); JsonObject jsonObject = json.as(); StateUpdateResult outcome = _statefulService->updateWithoutPropagation(jsonObject, _stateUpdater); - if (outcome == StateUpdateResult::ERROR) { + if (outcome == StateUpdateResult::ERROR) return request->reply(400); - } else if ((outcome == StateUpdateResult::CHANGED)) { + else if ((outcome == StateUpdateResult::CHANGED)) { // persist the changes to the FS _statefulService->callUpdateHandlers(HTTP_ENDPOINT_ORIGIN_ID); } diff --git a/esp32/lib/ESP32-sveltekit/template/stateful_persistence.h b/esp32/lib/ESP32-sveltekit/template/stateful_persistence.h index 38dbc23..1001b25 100644 --- a/esp32/lib/ESP32-sveltekit/template/stateful_persistence.h +++ b/esp32/lib/ESP32-sveltekit/template/stateful_persistence.h @@ -58,25 +58,18 @@ class FSPersistence { } bool writeToFS() { - // create and populate a new json object JsonDocument jsonDocument; JsonObject jsonObject = jsonDocument.to(); _statefulService->read(jsonObject, _stateReader); - // make directories if required mkdirs(); - // serialize it to filesystem - File settingsFile = _fs->open(_filePath, "w"); + File file = _fs->open(_filePath, "w"); - // failed to open file, return false - if (!settingsFile) { - return false; - } + if (!file) return false; - // serialize the data to the file - serializeJson(jsonDocument, settingsFile); - settingsFile.close(); + serializeJson(jsonDocument, file); + file.close(); return true; } @@ -100,7 +93,7 @@ class FSPersistence { FS *_fs {&ESPFS}; const char *_filePath; size_t _bufferSize; - update_handler_id_t _updateHandlerId; + HandlerId _updateHandlerId; // We assume we have a _filePath with format // "/directory1/directory2/filename" We create a directory for each missing @@ -110,9 +103,7 @@ class FSPersistence { int index = 0; while ((index = path.indexOf('/', index + 1)) != -1) { String segment = path.substring(0, index); - if (!_fs->exists(segment)) { - _fs->mkdir(segment); - } + if (!_fs->exists(segment)) _fs->mkdir(segment); } } diff --git a/esp32/lib/ESP32-sveltekit/template/stateful_service.h b/esp32/lib/ESP32-sveltekit/template/stateful_service.h index 1d82452..7a4f431 100644 --- a/esp32/lib/ESP32-sveltekit/template/stateful_service.h +++ b/esp32/lib/ESP32-sveltekit/template/stateful_service.h @@ -1,20 +1,4 @@ -#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. - **/ +#pragma once #include #include @@ -32,28 +16,42 @@ using JsonStateUpdater = std::function using JsonStateReader = std::function; -typedef size_t update_handler_id_t; -typedef size_t hook_handler_id_t; -typedef std::function StateUpdateCallback; -typedef std::function StateHookCallback; +using HandlerId = size_t; +using StateUpdateCallback = std::function; +using StateHookCallback = std::function; -typedef struct StateUpdateHandlerInfo { - static inline update_handler_id_t currentUpdatedHandlerId = 0; - update_handler_id_t _id; - StateUpdateCallback _callback; - bool _allowRemove; - StateUpdateHandlerInfo(StateUpdateCallback callback, bool allowRemove) - : _id(++currentUpdatedHandlerId), _callback(callback), _allowRemove(allowRemove) {}; -} StateUpdateHandlerInfo_t; +class HandlerBase { + protected: + static inline HandlerId nextId_ = 1; // Start from 1, 0 is invalid + HandlerId id_; + bool allowRemove_; -typedef struct StateHookHandlerInfo { - static inline hook_handler_id_t currentHookHandlerId = 0; - hook_handler_id_t _id; - StateHookCallback _callback; - bool _allowRemove; - StateHookHandlerInfo(StateHookCallback callback, bool allowRemove) - : _id(++currentHookHandlerId), _callback(callback), _allowRemove(allowRemove) {}; -} StateHookHandlerInfo_t; + HandlerBase(bool allowRemove) : id_(nextId_++), allowRemove_(allowRemove) {} + + public: + HandlerId getId() const { return id_; } + bool isRemovable() const { return allowRemove_; } +}; + +class UpdateHandler : public HandlerBase { + StateUpdateCallback callback_; + + public: + UpdateHandler(StateUpdateCallback callback, bool allowRemove) + : HandlerBase(allowRemove), callback_(std::move(callback)) {} + + void invoke(const String &originId) const { callback_(originId); } +}; + +class HookHandler : public HandlerBase { + StateHookCallback callback_; + + public: + HookHandler(StateHookCallback callback, bool allowRemove) + : HandlerBase(allowRemove), callback_(std::move(callback)) {} + + void invoke(const String &originId, StateUpdateResult &result) const { callback_(originId, result); } +}; template class StatefulService { @@ -61,93 +59,81 @@ class StatefulService { template StatefulService(Args &&...args) : state_(std::forward(args)...), mutex_(xSemaphoreCreateRecursiveMutex()) {} - update_handler_id_t addUpdateHandler(StateUpdateCallback callback, bool allowRemove = true) { + HandlerId addUpdateHandler(StateUpdateCallback callback, bool allowRemove = true) { if (!callback) return 0; - StateUpdateHandlerInfo_t updateHandler(callback, allowRemove); - updateHandlers_.push_back(updateHandler); - return updateHandler._id; + updateHandlers_.emplace_back(std::move(callback), allowRemove); + return updateHandlers_.back().getId(); } - 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; - } - } + void removeUpdateHandler(HandlerId id) { + updateHandlers_.remove_if( + [id](const UpdateHandler &handler) { return handler.isRemovable() && handler.getId() == id; }); } - hook_handler_id_t addHookHandler(StateHookCallback callback, bool allowRemove = true) { + HandlerId addHookHandler(StateHookCallback callback, bool allowRemove = true) { if (!callback) return 0; - StateHookHandlerInfo_t hookHandler(callback, allowRemove); - hookHandlers_.push_back(hookHandler); - return hookHandler._id; + hookHandlers_.emplace_back(std::move(callback), allowRemove); + return hookHandlers_.back().getId(); } - 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; - } - } + void removeHookHandler(HandlerId id) { + hookHandlers_.remove_if( + [id](const HookHandler &handler) { return handler.isRemovable() && handler.getId() == id; }); } StateUpdateResult update(std::function stateUpdater, const String &originId) { - beginTransaction(); + lock(); StateUpdateResult result = stateUpdater(state_); - endTransaction(); + unlock(); notifyStateChange(originId, result); return result; } StateUpdateResult updateWithoutPropagation(std::function stateUpdater) { - beginTransaction(); + lock(); StateUpdateResult result = stateUpdater(state_); - endTransaction(); + unlock(); return result; } StateUpdateResult update(JsonObject &jsonObject, JsonStateUpdater stateUpdater, const String &originId) { - beginTransaction(); + lock(); StateUpdateResult result = stateUpdater(jsonObject, state_); - endTransaction(); + unlock(); notifyStateChange(originId, result); return result; } StateUpdateResult updateWithoutPropagation(JsonObject &jsonObject, JsonStateUpdater stateUpdater) { - beginTransaction(); + lock(); StateUpdateResult result = stateUpdater(jsonObject, state_); - endTransaction(); + unlock(); return result; } void read(std::function stateReader) { - beginTransaction(); + lock(); stateReader(state_); - endTransaction(); + unlock(); } void read(JsonObject &jsonObject, JsonStateReader stateReader) { - beginTransaction(); + lock(); stateReader(state_, jsonObject); - endTransaction(); + unlock(); } void callUpdateHandlers(const String &originId) { - for (const StateUpdateHandlerInfo_t &updateHandler : updateHandlers_) { - updateHandler._callback(originId); + for (const UpdateHandler &updateHandler : updateHandlers_) { + updateHandler.invoke(originId); } } void callHookHandlers(const String &originId, StateUpdateResult &result) { - for (const StateHookHandlerInfo_t &hookHandler : hookHandlers_) { - hookHandler._callback(originId, result); + for (const HookHandler &hookHandler : hookHandlers_) { + hookHandler.invoke(originId, result); } } @@ -156,8 +142,8 @@ class StatefulService { private: T state_; - inline void beginTransaction() { xSemaphoreTakeRecursive(mutex_, portMAX_DELAY); } - inline void endTransaction() { xSemaphoreGiveRecursive(mutex_); } + inline void lock() { xSemaphoreTakeRecursive(mutex_, portMAX_DELAY); } + inline void unlock() { xSemaphoreGiveRecursive(mutex_); } void notifyStateChange(const String &originId, StateUpdateResult &result) { callHookHandlers(originId, result); @@ -167,8 +153,6 @@ class StatefulService { } SemaphoreHandle_t mutex_; - std::list updateHandlers_; - std::list hookHandlers_; + std::list updateHandlers_; + std::list hookHandlers_; }; - -#endif // end StatefulService_h