Complete Rebuild, with Subsystems for each component. RTOS Tasks. (help by Claude)
This commit is contained in:
241
vesper/src/FileManager/FileManager.cpp
Normal file
241
vesper/src/FileManager/FileManager.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
#include "FileManager.hpp"
|
||||
|
||||
FileManager::FileManager(ConfigManager* config) : configManager(config) {
|
||||
// Constructor - store reference to ConfigManager
|
||||
}
|
||||
|
||||
bool FileManager::initializeSD() {
|
||||
uint8_t sdPin = configManager->getHardwareConfig().sdChipSelect;
|
||||
if (!SD.begin(sdPin)) {
|
||||
LOG_ERROR("SD Card initialization failed!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileManager::addMelody(JsonVariant doc) {
|
||||
LOG_INFO("Adding melody from JSON data...");
|
||||
|
||||
// Extract URL and filename from JSON
|
||||
if (!doc.containsKey("download_url") || !doc.containsKey("melodys_uid")) {
|
||||
LOG_ERROR("Missing required parameters: download_url or melodys_uid");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* url = doc["download_url"];
|
||||
const char* filename = doc["melodys_uid"];
|
||||
|
||||
// Download the melody file to /melodies directory
|
||||
if (downloadFile(url, "/melodies", filename)) {
|
||||
LOG_INFO("Melody download successful: %s", filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG_ERROR("Melody download failed: %s", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileManager::ensureDirectoryExists(const String& dirPath) {
|
||||
if (!initializeSD()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the directory ends with '/'
|
||||
String normalizedPath = dirPath;
|
||||
if (!normalizedPath.endsWith("/")) {
|
||||
normalizedPath += "/";
|
||||
}
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
return SD.mkdir(normalizedPath.c_str());
|
||||
}
|
||||
|
||||
bool FileManager::downloadFile(const String& url, const String& directory, const String& filename) {
|
||||
LOG_INFO("Starting download from: %s", url.c_str());
|
||||
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode != HTTP_CODE_OK) {
|
||||
LOG_ERROR("HTTP GET failed, error: %s", http.errorToString(httpCode).c_str());
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initializeSD()) {
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure directory exists
|
||||
if (!ensureDirectoryExists(directory)) {
|
||||
LOG_ERROR("Failed to create directory: %s", directory.c_str());
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build full file path
|
||||
String dirPath = directory;
|
||||
if (!dirPath.endsWith("/")) dirPath += "/";
|
||||
String fullPath = dirPath + filename;
|
||||
|
||||
File file = SD.open(fullPath.c_str(), FILE_WRITE);
|
||||
if (!file) {
|
||||
LOG_ERROR("Failed to open file for writing: %s", fullPath.c_str());
|
||||
http.end();
|
||||
return false;
|
||||
}
|
||||
|
||||
WiFiClient* stream = http.getStreamPtr();
|
||||
uint8_t buffer[1024];
|
||||
int bytesRead;
|
||||
|
||||
while (http.connected() && (bytesRead = stream->readBytes(buffer, sizeof(buffer))) > 0) {
|
||||
file.write(buffer, bytesRead);
|
||||
}
|
||||
|
||||
file.close();
|
||||
http.end();
|
||||
LOG_INFO("Download complete, file saved to: %s", fullPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
String FileManager::listFilesAsJson(const char* dirPath) {
|
||||
if (!initializeSD()) {
|
||||
LOG_ERROR("SD initialization failed");
|
||||
return "{}";
|
||||
}
|
||||
|
||||
File dir = SD.open(dirPath);
|
||||
if (!dir || !dir.isDirectory()) {
|
||||
LOG_ERROR("Directory not found: %s", dirPath);
|
||||
return "{}";
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(1024);
|
||||
JsonArray fileList = doc.createNestedArray("files");
|
||||
|
||||
File file = dir.openNextFile();
|
||||
while (file) {
|
||||
if (!file.isDirectory()) {
|
||||
fileList.add(file.name());
|
||||
}
|
||||
file = dir.openNextFile();
|
||||
}
|
||||
|
||||
String json;
|
||||
serializeJson(doc, json);
|
||||
return json;
|
||||
}
|
||||
|
||||
bool FileManager::fileExists(const String& filePath) {
|
||||
if (!initializeSD()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = SD.open(filePath.c_str());
|
||||
if (file) {
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileManager::deleteFile(const String& filePath) {
|
||||
if (!initializeSD()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SD.remove(filePath.c_str())) {
|
||||
LOG_INFO("File deleted: %s", filePath.c_str());
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERROR("Failed to delete file: %s", filePath.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileManager::createDirectory(const String& dirPath) {
|
||||
return ensureDirectoryExists(dirPath);
|
||||
}
|
||||
|
||||
size_t FileManager::getFileSize(const String& filePath) {
|
||||
if (!initializeSD()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
File file = SD.open(filePath.c_str());
|
||||
if (!file) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t size = file.size();
|
||||
file.close();
|
||||
return size;
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// HEALTH CHECK IMPLEMENTATION
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
bool FileManager::isHealthy() const {
|
||||
// Check if ConfigManager is available
|
||||
if (!configManager) {
|
||||
LOG_DEBUG("FileManager: Unhealthy - ConfigManager not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if SD card can be initialized
|
||||
uint8_t sdPin = configManager->getHardwareConfig().sdChipSelect;
|
||||
if (!SD.begin(sdPin)) {
|
||||
LOG_DEBUG("FileManager: Unhealthy - SD Card initialization failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we can read from SD card (test with root directory)
|
||||
File root = SD.open("/");
|
||||
if (!root) {
|
||||
LOG_DEBUG("FileManager: Unhealthy - Cannot access SD root directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!root.isDirectory()) {
|
||||
LOG_DEBUG("FileManager: Unhealthy - SD root is not a directory");
|
||||
root.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
root.close();
|
||||
|
||||
// Check if we can write to SD card (create/delete a test file)
|
||||
String testFile = "/health_test.tmp";
|
||||
File file = SD.open(testFile.c_str(), FILE_WRITE);
|
||||
if (!file) {
|
||||
LOG_DEBUG("FileManager: Unhealthy - Cannot write to SD card");
|
||||
return false;
|
||||
}
|
||||
|
||||
file.print("health_check");
|
||||
file.close();
|
||||
|
||||
// Verify we can read the test file
|
||||
file = SD.open(testFile.c_str(), FILE_READ);
|
||||
if (!file) {
|
||||
LOG_DEBUG("FileManager: Unhealthy - Cannot read test file from SD card");
|
||||
return false;
|
||||
}
|
||||
|
||||
String content = file.readString();
|
||||
file.close();
|
||||
|
||||
// Clean up test file
|
||||
SD.remove(testFile.c_str());
|
||||
|
||||
if (content != "health_check") {
|
||||
LOG_DEBUG("FileManager: Unhealthy - SD card read/write test failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user