|
|
|
@@ -1,4 +1,5 @@
|
|
|
|
#include "FileManager.hpp"
|
|
|
|
#include "FileManager.hpp"
|
|
|
|
|
|
|
|
#include "../BuiltInMelodies/BuiltInMelodies.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
FileManager::FileManager(ConfigManager* config) : configManager(config) {
|
|
|
|
FileManager::FileManager(ConfigManager* config) : configManager(config) {
|
|
|
|
// Constructor - store reference to ConfigManager
|
|
|
|
// Constructor - store reference to ConfigManager
|
|
|
|
@@ -23,15 +24,26 @@ bool FileManager::addMelody(JsonVariant doc) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char* url = doc["download_url"];
|
|
|
|
const char* url = doc["download_url"];
|
|
|
|
const char* filename = doc["melodys_uid"];
|
|
|
|
const char* melodyUid = doc["melodys_uid"];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Check if this is a built-in melody - skip download if it exists
|
|
|
|
|
|
|
|
if (BuiltInMelodies::isBuiltInMelody(melodyUid)) {
|
|
|
|
|
|
|
|
const BuiltInMelodies::MelodyInfo* builtinMelody = BuiltInMelodies::findMelodyByUID(melodyUid);
|
|
|
|
|
|
|
|
if (builtinMelody != nullptr) {
|
|
|
|
|
|
|
|
LOG_INFO("Melody '%s' is a built-in melody, skipping download", melodyUid);
|
|
|
|
|
|
|
|
return true; // Success - no download needed
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// If starts with builtin_ but not found, log warning and try download anyway
|
|
|
|
|
|
|
|
LOG_WARNING("Melody '%s' has builtin_ prefix but not found in library, attempting download", melodyUid);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Download the melody file to /melodies directory
|
|
|
|
// Download the melody file to /melodies directory
|
|
|
|
if (downloadFile(url, "/melodies", filename)) {
|
|
|
|
if (downloadFile(url, "/melodies", melodyUid)) {
|
|
|
|
LOG_INFO("Melody download successful: %s", filename);
|
|
|
|
LOG_INFO("Melody download successful: %s", melodyUid);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LOG_ERROR("Melody download failed: %s", filename);
|
|
|
|
LOG_ERROR("Melody download failed: %s", melodyUid);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -62,11 +74,13 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
bool isHttps = url.startsWith("https://");
|
|
|
|
bool isHttps = url.startsWith("https://");
|
|
|
|
|
|
|
|
|
|
|
|
HTTPClient http;
|
|
|
|
HTTPClient http;
|
|
|
|
|
|
|
|
WiFiClientSecure* secureClient = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
// Configure HTTP client based on protocol
|
|
|
|
// Configure HTTP client based on protocol
|
|
|
|
if (isHttps) {
|
|
|
|
if (isHttps) {
|
|
|
|
WiFiClientSecure* secureClient = new WiFiClientSecure();
|
|
|
|
secureClient = new WiFiClientSecure();
|
|
|
|
secureClient->setInsecure(); // Skip certificate validation for Firebase
|
|
|
|
secureClient->setInsecure(); // Skip certificate validation for Firebase
|
|
|
|
|
|
|
|
secureClient->setTimeout(15); // 15 second timeout for TLS operations
|
|
|
|
http.begin(*secureClient, url);
|
|
|
|
http.begin(*secureClient, url);
|
|
|
|
LOG_DEBUG("Using HTTPS with secure client");
|
|
|
|
LOG_DEBUG("Using HTTPS with secure client");
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
@@ -77,17 +91,28 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
http.setTimeout(30000); // 30 second timeout for large files
|
|
|
|
http.setTimeout(30000); // 30 second timeout for large files
|
|
|
|
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); // Follow redirects automatically
|
|
|
|
http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); // Follow redirects automatically
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Disable task watchdog for current task during blocking HTTPS operation
|
|
|
|
|
|
|
|
// The TLS handshake can take several seconds and would trigger watchdog
|
|
|
|
|
|
|
|
LOG_DEBUG("Disabling watchdog for download...");
|
|
|
|
|
|
|
|
esp_task_wdt_delete(NULL);
|
|
|
|
|
|
|
|
|
|
|
|
LOG_DEBUG("Sending HTTP GET request...");
|
|
|
|
LOG_DEBUG("Sending HTTP GET request...");
|
|
|
|
int httpCode = http.GET();
|
|
|
|
int httpCode = http.GET();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Re-enable task watchdog after HTTP request completes
|
|
|
|
|
|
|
|
esp_task_wdt_add(NULL);
|
|
|
|
|
|
|
|
LOG_DEBUG("Watchdog re-enabled after HTTP request");
|
|
|
|
|
|
|
|
|
|
|
|
if (httpCode != HTTP_CODE_OK && httpCode != HTTP_CODE_MOVED_PERMANENTLY && httpCode != HTTP_CODE_FOUND) {
|
|
|
|
if (httpCode != HTTP_CODE_OK && httpCode != HTTP_CODE_MOVED_PERMANENTLY && httpCode != HTTP_CODE_FOUND) {
|
|
|
|
LOG_ERROR("HTTP GET failed, code: %d, error: %s", httpCode, http.errorToString(httpCode).c_str());
|
|
|
|
LOG_ERROR("HTTP GET failed, code: %d, error: %s", httpCode, http.errorToString(httpCode).c_str());
|
|
|
|
http.end();
|
|
|
|
http.end();
|
|
|
|
|
|
|
|
if (secureClient) delete secureClient;
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!initializeSD()) {
|
|
|
|
if (!initializeSD()) {
|
|
|
|
http.end();
|
|
|
|
http.end();
|
|
|
|
|
|
|
|
if (secureClient) delete secureClient;
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -95,6 +120,7 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
if (!ensureDirectoryExists(directory)) {
|
|
|
|
if (!ensureDirectoryExists(directory)) {
|
|
|
|
LOG_ERROR("Failed to create directory: %s", directory.c_str());
|
|
|
|
LOG_ERROR("Failed to create directory: %s", directory.c_str());
|
|
|
|
http.end();
|
|
|
|
http.end();
|
|
|
|
|
|
|
|
if (secureClient) delete secureClient;
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -107,6 +133,7 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
if (!file) {
|
|
|
|
if (!file) {
|
|
|
|
LOG_ERROR("Failed to open file for writing: %s", fullPath.c_str());
|
|
|
|
LOG_ERROR("Failed to open file for writing: %s", fullPath.c_str());
|
|
|
|
http.end();
|
|
|
|
http.end();
|
|
|
|
|
|
|
|
if (secureClient) delete secureClient;
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -134,7 +161,7 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
file.write(buffer, bytesRead);
|
|
|
|
file.write(buffer, bytesRead);
|
|
|
|
totalBytes += bytesRead;
|
|
|
|
totalBytes += bytesRead;
|
|
|
|
|
|
|
|
|
|
|
|
// Log progress every 5KB
|
|
|
|
// Log progress every 5 seconds
|
|
|
|
if (millis() - lastLog > 5000) {
|
|
|
|
if (millis() - lastLog > 5000) {
|
|
|
|
LOG_DEBUG("Download progress: %u bytes", totalBytes);
|
|
|
|
LOG_DEBUG("Download progress: %u bytes", totalBytes);
|
|
|
|
lastLog = millis();
|
|
|
|
lastLog = millis();
|
|
|
|
@@ -142,10 +169,10 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Aggressive task yielding every 100ms to prevent watchdog timeout
|
|
|
|
// Aggressive task yielding every 50ms to prevent watchdog timeout
|
|
|
|
if (millis() - lastYield > 100) {
|
|
|
|
if (millis() - lastYield > 50) {
|
|
|
|
yield();
|
|
|
|
yield();
|
|
|
|
vTaskDelay(1 / portTICK_PERIOD_MS); // Let other tasks run
|
|
|
|
vTaskDelay(5 / portTICK_PERIOD_MS); // Let other tasks run (5ms)
|
|
|
|
lastYield = millis();
|
|
|
|
lastYield = millis();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -154,14 +181,16 @@ bool FileManager::downloadFile(const String& url, const String& directory, const
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Small delay if no data available yet
|
|
|
|
// Yield and small delay if no data available yet
|
|
|
|
if (!availableSize) {
|
|
|
|
if (!availableSize) {
|
|
|
|
delay(10);
|
|
|
|
yield();
|
|
|
|
|
|
|
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
file.close();
|
|
|
|
http.end();
|
|
|
|
http.end();
|
|
|
|
|
|
|
|
if (secureClient) delete secureClient;
|
|
|
|
LOG_INFO("Download complete, file saved to: %s (%u bytes)", fullPath.c_str(), totalBytes);
|
|
|
|
LOG_INFO("Download complete, file saved to: %s (%u bytes)", fullPath.c_str(), totalBytes);
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|