chore: Refactor stores to use PersistableStore CRTP template (#2464)
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief Non-template core of PersistableStore.
|
||||
*
|
||||
* All ArduinoJson parse/serialize machinery is instantiated once here (in
|
||||
* PersistableStore.cpp) instead of in every store's translation unit. GCC
|
||||
* emits the JSON serializer/parser templates as local .isra clones per TU
|
||||
* (~0.5KB each), so keeping serializeJson/deserializeJson out of the stores
|
||||
* is what makes the abstraction flash-neutral.
|
||||
*/
|
||||
class PersistableStoreBase {
|
||||
protected:
|
||||
PersistableStoreBase() = default;
|
||||
~PersistableStoreBase() = default;
|
||||
|
||||
// Serializes doc and writes it to path (ensures /.crosspoint exists). Logs on failure.
|
||||
static bool writeDocToFile(const char* path, const JsonDocument& doc);
|
||||
|
||||
// Reads path and parses it into doc. Returns false silently when the file
|
||||
// does not exist (expected on first boot); logs on read/parse failure.
|
||||
static bool readDocFromFile(const char* path, JsonDocument& doc);
|
||||
|
||||
/**
|
||||
* Helper function for extracting an obfuscated password from a JSON value.
|
||||
* Accepts JsonVariantConst so callers can pass either a whole JsonDocument
|
||||
* or a JsonObject element (e.g. inside an array iteration).
|
||||
* If the decoded password requires a resave (e.g. from plaintext fallback), `needsResave` is set to true.
|
||||
*/
|
||||
static std::string extractPassword(JsonVariantConst doc, bool& needsResave);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Base class for persistable singletons using CRTP.
|
||||
*
|
||||
* Derived classes must provide:
|
||||
* - A private default constructor
|
||||
* - friend class PersistableStore<Derived>;
|
||||
* - static const char* getFilePath();
|
||||
* - void toJson(JsonDocument& doc) const;
|
||||
* - bool fromJson(JsonVariantConst doc);
|
||||
*
|
||||
* Note for implementers: read string values as `const char*` (e.g.
|
||||
* `obj["name"] | ""`), never as `| std::string("")` — ArduinoJson's
|
||||
* std::string converter drags a per-TU copy of the whole JSON serializer
|
||||
* into flash via its serializeJson fallback.
|
||||
*/
|
||||
template <typename T>
|
||||
class PersistableStore : public PersistableStoreBase {
|
||||
protected:
|
||||
PersistableStore() = default;
|
||||
~PersistableStore() = default;
|
||||
|
||||
public:
|
||||
// Delete copy constructor and assignment
|
||||
PersistableStore(const PersistableStore&) = delete;
|
||||
PersistableStore& operator=(const PersistableStore&) = delete;
|
||||
|
||||
static T& getInstance() {
|
||||
static T instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool saveToFile() const {
|
||||
JsonDocument doc;
|
||||
static_cast<const T*>(this)->toJson(doc);
|
||||
return writeDocToFile(T::getFilePath(), doc);
|
||||
}
|
||||
|
||||
bool loadFromFile() {
|
||||
JsonDocument doc;
|
||||
if (!readDocFromFile(T::getFilePath(), doc)) {
|
||||
return false;
|
||||
}
|
||||
return static_cast<T*>(this)->fromJson(doc.as<JsonVariantConst>());
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user