🔥 Removes old stateful persistence
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
#include <settings/ap_settings.h>
|
||||
#include <utils/timing.h>
|
||||
#include <wifi/wifi_idf.h>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <mdns.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
#include <settings/mdns_settings.h>
|
||||
#include <utils/timing.h>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <features.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
|
||||
#include <settings/camera_settings.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <utils/math_utils.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define ServoController_h
|
||||
|
||||
#include <peripherals/drivers/pca9685.h>
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <utils/math_utils.h>
|
||||
@@ -24,22 +24,17 @@ inline ServoSettings ServoSettings_defaults() {
|
||||
ServoSettings settings = {};
|
||||
settings.servos_count = 12;
|
||||
const api_Servo defaults[12] = {
|
||||
{306, -1, 0, 2.0f, "Servo1"}, {306, 1, -45, 2.0f, "Servo2"},
|
||||
{306, 1, 90, 2.0f, "Servo3"}, {306, -1, 0, 2.0f, "Servo4"},
|
||||
{306, -1, 45, 2.0f, "Servo5"}, {306, -1, -90, 2.0f, "Servo6"},
|
||||
{306, 1, 0, 2.0f, "Servo7"}, {306, 1, -45, 2.0f, "Servo8"},
|
||||
{306, 1, 90, 2.0f, "Servo9"}, {306, 1, 0, 2.0f, "Servo10"},
|
||||
{306, -1, 45, 2.0f, "Servo11"}, {306, -1, -90, 2.0f, "Servo12"}
|
||||
};
|
||||
{306, -1, 0, 2.0f, "Servo1"}, {306, 1, -45, 2.0f, "Servo2"}, {306, 1, 90, 2.0f, "Servo3"},
|
||||
{306, -1, 0, 2.0f, "Servo4"}, {306, -1, 45, 2.0f, "Servo5"}, {306, -1, -90, 2.0f, "Servo6"},
|
||||
{306, 1, 0, 2.0f, "Servo7"}, {306, 1, -45, 2.0f, "Servo8"}, {306, 1, 90, 2.0f, "Servo9"},
|
||||
{306, 1, 0, 2.0f, "Servo10"}, {306, -1, 45, 2.0f, "Servo11"}, {306, -1, -90, 2.0f, "Servo12"}};
|
||||
for (int i = 0; i < 12; i++) {
|
||||
settings.servos[i] = defaults[i];
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
inline void ServoSettings_read(const ServoSettings &settings, ServoSettings &proto) {
|
||||
proto = settings;
|
||||
}
|
||||
inline void ServoSettings_read(const ServoSettings &settings, ServoSettings &proto) { proto = settings; }
|
||||
|
||||
inline StateUpdateResult ServoSettings_update(const ServoSettings &proto, ServoSettings &settings) {
|
||||
settings = proto;
|
||||
@@ -52,9 +47,8 @@ class ServoController : public StatefulService<ServoSettings> {
|
||||
: protoEndpoint(ServoSettings_read, ServoSettings_update, this,
|
||||
API_REQUEST_EXTRACTOR(servo_settings, ServoSettings),
|
||||
API_RESPONSE_ASSIGNER(servo_settings, ServoSettings)),
|
||||
_persistence(ServoSettings_read, ServoSettings_update, this,
|
||||
SERVO_SETTINGS_FILE, api_ServoSettings_fields, api_ServoSettings_size,
|
||||
ServoSettings_defaults()) {}
|
||||
_persistence(ServoSettings_read, ServoSettings_update, this, SERVO_SETTINGS_FILE, api_ServoSettings_fields,
|
||||
api_ServoSettings_size, ServoSettings_defaults()) {}
|
||||
|
||||
void begin() {
|
||||
_persistence.readFromFS();
|
||||
|
||||
@@ -1,35 +1,65 @@
|
||||
#ifndef FSPersistence_h
|
||||
#define FSPersistence_h
|
||||
#pragma once
|
||||
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/state_result.h>
|
||||
#include <filesystem.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
static const char *TAG_PERSISTENCE = "FSPersistencePB";
|
||||
|
||||
template <class T>
|
||||
class FSPersistence {
|
||||
class FSPersistencePB {
|
||||
public:
|
||||
FSPersistence(JsonStateReader<T> stateReader, JsonStateUpdater<T> stateUpdater, StatefulService<T> *statefulService,
|
||||
const char *filePath)
|
||||
using ProtoStateReader = std::function<void(const T &, T &)>;
|
||||
using ProtoStateUpdater = std::function<StateUpdateResult(const T &, T &)>;
|
||||
|
||||
FSPersistencePB(ProtoStateReader stateReader, ProtoStateUpdater stateUpdater, StatefulService<T> *statefulService,
|
||||
const char *filePath, const pb_msgdesc_t *msgDescriptor, size_t maxSize, const T &defaultState)
|
||||
: _stateReader(stateReader),
|
||||
_stateUpdater(stateUpdater),
|
||||
_statefulService(statefulService),
|
||||
_filePath(filePath),
|
||||
_msgDescriptor(msgDescriptor),
|
||||
_maxSize(maxSize),
|
||||
_defaultState(defaultState),
|
||||
_updateHandlerId(0) {
|
||||
enableUpdateHandler();
|
||||
}
|
||||
|
||||
void readFromFS() {
|
||||
std::string content = FileSystem::readFile(_filePath);
|
||||
FILE *file = fopen(_filePath, "rb");
|
||||
|
||||
if (!content.empty()) {
|
||||
JsonDocument jsonDocument;
|
||||
DeserializationError error = deserializeJson(jsonDocument, content);
|
||||
if (error == DeserializationError::Ok) {
|
||||
JsonVariant jsonObject = jsonDocument.as<JsonVariant>();
|
||||
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||
return;
|
||||
if (file) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t fileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
if (fileSize > 0 && fileSize <= _maxSize) {
|
||||
uint8_t *buffer = new uint8_t[fileSize];
|
||||
size_t bytesRead = fread(buffer, 1, fileSize, file);
|
||||
fclose(file);
|
||||
|
||||
if (bytesRead == fileSize) {
|
||||
T *protoMsg = new T();
|
||||
*protoMsg = {};
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, bytesRead);
|
||||
|
||||
if (pb_decode(&stream, _msgDescriptor, protoMsg)) {
|
||||
_statefulService->updateWithoutPropagation(
|
||||
[this, protoMsg](T &state) { return _stateUpdater(*protoMsg, state); });
|
||||
delete protoMsg;
|
||||
delete[] buffer;
|
||||
return;
|
||||
}
|
||||
delete protoMsg;
|
||||
}
|
||||
delete[] buffer;
|
||||
} else {
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,16 +68,35 @@ class FSPersistence {
|
||||
}
|
||||
|
||||
bool writeToFS() {
|
||||
JsonDocument jsonDocument;
|
||||
JsonVariant jsonObject = jsonDocument.to<JsonVariant>();
|
||||
_statefulService->read(jsonObject, _stateReader);
|
||||
uint8_t *buffer = new uint8_t[_maxSize];
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, _maxSize);
|
||||
|
||||
T *protoMsg = new T();
|
||||
*protoMsg = {};
|
||||
_statefulService->read([this, protoMsg](const T &state) { _stateReader(state, *protoMsg); });
|
||||
|
||||
bool encodeSuccess = pb_encode(&stream, _msgDescriptor, protoMsg);
|
||||
delete protoMsg;
|
||||
|
||||
if (!encodeSuccess) {
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
mkdirs();
|
||||
|
||||
std::string content;
|
||||
serializeJson(jsonDocument, content);
|
||||
FILE *file = fopen(_filePath, "wb");
|
||||
if (!file) {
|
||||
ESP_LOGE(TAG_PERSISTENCE, "Failed to open file for writing: %s", _filePath);
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
return FileSystem::writeFile(_filePath, content.c_str());
|
||||
size_t written = fwrite(buffer, 1, stream.bytes_written, file);
|
||||
fclose(file);
|
||||
delete[] buffer;
|
||||
|
||||
return written == stream.bytes_written;
|
||||
}
|
||||
|
||||
void disableUpdateHandler() {
|
||||
@@ -64,11 +113,13 @@ class FSPersistence {
|
||||
}
|
||||
|
||||
private:
|
||||
JsonStateReader<T> _stateReader;
|
||||
JsonStateUpdater<T> _stateUpdater;
|
||||
ProtoStateReader _stateReader;
|
||||
ProtoStateUpdater _stateUpdater;
|
||||
StatefulService<T> *_statefulService;
|
||||
const char *_filePath;
|
||||
size_t _bufferSize;
|
||||
const pb_msgdesc_t *_msgDescriptor;
|
||||
size_t _maxSize;
|
||||
T _defaultState;
|
||||
HandlerId _updateHandlerId;
|
||||
|
||||
void mkdirs() {
|
||||
@@ -84,11 +135,7 @@ class FSPersistence {
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void applyDefaults() {
|
||||
JsonDocument jsonDocument;
|
||||
JsonVariant jsonObject = jsonDocument.as<JsonVariant>();
|
||||
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
|
||||
void applyDefaults() {
|
||||
_statefulService->updateWithoutPropagation([this](T &state) { return _stateUpdater(_defaultState, state); });
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/state_result.h>
|
||||
#include <filesystem.h>
|
||||
#include <pb_encode.h>
|
||||
#include <pb_decode.h>
|
||||
#include <cstdio>
|
||||
#include <sys/stat.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
static const char *TAG_PERSISTENCE = "FSPersistencePB";
|
||||
|
||||
template <class T>
|
||||
class FSPersistencePB {
|
||||
public:
|
||||
using ProtoStateReader = std::function<void(const T &, T &)>;
|
||||
using ProtoStateUpdater = std::function<StateUpdateResult(const T &, T &)>;
|
||||
|
||||
FSPersistencePB(ProtoStateReader stateReader, ProtoStateUpdater stateUpdater, StatefulService<T> *statefulService,
|
||||
const char *filePath, const pb_msgdesc_t *msgDescriptor, size_t maxSize, const T &defaultState)
|
||||
: _stateReader(stateReader),
|
||||
_stateUpdater(stateUpdater),
|
||||
_statefulService(statefulService),
|
||||
_filePath(filePath),
|
||||
_msgDescriptor(msgDescriptor),
|
||||
_maxSize(maxSize),
|
||||
_defaultState(defaultState),
|
||||
_updateHandlerId(0) {
|
||||
enableUpdateHandler();
|
||||
}
|
||||
|
||||
void readFromFS() {
|
||||
FILE *file = fopen(_filePath, "rb");
|
||||
|
||||
if (file) {
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t fileSize = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
if (fileSize > 0 && fileSize <= _maxSize) {
|
||||
uint8_t *buffer = new uint8_t[fileSize];
|
||||
size_t bytesRead = fread(buffer, 1, fileSize, file);
|
||||
fclose(file);
|
||||
|
||||
if (bytesRead == fileSize) {
|
||||
T *protoMsg = new T();
|
||||
*protoMsg = {};
|
||||
pb_istream_t stream = pb_istream_from_buffer(buffer, bytesRead);
|
||||
|
||||
if (pb_decode(&stream, _msgDescriptor, protoMsg)) {
|
||||
_statefulService->updateWithoutPropagation(
|
||||
[this, protoMsg](T &state) { return _stateUpdater(*protoMsg, state); });
|
||||
delete protoMsg;
|
||||
delete[] buffer;
|
||||
return;
|
||||
}
|
||||
delete protoMsg;
|
||||
}
|
||||
delete[] buffer;
|
||||
} else {
|
||||
fclose(file);
|
||||
}
|
||||
}
|
||||
|
||||
applyDefaults();
|
||||
writeToFS();
|
||||
}
|
||||
|
||||
bool writeToFS() {
|
||||
uint8_t *buffer = new uint8_t[_maxSize];
|
||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, _maxSize);
|
||||
|
||||
T *protoMsg = new T();
|
||||
*protoMsg = {};
|
||||
_statefulService->read([this, protoMsg](const T &state) { _stateReader(state, *protoMsg); });
|
||||
|
||||
bool encodeSuccess = pb_encode(&stream, _msgDescriptor, protoMsg);
|
||||
delete protoMsg;
|
||||
|
||||
if (!encodeSuccess) {
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
mkdirs();
|
||||
|
||||
FILE *file = fopen(_filePath, "wb");
|
||||
if (!file) {
|
||||
ESP_LOGE(TAG_PERSISTENCE, "Failed to open file for writing: %s", _filePath);
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t written = fwrite(buffer, 1, stream.bytes_written, file);
|
||||
fclose(file);
|
||||
delete[] buffer;
|
||||
|
||||
return written == stream.bytes_written;
|
||||
}
|
||||
|
||||
void disableUpdateHandler() {
|
||||
if (_updateHandlerId) {
|
||||
_statefulService->removeUpdateHandler(_updateHandlerId);
|
||||
_updateHandlerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void enableUpdateHandler() {
|
||||
if (!_updateHandlerId) {
|
||||
_updateHandlerId = _statefulService->addUpdateHandler([&](const std::string &originId) { writeToFS(); });
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ProtoStateReader _stateReader;
|
||||
ProtoStateUpdater _stateUpdater;
|
||||
StatefulService<T> *_statefulService;
|
||||
const char *_filePath;
|
||||
const pb_msgdesc_t *_msgDescriptor;
|
||||
size_t _maxSize;
|
||||
T _defaultState;
|
||||
HandlerId _updateHandlerId;
|
||||
|
||||
void mkdirs() {
|
||||
std::string path(_filePath);
|
||||
size_t index = 0;
|
||||
while ((index = path.find('/', index + 1)) != std::string::npos) {
|
||||
std::string segment = path.substr(0, index);
|
||||
struct stat st;
|
||||
if (stat(segment.c_str(), &st) != 0) {
|
||||
FileSystem::mkdirRecursive(segment.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void applyDefaults() {
|
||||
_statefulService->updateWithoutPropagation([this](T &state) { return _stateUpdater(_defaultState, state); });
|
||||
}
|
||||
};
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <filesystem.h>
|
||||
#include <utils/timing.h>
|
||||
#include <template/stateful_service.h>
|
||||
#include <template/stateful_persistence_pb.h>
|
||||
#include <template/stateful_persistence.h>
|
||||
#include <template/stateful_proto_endpoint.h>
|
||||
#include <settings/wifi_settings.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user