Remove refrence to SPIFFS global from persistence code, factor out persistence code so it can be re-used.
This commit is contained in:
		
							
								
								
									
										98
									
								
								src/SettingsPersistence.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/SettingsPersistence.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
				
			|||||||
 | 
					#ifndef SettingsPersistence_h
 | 
				
			||||||
 | 
					#define SettingsPersistence_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ESPAsyncWebServer.h>
 | 
				
			||||||
 | 
					#include <FS.h>
 | 
				
			||||||
 | 
					#include <AsyncJson.h>
 | 
				
			||||||
 | 
					#include <ArduinoJson.h>
 | 
				
			||||||
 | 
					#include <AsyncJsonRequestWebHandler.h>
 | 
				
			||||||
 | 
					#include <AsyncJsonCallbackResponse.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					* At the moment, not expecting settings service to have to deal with large JSON
 | 
				
			||||||
 | 
					* files this could be made configurable fairly simply, it's exposed on
 | 
				
			||||||
 | 
					* AsyncJsonRequestWebHandler with a setter.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#define MAX_SETTINGS_SIZE 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					* Mixin for classes which need to save settings to/from a file on the the file system as JSON.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					class SettingsPersistence {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // will store and retrieve config from the file system
 | 
				
			||||||
 | 
					  FS* _fs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // the file path our settings will be saved to
 | 
				
			||||||
 | 
					  char const* _filePath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool writeToFS() {
 | 
				
			||||||
 | 
					    // create and populate a new json object
 | 
				
			||||||
 | 
					    DynamicJsonBuffer jsonBuffer;
 | 
				
			||||||
 | 
					    JsonObject& root = jsonBuffer.createObject();
 | 
				
			||||||
 | 
					    writeToJsonObject(root);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // serialize it to filesystem
 | 
				
			||||||
 | 
					    File configFile = _fs->open(_filePath, "w");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // failed to open file, return false
 | 
				
			||||||
 | 
					    if (!configFile) {
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    root.printTo(configFile);
 | 
				
			||||||
 | 
					    configFile.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void readFromFS(){
 | 
				
			||||||
 | 
					    File configFile = _fs->open(_filePath, "r");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // use defaults if no config found
 | 
				
			||||||
 | 
					    if (configFile) {
 | 
				
			||||||
 | 
					      // Protect against bad data uploaded to file system
 | 
				
			||||||
 | 
					      // We never expect the config file to get very large, so cap it.
 | 
				
			||||||
 | 
					      size_t size = configFile.size();
 | 
				
			||||||
 | 
					      if (size <= MAX_SETTINGS_SIZE) {
 | 
				
			||||||
 | 
					        DynamicJsonBuffer jsonBuffer;
 | 
				
			||||||
 | 
					        JsonObject& root = jsonBuffer.parseObject(configFile);
 | 
				
			||||||
 | 
					        if (root.success()) {
 | 
				
			||||||
 | 
					          readFromJsonObject(root);
 | 
				
			||||||
 | 
					          configFile.close();
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      configFile.close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If we reach here we have not been successful in loading the config,
 | 
				
			||||||
 | 
					    // hard-coded emergency defaults are now applied.
 | 
				
			||||||
 | 
					    applyDefaultConfig();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // serialization routene, from local config to JsonObject
 | 
				
			||||||
 | 
					    virtual void readFromJsonObject(JsonObject& root){}
 | 
				
			||||||
 | 
					    virtual void writeToJsonObject(JsonObject& root){}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We assume the readFromJsonObject supplies sensible defaults if an empty object
 | 
				
			||||||
 | 
					    // is supplied, this virtual function allows that to be changed.
 | 
				
			||||||
 | 
					    virtual void applyDefaultConfig(){
 | 
				
			||||||
 | 
					      DynamicJsonBuffer jsonBuffer;
 | 
				
			||||||
 | 
					      JsonObject& root = jsonBuffer.createObject();
 | 
				
			||||||
 | 
					      readFromJsonObject(root);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SettingsPersistence(FS* fs, char const* servicePath, char const* filePath):
 | 
				
			||||||
 | 
					      _fs(fs), _filePath(filePath) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    virtual ~SettingsPersistence() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif // end SettingsPersistence
 | 
				
			||||||
@@ -7,79 +7,24 @@
 | 
				
			|||||||
#elif defined(ESP_PLATFORM)
 | 
					#elif defined(ESP_PLATFORM)
 | 
				
			||||||
  #include <WiFi.h>
 | 
					  #include <WiFi.h>
 | 
				
			||||||
  #include <AsyncTCP.h>
 | 
					  #include <AsyncTCP.h>
 | 
				
			||||||
  #include <SPIFFS.h>
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <SettingsPersistence.h>
 | 
				
			||||||
#include <ESPAsyncWebServer.h>
 | 
					#include <ESPAsyncWebServer.h>
 | 
				
			||||||
#include <FS.h>
 | 
					 | 
				
			||||||
#include <AsyncJson.h>
 | 
					#include <AsyncJson.h>
 | 
				
			||||||
#include <ArduinoJson.h>
 | 
					#include <ArduinoJson.h>
 | 
				
			||||||
#include <AsyncJsonRequestWebHandler.h>
 | 
					#include <AsyncJsonRequestWebHandler.h>
 | 
				
			||||||
#include <AsyncJsonCallbackResponse.h>
 | 
					#include <AsyncJsonCallbackResponse.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
* At the moment, not expecting settings service to have to deal with large JSON
 | 
					 | 
				
			||||||
* files this could be made configurable fairly simply, it's exposed on
 | 
					 | 
				
			||||||
* AsyncJsonRequestWebHandler with a setter.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
#define MAX_SETTINGS_SIZE 1024
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
* Abstraction of a service which stores it's settings as JSON in SPIFFS.
 | 
					* Abstraction of a service which stores it's settings as JSON in a file system.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
class SettingsService {
 | 
					class SettingsService : public SettingsPersistence {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  char const* _filePath;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  AsyncJsonRequestWebHandler _updateHandler;
 | 
					  AsyncJsonRequestWebHandler _updateHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool writeToSPIFFS() {
 | 
					 | 
				
			||||||
    // create and populate a new json object
 | 
					 | 
				
			||||||
    DynamicJsonBuffer jsonBuffer;
 | 
					 | 
				
			||||||
    JsonObject& root = jsonBuffer.createObject();
 | 
					 | 
				
			||||||
    writeToJsonObject(root);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // serialize it to SPIFFS
 | 
					 | 
				
			||||||
    File configFile = SPIFFS.open(_filePath, "w");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // failed to open file, return false
 | 
					 | 
				
			||||||
    if (!configFile) {
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    root.printTo(configFile);
 | 
					 | 
				
			||||||
    configFile.close();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void readFromSPIFFS(){
 | 
					 | 
				
			||||||
    File configFile = SPIFFS.open(_filePath, "r");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // use defaults if no config found
 | 
					 | 
				
			||||||
    if (configFile) {
 | 
					 | 
				
			||||||
      // Protect against bad data uploaded to SPIFFS
 | 
					 | 
				
			||||||
      // We never expect the config file to get very large, so cap it.
 | 
					 | 
				
			||||||
      size_t size = configFile.size();
 | 
					 | 
				
			||||||
      if (size <= MAX_SETTINGS_SIZE) {
 | 
					 | 
				
			||||||
        DynamicJsonBuffer jsonBuffer;
 | 
					 | 
				
			||||||
        JsonObject& root = jsonBuffer.parseObject(configFile);
 | 
					 | 
				
			||||||
        if (root.success()) {
 | 
					 | 
				
			||||||
          readFromJsonObject(root);
 | 
					 | 
				
			||||||
          configFile.close();
 | 
					 | 
				
			||||||
          return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      configFile.close();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // If we reach here we have not been successful in loading the config,
 | 
					 | 
				
			||||||
    // hard-coded emergency defaults are now applied.
 | 
					 | 
				
			||||||
    applyDefaultConfig();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void fetchConfig(AsyncWebServerRequest *request){
 | 
					  void fetchConfig(AsyncWebServerRequest *request){
 | 
				
			||||||
    AsyncJsonResponse * response = new AsyncJsonResponse();
 | 
					    AsyncJsonResponse * response = new AsyncJsonResponse();
 | 
				
			||||||
    writeToJsonObject(response->getRoot());
 | 
					    writeToJsonObject(response->getRoot());
 | 
				
			||||||
@@ -91,7 +36,7 @@ private:
 | 
				
			|||||||
    if (json.is<JsonObject>()){
 | 
					    if (json.is<JsonObject>()){
 | 
				
			||||||
      JsonObject& newConfig = json.as<JsonObject>();
 | 
					      JsonObject& newConfig = json.as<JsonObject>();
 | 
				
			||||||
      readFromJsonObject(newConfig);
 | 
					      readFromJsonObject(newConfig);
 | 
				
			||||||
      writeToSPIFFS();
 | 
					      writeToFS();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // write settings back with a callback to reconfigure the wifi
 | 
					      // write settings back with a callback to reconfigure the wifi
 | 
				
			||||||
      AsyncJsonCallbackResponse * response = new AsyncJsonCallbackResponse([this] () {onConfigUpdated();});
 | 
					      AsyncJsonCallbackResponse * response = new AsyncJsonCallbackResponse([this] () {onConfigUpdated();});
 | 
				
			||||||
@@ -108,28 +53,13 @@ private:
 | 
				
			|||||||
    // will serve setting endpoints from here
 | 
					    // will serve setting endpoints from here
 | 
				
			||||||
    AsyncWebServer* _server;
 | 
					    AsyncWebServer* _server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // will store and retrieve config from the file system
 | 
					 | 
				
			||||||
    FS* _fs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // reads the local config from the
 | 
					 | 
				
			||||||
    virtual void readFromJsonObject(JsonObject& root){}
 | 
					 | 
				
			||||||
    virtual void writeToJsonObject(JsonObject& root){}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // implement to perform action when config has been updated
 | 
					    // implement to perform action when config has been updated
 | 
				
			||||||
    virtual void onConfigUpdated(){}
 | 
					    virtual void onConfigUpdated(){}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // We assume the readFromJsonObject supplies sensible defaults if an empty object
 | 
					 | 
				
			||||||
    // is supplied, this virtual function allows that to be changed.
 | 
					 | 
				
			||||||
    virtual void applyDefaultConfig(){
 | 
					 | 
				
			||||||
      DynamicJsonBuffer jsonBuffer;
 | 
					 | 
				
			||||||
      JsonObject& root = jsonBuffer.createObject();
 | 
					 | 
				
			||||||
      readFromJsonObject(root);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    SettingsService(AsyncWebServer* server, FS* fs, char const* servicePath, char const* filePath):
 | 
					    SettingsService(AsyncWebServer* server, FS* fs, char const* servicePath, char const* filePath):
 | 
				
			||||||
    _filePath(filePath), _server(server), _fs(fs){
 | 
					      SettingsPersistence(fs, servicePath, filePath), _server(server) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // configure fetch config handler
 | 
					      // configure fetch config handler
 | 
				
			||||||
      _server->on(servicePath, HTTP_GET, std::bind(&SettingsService::fetchConfig, this, std::placeholders::_1));
 | 
					      _server->on(servicePath, HTTP_GET, std::bind(&SettingsService::fetchConfig, this, std::placeholders::_1));
 | 
				
			||||||
@@ -145,7 +75,7 @@ private:
 | 
				
			|||||||
    virtual ~SettingsService() {}
 | 
					    virtual ~SettingsService() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual void begin() {
 | 
					    virtual void begin() {
 | 
				
			||||||
      readFromSPIFFS();
 | 
					      readFromFS();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user