FilesystemModule
Source:
FilesystemModule.h
FilesystemModule¶
src/core/system/FilesystemModule.h:45Inherits:
MoonModule
Control-list-driven JSON persistence: it writes control values to flash, so settings survive a reboot.
It is always loaded and runs first, so its load hook fires before any other module sets up. Storage is one flat JSON file per top-level module, named after the module's type. Its bodies live in the .cpp, keeping the recompile cost off the tree.
Public Methods¶
inline void ageDirtyForTest(uint32_t ms)
: Age the ceiling clock, so a test need not sleep through it.
FilesystemModule() = default
: The constructor leaves the singleton alone, which setScheduler registers.
~FilesystemModule() override
: Clear the singleton when this is the instance that registered it.
virtual inline bool respectsEnabled() const override
: Keep flushing whatever the enabled toggle says, so disabling this module cannot lose changes.
virtual inline bool appearsInUi() const override
: Stay out of the UI: this is a pure engine, and FileManagerModule shows its status.
void setScheduler(Scheduler * s)
: Adopt the scheduler, register the singleton and wire the persistence hooks.
virtual void setup() override
: Mount the filesystem and create the config directory.
virtual void tick1s() override
: Once the debounce or the ceiling expires, write every dirty subtree.
inline char * lastSavedStr()
: The live "last saved" buffer, which FileManagerModule binds its own control straight at.
void flush()
: Save every dirty subtree now, which is the same work the debounce eventually does.
bool saveSubtreeTo(MoonModule * m, JsonSink & sink, const char * prefix = "")
: Serialize a subtree into a caller's sink, the prefix letting several share one object.
bool applySubtree(MoonModule * m, const char * json, const char * prefix = "")
: Apply a serialized subtree to a live tree, driving the lifecycle a runtime rebuild needs.
bool applyConfigFile(const char * path)
: Apply a written config file onto the running tree, so a restored backup needs no reboot.
bool requestConfigApply(const char * path)
: Queue a written config file, which the next tick applies on the render task.
virtual void tick20ms() override
: Apply any config file the upload path queued.
Public Static Attributes¶
constexpr const char * CONFIG_DIR = "/.config"
: where every config file lives
constexpr size_t MAX_PATH = 64
: the longest path this module builds
constexpr size_t MAX_KEY = 48
: the longest dotted key it composes
constexpr uint32_t DEBOUNCE_MS = 2000
: how long a save waits for quiet
constexpr uint32_t MAX_DEFER_MS = 10000
: The ceiling on a deferred save, so a continuous writer cannot starve one forever.
Public Static Methods¶
static inline FilesystemModule * instance()
: The live singleton, or null before the boot wiring registers it.
static void flushPending()
: Force the pending saves through from a static context, as the reboot handler does.
static void noteDirty()
: Record that something changed, which starts the debounce.
More info¶
One flat file per module, reconciled at load¶
Children are encoded positionally under an index prefix, with no nested objects. A structured value reads back through its control's own restore hook, and a derived one is never saved. Each child carries its type, and that type drives reconciliation. Where the file names a different type at a position, the loader creates it and swaps it in. A child the file omits is torn down, and one past the end is appended.
Saving is debounced, and bounded¶
Every successful mutation marks its module dirty, tree-shape changes included. A save waits for quiet, then writes each dirty subtree to a temporary file and renames it. A flag clears only once its write succeeds, so a failed write is retried.
Conditional controls, and the first boot¶
A module binds its whole control set and hides what does not apply, so a value is always found. On the first boot no file exists, so each module keeps its defaults until something changes.
