#ifndef FSPersistence_h #define FSPersistence_h #include #include #include #include #define MAX_FILE_SIZE 1024 template class FSPersistence { public: FSPersistence(JsonSerializer jsonSerializer, JsonDeserializer jsonDeserializer, StatefulService* statefulService, FS* fs, char const* filePath) : _jsonSerializer(jsonSerializer), _jsonDeserializer(jsonDeserializer), _statefulService(statefulService), _fs(fs), _filePath(filePath) { enableUpdateHandler(); } void readFromFS() { File settingsFile = _fs->open(_filePath, "r"); if (settingsFile) { if (settingsFile.size() <= MAX_FILE_SIZE) { DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_FILE_SIZE); DeserializationError error = deserializeJson(jsonDocument, settingsFile); if (error == DeserializationError::Ok && jsonDocument.is()) { updateSettings(jsonDocument.as()); settingsFile.close(); return; } } settingsFile.close(); } // If we reach here we have not been successful in loading the config, // hard-coded emergency defaults are now applied. applyDefaults(); } bool writeToFS() { // create and populate a new json object DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_FILE_SIZE); JsonObject jsonObject = jsonDocument.to(); _statefulService->read(jsonObject, _jsonSerializer); // serialize it to filesystem File settingsFile = _fs->open(_filePath, "w"); // failed to open file, return false if (!settingsFile) { return false; } // serialize the data to the file serializeJson(jsonDocument, settingsFile); settingsFile.close(); return true; } void disableUpdateHandler() { if (_updateHandlerId) { _statefulService->removeUpdateHandler(_updateHandlerId); _updateHandlerId = 0; } } void enableUpdateHandler() { if (!_updateHandlerId) { _updateHandlerId = _statefulService->addUpdateHandler([&](String originId) { writeToFS(); }); } } private: JsonSerializer _jsonSerializer; JsonDeserializer _jsonDeserializer; StatefulService* _statefulService; FS* _fs; char const* _filePath; update_handler_id_t _updateHandlerId = 0; // update the settings, but do not call propogate void updateSettings(JsonObject root) { _statefulService->updateWithoutPropagation(root, _jsonDeserializer); } protected: // We assume the deserializer supplies sensible defaults if an empty object // is supplied, this virtual function allows that to be changed. virtual void applyDefaults() { DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_FILE_SIZE); updateSettings(jsonDocument.to()); } }; #endif // end FSPersistence