boothifier/webSock/AppUpgrade.h

156 lines
4.7 KiB
C++

#pragma once
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <Update.h>
#include <FS.h>
#include <memory>
#include <ESPAsyncWebServer.h>
#include "AppVersion.h"
#define DEFAULT_MANIFEST_URL "https://storage.googleapis.com/boothifier/latest/"
#define BUFFER_SIZE 4096
extern TaskHandle_t Update_Task_Handle;
/**
* @brief File information structure
*/
struct FileInfo {
String remotePath; ///< Path on remote server
String localPath; ///< Path in local filesystem
String md5; ///< MD5 hash for verification
//size_t size; ///< File size in bytes
};
/**
* @class AppUpdater
* @brief Handles firmware and filesystem updates
*/
class AppUpdater {
public:
Version localVersion;
const char* bucketUrl;
const char* appName;
const char* manifestName;
JsonDocument jsonManifest;
JsonArray jsonFilesArray;
/**
* @brief Update status enumeration
*/
enum class UpdateStatus {
IDLE, ///< No update in progress
MESSAGE, ///< Update message
DOWNLOADING, ///< Downloading files
VERIFYING, ///< Verifying file integrity
SKIPPING, ///< File already up to date
SAVING, ///< Saving to filesystem
COMPLETE, ///< Update complete
ERROR ///< Error occurred
};
/**
* @brief Constructor
* @param version Current firmware version
* @param bucket Base URL for updates
* @param fs Filesystem reference
*/
AppUpdater(fs::FS& fs, const char* currVersion, const char* bucket, const char* manifestName ="update.json", const char* appBin = "firmware.bin" );
/**
* @brief Set progress callback function
* @param callback Function to call with progress updates
*/
void setProgressCallback(void (*callback)( UpdateStatus status, int percentage, const char* message));
/**
* @brief Check for and apply updates
* @return true if update successful
*/
bool IsUpdateAvailable(void);
/**
* @brief Update files from manifest
* @param manifestPath Path to manifest file
* @return true if all files updated successfully
*/
//bool updateFilesFromManifest(const char* manifestPath = DEFAULT_MANIFEST_URL);
bool updateFilesArray(void);
/**
* @brief Update single file
* @param remotePath Remote file path
* @param localPath Local file path
* @param expectedMd5 Expected MD5 hash
* @return true if file updated successfully
*/
bool updateFile(const char* remotePath, const char* localPath, const char* expectedMd5);
/**
* @brief Get manifest content
* @param manifestPath Path to manifest file
* @return Manifest content as a json document
*/
bool checkManifest(void);
bool updateApp(void);
String getVersion(void);
private:
typedef void (*ProgressCallback)(UpdateStatus status, int percentage, const char* message);
ProgressCallback progressCb;
fs::FS& fileSystem;
UpdateStatus status;
std::unique_ptr<uint8_t[]> downloadBuffer;
bool updateAvailable = false;
/**
* @brief Verify and save file
* @param stream Input stream
* @param contentLength Expected content length
* @param localPath Local file path
* @param expectedMd5 Expected MD5 hash
* @return true if successful
*/
bool verifyAndSaveFile(WiFiClient* stream, size_t contentLength,
const char* localPath, const char* expectedMd5);
/**
* @brief Update progress callback
* @param percentage Progress percentage
* @param newStatus Current status
*/
void updateProgress(UpdateStatus newStatus, int percentage, const char* message = nullptr);
String getLocalMD5(const char* filePath);
};
// Queue handle for firmware update messages
extern QueueHandle_t updateMsgQueue;
// Message structure for update progress
struct UpdateMessage {
String message;
bool complete;
int progress;
};
/**
* @brief Firmware update task
* @param param Task parameters
*/
void firmwareUpdateTask(void* param);
void startFirmwareUpdateTask(AsyncWebSocket* eventSrc);
void updateProgress(AppUpdater::UpdateStatus status, int percentage, const char* message);
void sendUpdateMessage(const char* message, bool complete, int progress);
void handleUpdateProgress(AsyncWebServerRequest *request);